Inside TYPO3 – Teil 4 – Das Table Configuration Array und Flexforms: Ein Blick in das Innere des CMS
Eine der Hauptaufgaben eines Content Management Systems ist es, Daten in die Datenbank zu schreiben und dort wieder heraus zu holen und darzustellen – so auch bei TYPO3. Es gibt eine Vielzahl von Möglichkeiten, dies zu realisieren – wobei einige davon beispielsweise alle dazu benötigten Informationen direkt aus der Datenstruktur der Datenbank ermitteln. So könnte man beispielsweise ein Feld, das in der Datenbank als „TEXT“ definiert ist, lediglich als „HTML INPUT“-Feld im Backend darstellen. Füllt man dieses Feld aus, wird der Inhalt wieder in die Datenbank geschrieben. Dieses Vorgehen hat allerdings eine Reihe von Nachteilen:
- Es lassen sich nur wenige verschiedene Eingabe-Typen realisieren: Würde man beispielsweise in ein INPUT-Feld einen Bildnamen schreiben, wüsste TYPO3 nicht, dass das Bild und nicht nur der Name angezeigt werden soll.
- Man kann keinerlei Validierung festlegen und als Eingabewert etwa nur positive Zahlen zulassen.
- TYPO3 müsste alle Tabellendefinitionen ermitteln und laden, da das CMS gar nicht wissen kann, welche Tabellen gerade in Benutzung sind und welche beispielsweise nur Überbleibsel von früheren Tests oder deinstallierten Extensions sind.
- Bei jeder Veränderung (z. B. hinsichtlich der Darstellung) müsste die Datenbank direkt beschrieben werden.
- Verbindungen zu anderen Tabellen sind nur mit Fremdschlüsseln zu erreichen. Diese stehen aber aufgrund von Kompatibilitätsgründen nicht zur Verfügung. Somit können keinerlei Relationen realisiert werden.
- Manche Eingabetypen lassen sich schlicht nicht realisieren. So gibt es mit normalen INPUT-Feldern keine Möglichkeit, Checkboxen oder Selectboxen abzubilden.
- Man kann in der Datenstruktur keinerlei Informationen dazu hinterlegen, wie das spätere Eingabeformular realisiert werden soll – beispielsweise welche Felder sich wo befinden oder ob bestimmte Felder ein- oder ausgeblendet werden sollen.
Daher hat man sich bei der Konzeption von TYPO3 dazu entschieden, mit dem so genannten Table Configuration Array, kurz TCA, eine weitere Ebene einzuführen. Dieses Array enthält neben den generellen Informationen zu den Tabellen auch Informationen zu den einzelnen Feldern sowie ausreichend Metainformationen in Bezug auf Rendering, Validierung und die Relationen zu anderen Tabellen und Feldern. Da diese Informationen nun als PHP-Array vorliegen, können sie leicht beschrieben und ermittelt werden.
Der Zugriff auf dieses Array aus PHP heraus lautet schlicht „$TCA“. Sie können das TCA aber auch im Backend Ihrer TYPO3-Installation einsehen, da dieses hierfür ein eigenes Modul entält. Klicken Sie hierzu auf das Modul „Tools -> Configuration“ und wählen aus dem Pulldownmenü „$TCA (tables.php)“.
Die meisten im System verfügbaren Tabellen, für die eine Definition sinnvoll ist, werden hier aufgelistet. Die Unterschlüssel „ctrl“, „interface“, „feInterface“, „types“ und „palettes“, sind für die Konfiguration der Tabelle und deren Darstellung im Ganzen zuständig. Im Unterschlüssel „columns“ befinden sich die Definitionen der einzelnen Tabellenfelder (Spalten). Dabei haben die Unterschlüssel folgende Bedeutung:
ctrl
Hiermit werden die Eigenschaften festgelegt, wie die Tabelle im Backend aussehen soll und wie diese grundsätzlich behandelt werden soll. So wird beispielsweise festgelegt, welches Label für die Bezeichnung im Modul „Liste“ verwendet wird und welche Felder ein- oder ausgeblendet werden sollen.
interface
Mit diesem Schlüssel wird das Interface im Backend definiert. So können hier Einstellungen für die Informationsdialoge, Feldbeschreibungen und die Anzahl der Datensätze in der Seiten- und Listenansicht definiert werden.
feInterface
Während der Unterschlüssel „interface“ für das Backend zuständig ist, wird mit „feInterface“ das Interface im Frontend konfiguriert. Dieses wird beim Frontend-Editing angesprochen, so kann man die dafür benötigten Einstellungen detailiert festlegen.
palettes
Über Paletten können verschiedenste Formularelemente zusammengefasst und strukturiert werden. Darüber hinaus dienen sie dazu, sogenannte „Secondary Options“ zu definieren, also zusätzliche Optionen. Diese können leicht über die Checkbox am unteren Ende der Seite in der Seitenansicht ausgeblendet werden, um die Übersicht zu erhöhen.
types
Dieser Unterschlüssel legt einerseits die Reihenfolge der Elemente in einem Backend-Formular fest, andererseits definiert er Felder in Abhängigkeit anderer Felder. So hat beispielsweise jeder Seitentyp eigene Eingabefelder. Ändert man den Seitentyp, wird die Seite neu geladen und präsentiert andere Eingabefelder als zuvor. Dabei ist wichtig zu wissen, dass es sich hierbei lediglich um eine andere Darstellung handelt. Einmal eingegebene Daten im Formular bleiben auch beim Seitentyp-Wechsel erhalten.
columns
Hier werden die einzelnen Felder konfiguriert. Dieser Abschnitt ist daher auch der umfangreichste, da für jedes Feld, das im Backend editiert werden kann, eine eigene Definition vorhanden ist. Hier kann beispielsweise festgelegt werden, um welchen Typ es sich bei dem Feld handelt.
Innerhalb von columns gibt (wie bei den anderen Unterschlüsseln auch) weitere Schlüssel – hier beispielsweise „label“ (legt die Beschriftung fest) und „config“ (dessen Unterschlüssel „type“ wiederum den grundsätzlichen Typ des Backendfelds festlegt und konfiguriert). Die nachstehende Tabelle zeigt die möglichen Typen.
Input type | Resultat im Backend-Formular |
input | Ein normales INPUT-Feld, gegebenenfalls mit zusätzlichen Parametern wie Evaluierung, Passwort-Feld, Datumsfeld etc. |
text | Textbox |
check | Checkbox |
radio | Radiobutton |
select | Selectbox |
group | Referenzen zu Datensätzen |
none | Nur Anzeige des Felds, aber keine Möglichkeit zur Veränderung |
passthrough | Wird direkt ohne Evaluierung in die Datenbank geschrieben |
user | Stellt die Möglichkeit zur Verfügung, eine eigene Klasse/Methode zur Darstellung und Evaluierung im Backend zu verwenden |
flex | Stellt eine Flexform zur Verfügung (siehe nächster Abschnitt) |
inline | Dient zur Konfiguration der IRRE-Fuktionalität (Inline-Relational-Record-Editing) |
Wenn man nun eine Extension erstellt, die die vier Felder „description“ (ein Textfeld), „industry“ (ein Eingabefeld), „url“ (ein Eingabefeld) und „logo“ (enthält den Pfad einer heraufladbaren Bilddatei) definiert hat, führt dies zu einem TCA ähnlich dem in der nächsten Abbildung. Gut zu sehen sind die columns-Bereiche der Felder samt ihres Typs.
Mit dieser Methode stößt man allerdings bald auf eine Schwachstelle. Nehmen wir einmal an, man möchte die Tabelle „tt_content“ erweitern, in der die Inhalte vorliegen. Das kann man erreichen, indem man ein neues Feld und die entsprechende TCA-Definition hinzufügt. Dieses Vorgehen mag zwar für zwei bis drei Extensions funktionieren, spätestens wenn man mehr Erweiterungen benötigt, sollte man dies auf eine andere Art regeln – schon damit die bestehende Tabelle nicht unnötig aufgebläht wird.
Flexforms
Eine Flexform ist im Grunde nichts anderes als eine etwas anders notierte TCA-Definition. Man definiert dabei in der Tabelle ein Feld vom Typ „flex“ und legt in dieses eine Flexform – ein XML-Dokument, das selbst wiederum ein komplexes Formular mit zahlreichen Feldern und sogar einzelnen Eingabeseiten (Sheets) definieren kann. Hauptanwendungsgebiet für Flexforms ist die Konfiguration von Plugins.
Die Konfiguration (alleine bei tt_news wären es 30 Optionen) wird nicht in der Tabelle „tt_content“ gespeichert, sondern im Feld „pi_flexform“. Genauer gesagt wird die Flexform selbst im Filesystem gespeichert (diese wird zum rendern der Backendformulare verwendet) und die in die Flexform eingegebenen Werte im Feld „pi_flexform“. Die für tt_news verwendete Flexform befindet sich in der Datei „typo3conf/ext/tt_news/flexform_ds.xml“ und sieht beispielsweise wie folgt aus:
<T3DataStructure> [...] <sheets> <sDEF> <ROOT> <TCEforms> <sheetTitle>LLL:EXT:tt_news/locallang_tca.xml:tt_news.pi_flexform.sheet_general</sheetTitle> <TCEforms> <type>array</type> <el> <what_to_display> <TCEforms> <label>LLL:EXT:tt_news/locallang_tca.xml:tt_news.pi_flexform.what_to_display</label> <config> <type>select</type> <items type="array"> <numIndex index="0" type="array"> <numIndex index="0">LIST</numIndex> <numIndex index="1">LIST</numIndex> </numIndex> <numIndex index="1" type="array"> <numIndex index="0">LATEST</numIndex> <numIndex index="1">LATEST</numIndex> </numIndex> [...] </config> </TCEforms> </what_to_display> [...] </el> </ROOT> </sDEF> [...] </sheets> </T3DataStructure>
Listing 1
In Listing 1 finden sich einige alte Bekannte: Das Feld, das im obigen Abschnitt definiert wird, hat den Namen „what_to_display“ und gibt den Modus an, in dem das Plugin laufen soll – also „LIST“, „LATEST“, „SINGLE“, „AMENU“ etc.
Über den Abschnitt „config“ wird wie im TCA das Eingabefeld konfiguriert und auch der Typ (hier „select“) festgelegt. Danach folgen die restlichen Konfigurationen für dieses Feld und später auch für alle anderen Felder.
Flexforms selbstgemacht
Will man nun selbst eine Flexform zu seiner selbstgeschriebenen Extension hinzufügen, muss man nur nach dem folgenden Schema vorgehen: Zunächst muss eine Extension erstellt und installiert werden. Anschließend wird die Datei „ext_tables.php“ modifiziert, in dem man die beiden folgenden Zeilen hinzufügt:
... $TCA['tt_content']['types']['list']['subtypes_addlist'][$_EXTKEY.'_pi1']='pi_flexform'; t3lib_extMgm::addPiFlexFormValue($_EXTKEY.'_pi1', 'FILE:EXT:'.$_EXTKEY.'/flexform_ds_pi1.xml'); ...
Listing 2
Nun wird im Root-Verzeichnis der Extension eine XML-Datei mit dem Namen „flexform_ds_pi1.xml“ angelegt. Eine Beispielkonfiguration finden Sie im TYPO3-Wiki [1] oder in der Dokumentation zu Flexforms [2]. Nach dem Löschen der Caches sollte die Flexform nun im Backend angezeigt werden, wenn Sie Ihr Plugin zufügen.
Wenn Sie auf die eingegebenen Werte zugreifen wollen, können Sie dies sehr einfach bewerkstelligen. Platzieren Sie einfach den Code zum Auslesen der Flexform in Ihre Plugin-Klasse:
class tx_meinExtensionKey_pi1 extends tslib_pibase { [...] function main($content,$conf) { ... // Initialisiere die Flexform $this->pi_initPIflexForm(); //Vorbereiten des Containers, der die Flexform-Werte enthalten soll $this->lConf = array(); // Auslesen des gesamten Flexform-Datenfeldes $piFlexForm = $this->cObj->data['pi_flexform']; // Nun wird das gesamte Array durchgegangen und die einzelnen // Werte ermittelt foreach ( $piFlexForm['data'] as $sheet => $data ) { foreach ( $data as $lang => $value ) { foreach ( $value as $key => $val ) { $this->lConf[$key] = $this->pi_getFFvalue($piFlexForm, $key, $sheet); // Beispielausgabe der Werte var_dump($this->lConf[$key]); } } } [...] }
Listing 3
Alle Artikel der Serie | |
Teil 1 (T3N Nr. 13) | Tour de Core |
Teil 2 (T3N Nr. 14) | Allgemeine APIs |
Teil 3 (T3N Nr. 15) | Backend- und Frontend-APIs |
Teil 4 (T3N Nr. 16) | TCA, Flexforms, Ajax |