Typo3 – eine eigene Extension erstellen

Auch wenn es zig Extensions bereits gibt, viele davon sind nur dürftig dokumentiert, andere bieten einfach nicht alle Funktionen, die man aktuell braucht. Schneller als einem lieb ist, wird man bei seiner Arbeit mit typo3 mit der Notwendigkeit konfrontiert, eine eigene Extension erstellen zu müssen. Deshalb hier eine kleine Anleitung anhand eines konkreten Beispiels.

Die Anforderungen

Ein neues Inhaltselement namens “Produktauswahl” soll es möglich machen, im Backend Produkte (die mit einer anderen Extension erstellt wurden) auszusuchen und im Frontend in einem jQuery Slider darzustellen.
Dafür benötigen wir folgendes:
– die Produkte Extension (in diesem Fall opensistemascasestudies)
– die Kickstarter Extension (die die ersten Schritte beim Extension erstellen sehr erleichtert)
– FTP Zugang zum Projekt

Backend – Start mit dem Kickstarter

Zunächst erstellen wir im Kickstarter eine neue Extension. Über Erweiterungen – Create a new Extension rufen wir den Kickstarter Wizard auf. Zuerst tragen wir unter General Info ein paar grundlegende Daten ein: wie heißt die Erweiterung, was macht sie, wer ist der Autor, etc. Als Kategorie wählen wir “Frontend” und Status “Alpha”.

Unsere Produktauswahl muss irgendwo gespeichert werden, also klicken wir auf new Database Tables und vergeben einen Tabellennamen (in meinem Fall tx_ccproduktauswahl_choice). Weiter unten besteht die Möglichkeit, ein Feld hinzuzufügen. Wir nennen das Feld “auswahl” und wählen als Field Type “Database Relation”. Hier sind die Möglichkeiten vielfältig, man könnte auch ein einfaches Textfeld wählen, oder ein RTE Textfeld, aber da wir Daten aus der Datenbank einfügen wollen, nehmen wir Database Relation, updaten einmal, wählen dann “custom table” aus und geben den Namen unseres extension tables ein: tx_opensistemasproductsservices_products_and_services

Anschließend wählen wir noch Frontend Plugins aus, tragen nochmal den Titel Produktauswahl ein und wählen “Add to ‘Insert Plugin’ list in Content Elements” und haken “Add icon to ‘New Content Element’ wizard” an.

Am Ende klicken wir links auf “view result” und wenn wir zufrieden sind, schreiben wir die Extension (write) und installieren sie.

Wichtig:

  • nach dem Ändern immer den “update” Button betätigen
  • Fehler beim Erstellen der Extension können problemlos ausgebessert werden. Wichtig ist aber, dass der Kickstarter alle Änderungen in der php Datei der Extension überschreibt. Bereits aktive, funktionierende Extensions sollten also als komplettes Backup vorhanden sein, bevor man sich an “edit in kickstarter” heranwagt.

Backend – Flexforms

Wenn wir alles richtig gemacht haben, steht uns unsere Extension nun als Contentelement zur Auswahl. Wir erstellen also eine Testseite und dort ein Contentelement mit dem Plugin “Produktauswahl”. Außer einem Titel wird man allerdings noch nichts eingeben oder auswählen können, aber das ist normal. Denn als nächstes müssen wir nachhelfen, damit unser Feld auch wirklich im Backend angezeigt wird.
Wir gehen dafür in den Ordner, den kickstarter für unsere Extension erstellt hat (typo3conf/ext/cc_produktauswahl/) und öffnen als erstes die Datei ext_tables.php und fügen ihr zum Schluss zwei Zeilen an:

  1. $TCA['tt_content']['types']['list']['subtypes_addlist'][$_EXTKEY.'_pi1']='pi_flexform';
  2. t3lib_extMgm::addPiFlexFormValue($_EXTKEY.'_pi1', 'FILE:EXT:'.$_EXTKEY.'/flexform_ds_pi1.xml');

Damit haben wir den Verweis zur xml Datei geschaffen, diese erstellen wir nun im Extension Verzeichnis und füllen sie mit folgenden Daten:

  1. <T3DataStructure>
  2. <sheets>
  3. <sDEF>
  4. <ROOT>
  5. <TCEforms>
  6. <sheetTitle>Options</sheetTitle>
  7. </TCEforms>
  8. <type>String</type>
  9. <el>
  10. <prods>
  11. <TCEforms>
  12. <exclude>1</exclude>
  13. <label>Produkte</label>
  14. <config>
  15. <type>group</type>
  16. <internal_type>db</internal_type>
  17. <allowed>tx_opensistemasproductsservices_products_and_services</allowed>
  18. <size>5</size>
  19. <maxitems>5</maxitems>
  20. <minitems>0</minitems>
  21. <show_thumbs>1</show_thumbs>
  22. </config>
  23. </TCEforms>
  24. </prods>
  25. </el>
  26. </ROOT>
  27. </sDEF>
  28. </sheets>
  29. </T3DataStructure>

Das “prods” tag beschreibt unser Auswahlfeld. Mit internal_type = db geben wir an, dass wir Daten aus der Datenbank holen wollen und allowed spezifiziert die Datenbank. Size ist die Größe des Selects, max- und minitems die Mindest- und Maximalanzahl der ausgewählten Einträge. Wir speichern die xml Datei, löschen den Cache und bearbeiten erneut unser Inhaltselement mit unserem Plugin und nun sollte auch unsere Produktauswahl sichtbar sein.

Wir wählen ein paar Produkte aus, speichern und wenn alles geklappt hat, wenden wir uns der Anzeige im Frontend zu.

Template

Als nächstes basteln wir uns ein Template für den Slider. Ich nehme für meinen Slider den jquery Coda Slider 2.0, dementsprechend passe ich meine HTML Vorlage an:

  1. <!-- ###TEMPLATE_SLIDE### begin-->

###TITLE###

 

###IMAGE###

 

###HEADER###. 

###BODY###

 

 

Für den Slider wird der gesamte Komplex umschlossen von zwei DIV tags, nämlich “coda-slider-wrapper” und “coda-slider preload”. TEMPLATE_SLIDE_ITEM ist die Vorlage für jedes Einzelitem, das dann später einem Panel des Sliders entspricht.
Wie das Template aussieht, ist natürlich im Prinzip unerheblich. Die wenigsten werden für ihre Extension einen Slider benötigen, aber für die Wartbarkeit und Übersichtlichkeit ist es definitiv nicht schlecht, ein Template zu haben und das bei den anderen in fileadmin/templates zu speichern. Wir nennen das Template slider.html, speichern es und widmen uns nun der Frontend Ausgabe.

Anzeige im Frontend

Rufen wir die Seite nun im Frontend auf, sehen wir, dass der Kickstarter uns ein schlichtes Formular gebastelt hat. Diese Ausgabe wird erzeugt in der Datei typo3conf/ext/cc_produktauswahl/pi/class.tx_ccproduktauswahl_pi1.php und daher öffnen wir nun diese Datei. Die Ausgabe spielt sich in der main Funktion ab und hier sieht man schon, wie das Formular erzeugt wird. Der Text wird in $content gespeichert und dann zurückgegeben.
Zuallererst holen wir uns unsere Flexform Inhalte:

  1. $this->pi_initPIflexForm();
  2. $piFlexForm = $this->cObj->data['pi_flexform'];
  3. foreach ( $piFlexForm['data'] as $sheet => $data ) {
  4. foreach ( $data as $lang => $value ) {
  5. foreach ( $value as $key => $val ) {
  6. $res[$key] = $this->pi_getFFvalue($piFlexForm, $key, $sheet);
  7. }
  8. }
  9. }

Nun haben wir unsere Inhalte in $res gespeichert. Hätten wir zwei Produkte mit den IDs 347 und 588 ausgewählt, sähe $res[‘prods’] so aus: 347,588
Nun laden wir unsere vorher erstellte Template Datei.

  1. $templateFile = 'fileadmin/templates/slider.html';
  2. $template = $this->cObj->fileResource($templateFile);
  3. $tpl = $this->cObj->getSubpart($template,"###TEMPLATE_SLIDE###");
  4. $tpl_ref = $this->cObj->getSubpart($template,"###TEMPLATE_SLIDE_ITEM###");

Die Namensgebung ist hierbei natürlich unwichtig.
Da unsere Produkt IDs in einem String, getrennt durch Kommata, vorhanden sind, zerpflücken wir sie mit einem Explode und holen dann mit den typo3 Funktionen die zugehörigen Daten aus der Datenbank:

  1. $tmp = explode(",", $res['prods']); //die ausgewählten produkte !
  2. if(sizeof($tmp) > 0){
  3. foreach($tmp as $k => $prodID){
  4. $record=$this->pi_getRecord('tx_opensistemasproductsservices_products_and_services',$prodID);
  5. $marker['###TITLE###'] = $record['title'];
  6. $marker['###BODY###'] = $record['body'];
  7. $itemContent.= $this->cObj->substituteMarkerArrayCached($tpl_ref,$marker);
  8. }
  9. }

Explode macht aus dem String ein Array, und für jedes Element des Arrays, d.h. für jede Produkt ID, lesen wir die Daten aus (pi_getRecord), ersetzen die Marker und speichern die Ausgabe in $itemContent.
Nach dem Durchlaufen der Produkte fügen wir unseren Inhalt in den Gesamtmarker ein und speichern das Ergebnis in $content:

  1. $content = $this->cObj->substituteSubpart($template,'###TEMPLATE_SLIDE_ITEM###',$itemContent);

Wir laden die Datei so hoch, leeren den Cache (WICHTIG!) und aktualisieren unsere Seite. Und nun – haben wir auch eine richtige Ausgabe.

Hier nochmal die komplette Version der main Funktion:

  1. function main($content, $conf) {
  2. $this->conf = $conf;
  3. $this->pi_setPiVarDefaults();
  4. $this->pi_loadLL();
  5. //Flexform Daten holen
  6. $this->pi_initPIflexForm();
  7. $piFlexForm = $this->cObj->data['pi_flexform'];
  8. foreach ( $piFlexForm['data'] as $sheet => $data ) {
  9. foreach ( $data as $lang => $value ) {
  10. foreach ( $value as $key => $val ) {
  11. $res[$key] = $this->pi_getFFvalue($piFlexForm, $key, $sheet);
  12. }
  13. }
  14. }
  15. //Template laden
  16. $templateFile = 'fileadmin/templates/slider.html';
  17. $template = $this->cObj->fileResource($templateFile);
  18. $tpl = $this->cObj->getSubpart($template,"###TEMPLATE_SLIDE###");
  19. $tpl_ref = $this->cObj->getSubpart($template,"###TEMPLATE_SLIDE_ITEM###");
  20. //Produkte durchlaufen
  21. $tmp = explode(",", $res['prods']); //die ausgewählten produkte !
  22. if(sizeof($tmp) > 0){
  23. foreach($tmp as $k => $prodID){
  24. $record=$this->pi_getRecord('tx_opensistemasproductsservices_products_and_services',$prodID);
  25. $marker['###TITLE###'] = $record['title'];
  26. $marker['###BODY###'] = $record['body'];
  27. $itemContent.= $this->cObj->substituteMarkerArrayCached($tpl_ref,$marker);
  28. }
  29. }
  30. $content = $this->cObj->substituteSubpart($template,'###TEMPLATE_SLIDE_ITEM###',$itemContent);
  31. return $this->pi_wrapInBaseClass($content);
  32. }

Conclusio

Damit haben wir eine erste Extension erstellt, die sich über die flexform_ds_pi1.xml Datei und die class.tx_ccproduktauswahl_pi1.php ändern/erweitern lässt.