Tabellen Definition und TCA

Tutorial Extensionentwicklung mit TYPO3 Teil 2

In diesem Abschnitte schaffen wir die Voraussetzungen für die erste Installation unserer Extension.

Datenbanktabellen mit der ext_tables.sql anlegen.

Mit Hilfe der ext_tables.sql können wir die benötigten Tabellen und Felder definieren. Bei der späteren Installation der Extension über den Extensionmanager werden dann alle Tabellen und Felder in der Datenbank automatisch angelegt.

Damit TYPO3 später mit den Datensätzen arbeiten kann, sind in jeder Tabelle mindestens folgende Felder erforderlich:

CREATE TABLE tx_tutproduktdatenbank_domain_model_product (
    uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
    pid int(11) DEFAULT '0' NOT NULL,

    tstamp int(11) unsigned DEFAULT '0' NOT NULL,
    crdate int(11) unsigned DEFAULT '0' NOT NULL,
    deleted tinyint(4) unsigned DEFAULT '0' NOT NULL,
    hidden tinyint(4) unsigned DEFAULT '0' NOT NULL,

    PRIMARY KEY (uid),
    KEY parent (pid)
);

Mit der "create" Anweisung prüft TYPO3 automatisch, ob die entsprechende Tabelle schon vorhanden ist und wenn ja, ob alle Felder angelegt wurden. Bei einer Feldergänzung bleibt also die Tabelle mit den Daten in der Datenbank erhalten und es wir nur das entsprechende Feld erzeugt.

In den letzten beiden Zeilen wird der Tabellenindex definiert.

Wir definieren also unsere 4 Tabellen und fügen jeweils die Standard Felder hinzu:

Hersteller:

CREATE TABLE tx_tutproduktdatenbank_domain_model_manufactures (
    ...Standard Felder wie oben...

    man_name varchar(255) DEFAULT '' NOT NULL,
    man_web varchar(255) DEFAULT '' NOT NULL,

   ... index wie oben
);

Kategorien:

CREATE TABLE tx_tutproduktdatenbank_domain_model_categories (
    ... Standard Feler wie oben ...

    kat_name varchar(255) DEFAULT '' NOT NULL,

    ... index wie oben
);

Produkte:

CREATE TABLE tx_tutproduktdatenbank_domain_model_products (
    ... Standard-Felder wie oben ...

    prod_name varchar(255) DEFAULT '' NOT NULL,
    prod_sort int(11) unsigned DEFAULT '0' NOT NULL,
    prod_description text,
    prod_images int(11) unsigned DEFAULT '0' NOT NULL,
    prod_category int(11) unsigned DEFAULT '0' NOT NULL,
    prod_manufacture int(11) unsigned DEFAULT '0' NOT NULL,
    prod_maintextcontent int(11) unsigned DEFAULT '0' NOT NULL,
    prod_descriptioncontent int(11) unsigned DEFAULT '0' NOT NULL,
    prod_benefitcontent int(11) unsigned DEFAULT '0' NOT NULL,
    prod_techdetailcontent int(11) unsigned DEFAULT '0' NOT NULL,
    prod_downloads int(11) unsigned DEFAULT '0' NOT NULL,

   ...index wie oben
);

Produkt Content:

CREATE TABLE tx_tutproduktdatenbank_domain_model_productcontent (
    ... Standard-Felder wie oben ...
   
    prodid int(11) unsigned DEFAULT '0' NOT NULL,
    descrptionid int(11) unsigned DEFAULT '0' NOT NULL,
    benefitsid int(11) unsigned DEFAULT '0' NOT NULL,
    technicalid int(11) unsigned DEFAULT '0' NOT NULL,

    prodcont_headline varchar(255) DEFAULT '' NOT NULL,
    prodcont_text text,
    prodcont_images int(11) unsigned DEFAULT '0' NOT NULL,
    prodcont_imageposition int(11) unsigned DEFAULT '0' NOT NULL,

    ... Index wie oben
);

Eure Dateien könnt Ihr auch mit meinen Dateien auf GIT-Hub vergleichen.


Die TCA Dateien

In unserem Ordner Configuration/TCA legen wir jetzt für jede Datenbanktabelle eine php Datei an, z.B. tx_tutproduktdatenbank_domain_model_products.php.

WICHTIG: der Dateiname muss identisch mit dem Tabellennamen sein.

Exkurs: Der Extensionmanager generiert an dieser Stelle anders: innerhalb des TCA Verzeichnisses wird nur eine Datei mit dem Tabellennamen generiert (z.B. Products) und diese Datei über einen Eintrag in der ext_tables.php geladen. Damit funktioniert aber nicht das Caching der TCA unter 6.2. Der bessere Weg ist wie hier beschrieben, innerhalb des TCA Ordners Dateien mit dem kompletten Tabellennamen anzulegen. Diese können automatisch geladen werden und es bedaf keinen weiteren Eintrag in der ext_tables.php.

Den Aufbau einer TCA habe ich schonmal in der Rubrik Extensionentwicklung ausführlich beschrieben.  Hier nochmal das Grundgerüst das wir in alle 4 TCA Dateien kopieren.

 TCA Sections:

<?php
return array(
   
'ctrl' => array(
         ... genrelle Anzeigeoptionen im Backend (Icon, Titel etc ...)
         ... generelles Verhalten der Tabelle
         ... Pflichtangabe für jede Tabelle
     ),
     'interface' => array(
         ... Angaben wir die Tabelle im Backend angezeigt werden soll
     ),
     'types' => array(
         ... Anordnung der Felder innerhalb der Backendformulare (Datensatz bearbeiten)
     ),
     'palettes' => array(
         ... Hier können mehrere Felder für eine horizontale Anordnung im Formular zusammengafasst werden
     ),
     'columns' => array(
         ... Für jedes Datanbankfeld werden hier die Eigenschaften festgelegt:
         ... Feldtyp, Relationen, Validierung
     ),
);
?>

ctrl Section

In die crtl Section der TCAs können wir nachfolgendes Snippet eintragen. Dabei tauschen wir nur den den Wert für den Titel und setzen das richtige Feld für 'label'. Da die Daten der Tabelle productcontent als Inlineelement angezeigt werden, ändern wir in der TCA noch die Zeile  'dividers2tabs' => FALSE. Damit wird bewirkt, das keine Tabs angezeigt werden (was ich persönlich in Inlineformularen für unübersichtlich halte).

'ctrl' => array(
    'title' => 'Produkt',
    'label' => 'prod_name',
    'tstamp' => 'tstamp',
    'crdate' => 'crdate',
    'dividers2tabs' => TRUE,
    'delete' => 'deleted',
    'enablecolumns' => array(
        'disabled' => 'hidden',
    ),
  'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('tut_produktdatenbank') . 'ext_icon.gif'
),

Interface Section

Brauchen wir im Augenblick nicht zu berücksichtigen, und tragen daher ein leeres Array ein:

'interface' => array(
    'showRecordFieldList' => '   '
),

Types Section
Die Type Section ist in Kombination mit der Palettes Section für die Anordnung unsere Felder im Eingabeformular verantwortlich.
Die Zeile

,--div--;Meine Tab Beschreibung

erzeugt ein Tab im Formular, mit der Zeile

--palette--;Meine Beschriftung;paletten-name

füge ich eine selbst definierte Palette ein. Mit Paletten können Felder z.B. horizontal nebeneinander dargestellt werden.

In der Type Section muss also jedes Feld aufgeführt werden das im Formular angezeigt werden soll. Beschriftungen, Feldgrößen und Arten werden nachher im columns Array definiert, hier wird nur der Feldname angegeben.

Type und Palettes Array für die product TCA:

'types' => array(
    '1' => array('showitem' => ' ,--div--;Übersicht
                                 ,--palette--;Artikel;title
                                 , prod_images
                                 , prod_description

                                 ,--div--;TAB Main
                                 , prod_maintextcontent

                                 ,--div--;TAB Description
                                 , prod_descriptioncontent

                                 ,--div--;TAB Key Benefits
                                 , prod_benefitcontent

                                 ,--div--;TAB Technical Detail
                                 , prod_techdetailcontent

                                 ,--div--;TAB Downloads
                                 , prod_downloads

                                 ,--div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access
                                 , hidden;;1'
         )
),
'palettes' => array( 'title' => array('showitem' => 'prod_name, --linebreak--, prod_category, prod_manufacture', 'canNotCollapse' => 1)
),

Die type und palettes Sections der anderen TCAs sind recht simpel:

Type und Palettes Section für die Productcontent TCA:

'types' => array(
'1' => array('showitem' => ' , prodcont_headline
                             , prodcont_text
                             , prodcont_imageposition
                             , prodcont_images
)
),
'palettes' => array(       

),

Type und Palettes Section für die Hersteller TCA:

 'types' => array(
'1' => array('showitem' => ' ,--div--;Hersteller
                              , man_name
                              , man_web

                              ,--div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access
                              , hidden;;1'
    )
),
'palettes' => array(

),

Type und Palettes Section für die Kategorie TCA:

 'types' => array(
'1' => array('showitem' => ' ,--div--;Kategorie
                              , kat_name
                             , man_web

                             ,--div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access
                             , hidden;;1'
    )
),
'palettes' => array(

),

Zwischenstand: Ihr solltet jetzt 4 Dateien in eurem Extension Ordner unter Configuration/TCA haben. In jeder TCA Datei ist die crtl, interface, types und palettes Section mehr oder weniger gefüllt. Okay, dann frischen Kaffee holen, noch 10 Minuten durchhalten und wir können endlich unsere Extension das erste mal installieren.

Die Columns Section in den TCAs:

Wie bereits erwähnt, definieren wir in der TCA Comumns Section jedes Feld aus der Datenbank. Felder die hier nicht aufgeführt werden, kennt TYPO3 nicht, selbst wenn sie durch die ext_tables.sql erzeugt wurden. Auch wenn wir das Feld im Formular nicht anzeigen wollen (z.B. Felder die die Datensatzsortierung beinhalten) müssen wir es hier aufführen.

Wir hatten bei der Erstellung der ext_table.sql Felder definiert, die für das Arbeiten mit TYPO3 unerlässlich sind. Dazu gehörten uid, pid, tstamp, crdate, deleted und hidden. Uid und pid sind Systemfelder und brauchen Ausnahmsweise keinen weiteren Eintrag. Die anderen Felder haben wir bereits in der crtl Section gemapped. Da wir das hidden Feld später in unseren Formularen editieren wollen, müssen wir es hier nochmal aufnehmen:

'columns' => array(
       
        'hidden' => array(
            'exclude' => 1,
            'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
            'config' => array(
                'type' => 'check'
            )
        ),

       //hier folgen die Tabellen spezifischen Felder
)

Columns Section der Product TCA:

'columns' => array(
        'hidden' => array(
            'exclude' => 1,
            'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
            'config' => array(
                'type' => 'check'
            )
        ),
        'prod_sort' => array(
            'config' => array(
                'type' => 'passthrough')
        ),
        'prod_name' => array(
            'exclude' => 0,
            'label' => 'Name',
            'config' => array(
                'type' => 'input',
                'size' => 50,
            )
        ),
        'prod_description' => array(
            'exclude' => 0,
            'label' => 'Beschreibung',
            'config' => array(
                'type' => 'text',
                'cols' => 40,
                'rows' => 5,
            ),
            'defaultExtras' => 'richtext:rte_transform[flag=rte_enabled|mode=ts]',
        ),
        'prod_images' => array(
            'exclude' => 0,
            'label' => 'Artikel Bilder',
            'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('prodimage', array(
                'appearance' => array(
                    'createNewRelationLinkTitle' => 'Bild hinzufügen',
                    'collapseAll' => FALSE,
                ),
                    ), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'])
        ),
        'prod_category' => array(
            'exclude' => 0,
            'label' => 'Kategorie',
            'config' => array(
                'type' => 'select',
                'foreign_table' => 'tx_euromediaproducts_domain_model_category',
                'foreign_table_where' => 'ORDER BY category ASC',
                'size' => 1,
                'minitems' => 0,
                'maxitems' => 1,
            ),
        ),
        'prod_manufacture' => array(
            'exclude' => 0,
            'label' => 'Hersteller',
            'config' => array(
                'type' => 'select',
                'items' => array(
                    array('', 0),
                ),
                'foreign_table' => 'tx_euromediaproducts_domain_model_manufacture',
                'foreign_table_where' => 'ORDER BY manu_titel ASC',
                'size' => 1,
                'minitems' => 0,
                'maxitems' => 1,
            ),
        ),
        'prod_maintextcontent' => Array(
            'exclude' => 0,
            'label' => 'Content',
            'config' => Array(
                'type' => 'inline',
                'foreign_table' => 'tx_euromediaproducts_domain_model_productcontent',
                'foreign_field' => 'prodid',
                'maxitems' => 99,
            ),
        ),
        'prod_descriptioncontent' => Array(
            'exclude' => 0,
            'label' => 'Content',
            'config' => Array(
                'type' => 'inline',
                'foreign_table' => 'tx_euromediaproducts_domain_model_productcontent',
                'foreign_field' => 'descrptionid',
                'maxitems' => 99,
            ),
        ),
        'prod_benefitcontent' => Array(
            'exclude' => 0,
            'label' => 'Content',
            'config' => Array(
                'type' => 'inline',
                'foreign_table' => 'tx_euromediaproducts_domain_model_productcontent',
                'foreign_field' => 'benefitsid',
                'maxitems' => 99,
            ),
        ),
        'prod_techdetailcontent' => Array(
            'exclude' => 0,
            'label' => 'Content',
            'config' => Array(
                'type' => 'inline',
                'foreign_table' => 'tx_euromediaproducts_domain_model_productcontent',
                'foreign_field' => 'technicalid',
                'maxitems' => 99,
            ),
        ),
        'prod_downloads' => array(
            'exclude' => 0,
            'label' => 'Hersteller Logos',
            'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('downloads', array(
                'appearance' => array(
                    'createNewRelationLinkTitle' => 'Bild hinzufügen',
                    'collapseAll' => FALSE,
                ),
                    ), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'])
        ),
    ),

An diesem Beispiel sehen wir die unterschiedlichen Konfigurationsmöglichkeiten für die TCA Formularfelder.

config -> type -> check: erzeugt eine Checkbox, siehe hidden Feld
config -> type -> input: ein einfaches Textfeld, siehe prod_name
config -> type -> select: Select-Auswahlfeld mit Einträgen einer anderen Tabelle. Das Feld prod_manufacture hat zusätzlich eine leere Auswahl im Selectfeld.
config -> type ->text: erzeugt ein Textarea Feld, mit der Zeile "default extras" wird der RTE aktiviert.
config -> \TYPO3\... :getFileField: erstellt ein FAL Feld. Die felder sind umfangreich konfigurierbar.
config -> type -> inline: erstellt ein Feld für eine Inline Relation

Die columns Sections der anderen TCAs bauen wir entsprechend auf:

 

Columns Section der Productcontent TCA
Die Configuration des Image Positions Feldes ist eine Kopie aus der tt-content TCA. Damit erhlaten wir in unserem Formular die gleichen Optionen zur Bildpositionierung wie in normalen Contentelement Text/Bild.

    'columns' => array(
        'prodid' => array(
            'config' => array(
                'type' => 'passthrough')
        ),
        'descrptionid' => array(
            'config' => array(
                'type' => 'passthrough')
        ),
        'benefitsid' => array(
            'config' => array(
                'type' => 'passthrough')
        ),
        'technicalid' => array(
            'config' => array(
                'type' => 'passthrough')
        ),
        'prodcont_headline' => array(
            'config' => array(
                'type' => 'input',
                'size' => 30,
            )
        ),
        'prodcont_text' => array(
            'exclude' => 0,
            'label' => 'Beschreibung',
            'config' => array(
                'type' => 'text',
                'cols' => 40,
                'rows' => 5,
            ),
            'defaultExtras' => 'richtext:rte_transform[flag=rte_enabled|mode=ts]',
        ),
        'prodcont_images' => array(
            'exclude' => 0,
            'label' => 'Artikel Bilder',
            'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('prodimage', array(
                'appearance' => array(
                    'createNewRelationLinkTitle' => 'Bild hinzufügen',
                    'collapseAll' => FALSE,
                ),
                    ), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'])
        ),
        'prodcont_imageposition' => array(
            'exclude' => 0,
            'label' => 'Bildposition',
            'config' => array(
                'type' => 'select',
                'items' => array(
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.0',
                        0,
                        'selicons/above_center.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.1',
                        1,
                        'selicons/above_right.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.2',
                        2,
                        'selicons/above_left.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.3',
                        8,
                        'selicons/below_center.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.4',
                        9,
                        'selicons/below_right.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.5',
                        10,
                        'selicons/below_left.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.6',
                        17,
                        'selicons/intext_right.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.7',
                        18,
                        'selicons/intext_left.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.8',
                        '--div--'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.9',
                        25,
                        'selicons/intext_right_nowrap.gif'
                    ),
                    array(
                        'LLL:EXT:cms/locallang_ttc.xlf:imageorient.I.10',
                        26,
                        'selicons/intext_left_nowrap.gif'
                    )
                ),
                'selicon_cols' => 6,
                'default' => '0',
                'iconsInOptionTags' => 1
            )
        ),
    ),
        

Die Columns Section der Hersteller- und Kategorietabelle:

    'columns' => array(
        'hidden' => array(
            'exclude' => 1,
            'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
            'config' => array(
                'type' => 'check'
            )
        ),
        'man_name' => array(
            'exclude' => 0,
            'label' => 'Name',
            'config' => array(
                'type' => 'input',
                'size' => 30,
            )
        ),
        'man_web' => array(
            'exclude' => 0,
            'label' => 'Name',
            'config' => array(
                'type' => 'input',
                'size' => 30,
            )
        ),
    ),
        
    'columns' => array(
        'hidden' => array(
            'exclude' => 1,
            'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.hidden',
            'config' => array(
                'type' => 'check'
            )
        ),
        'kat_name' => array(
            'exclude' => 0,
            'label' => 'Kategorie',
            'config' => array(
                'type' => 'input',
                'size' => 30,
            )
        ),
    ),
      

Damit haben wir unsere TCA nun endlich fertig gestellt. Ihr könnt eure Ergebnisse auch mit meinen Dateien auf GIT-Hub vergelichen: gittHub tut_produktdatenbank.

Bevor die Extension installieren können, brauchen wir noch ein paar Angaben in der ext_emconf Datei:


Die ext_emconf Datei

Wie der Dateiname es schon vermuten lässt, werden hier alle Angaben für den Extensionmanager gemacht. Da unsere Extension keinerlei Besonderheiten hat können wir uns hier relativ kurz fassen:

$EM_CONF[$_EXTKEY] = array (
	'title' => 'Tutorial Produktdatenbank',
	'description' => 'Tutorial einer Extbase/Fluid Produktdatenbak. t3-developer.com',
	'category' => 'Frontend',
	'version' => '6.2.0',
	'state' => 'stable',
	'uploadfolder' => 0,
	'createDirs' => '',
	'clearcacheonload' => 1,
	'author' => 'klaus heuer',
	'author_email' => 'klaus.heuer@t3-developer.com',
	'author_company' => 't3-developer.com',
	'constraints' => 
	array (
		'depends' => 
		array (
		),
		'conflicts' => 
		array (
		),
		'suggests' => 
		array (
		),
	),
);

Endlich geschafft!

Wir können nun unsere Extension über den Extensionmanager erstmalig installieren. Dazu ladet Ihr euer Verzeichnis tut_produktdatenbank auf einen Webserver ins tpo3conf/ext Verzeichnis hoch. Nach dem leeren des Caches steht die Extension als installierbare Option im Extensionmanager zur Verfügung.

Jetzt noch einen Systemordner anlegen und über die Listenansicht können Datensätze erfasst werden.

Im nächsten Abschnitt legen wir die Extbase Models und Repositories an.

Tutorial Start nächstes Kapitel

Weitere Artikel zu diesem Thema:

Empfehlenswerte Lektüre:

Git. Verteilte Versionsverwaltung für Code und Dokumente

Das Buch richtet sich an Einsteiger und erfahrene Benutzer die ihre Kenntnisse vervollständigen wollen. Klar strukturiert, mit vielen Beispielen aus der Praxis, hilft das Buch die Funktionsweise von GIT zu verstehen und erklärt alle nötigen Befehele. Für Entwickler unbedingt empfehlenswert.

Kommentare

keine Kommentare vorhanden


Kommentar verfassen

Die Email Adresse wird nicht veröffentlicht.