Extensions flexibel und anpassbar entwickeln: Erweiterbare Erweiterungen
Entwickler können TYPO3 auf verschiedenste Art und Weise erweitern. Neben klassischen Extensions stehen auch die Konfiguration via TypoScript, Hooks und das XCLASS-Verfahren zur Verfügung. Nachfolgend werden diese Wege näher beleuchtet.
Funktionalität auslagern
Mit TypoScript kann eine Extension über cObject-Konstrukte [1] mit ergänzenden oder alternativen Funktionen ausgestattet werden. Innerhalb eines Plugins, das in der Regel von der Klasse „tslib_pibase“ erbt, können zusätzliche cObjects verarbeitet werden.
includeLibs.myfunc = fileadmin/scripts/user_myFunc.php plugin.tx_my_pi1.finish = USER_INT plugin.tx_my_pi1.finish { userFunc = user_myFunc->sendMail mailTo = admin@example.com }
Listing 1
Das entsprechende cObject wird in der Plugin-Konfiguration bestückt. USER_INT aus Listing 1 ermöglicht das nicht-gecachte Ausführen einer Funktion oder einer Klassenmethode. Es können natürlich auch die anderen cObject-Typen (CONTENT, COA, TEXT, MULTIMEDIA etc.) verwendet werden.
class tx_my_pi1 extends tslib_pibase { function main($content, $conf) { if($conf['finish']) { $this->cObj->regObj = $this; // Referenz auf Plugin-Objekt $content = $this->cObj->cObjGetSingle($conf['finish'],$conf['finish.']); } return $content; } }
Listing 2
Die Methode „cObjGetSingle“ der Oberklasse „tslib_pibase“ wird verwendet, um ein cObject „auszuführen“. USER-/USER_INT-Funktionen kann Zugriff auf den Plugin-Kontext gewährt werden. Der Rückgabewert ist stets eine Zeichenkette.
class user_myFunc { public $cObj = null; // wird automatisch gesetzt function sendMail($content, $conf) { $context = $this->cObj->regObj; // Referenz auf Plugin-Objekt mail($conf['mailTo'], 'Finished', 'Klasse: '.get_class($context)); } }
Listing 3
Die Einsatzgebiete dieser Vorgehensweise sind nahezu unerschöpflich, hängen aber von den vom Entwickler geschaffenen Erweiterungspunkten ab.
Marker
Jede Extension sollte eine Erweiterung der im Template einsetzbaren Marker zulassen. Um dazu nicht Klassen überschreiben zu müssen, kann die TypoScript-Konfiguration bereits viel leisten. Die Extension „tt_news“ beispielsweise geht einen anderen Weg und gewährleistet dies über einen so genannten Hook.
Hooks
Hooks [2] sind zunächst einmal Listen mit Funktionsnamen. Jeder Hook hat einen eindeutigen Namen. Die Funktionen werden an einer vom Entwickler vorgesehenen Stelle im PHP-Quellcode sequenziell aufgerufen. Je nach Einsatzzweck kann solchen Funktionen voller Zugriff auf den aktuellen Kontext gewährt werden. Der Kern wird somit erweiterbar.
Über einen Hook in der TYPO3-Klasse „tslib_fe-Klasse“ wird es beispielsweise ermöglicht, kurz vor der Ausgabe der Webseite im Frontend eine Aktion auszuführen und Werte des Objekts zu verändern.
require_once('fileadmin/user_badword.php'); $TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all']['my'] = 'user_myBadword';
Listing 4
function user_myBadword($param, $context) { $context->content = str_replace('schlecht', 'suboptimal', $context->content); }
Listing 5
// Hook for post-processing of page content cached/non-cached: if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'])) { $_params = array('pObj' => &$this); foreach($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'] as $_funcRef) { t3lib_div::callUserFunction($_funcRef,$_params,$this); } }
Listing 6
XCLASS
Jede Klasse einer Extension bietet in der Regel die Möglichkeit, sie durch eine Ableitung zu überschreiben. Dies ist dann nützlich, wenn die zu ändernde Stelle nicht mit den zuvor genannten Mitteln erweitert werden kann.
if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/template.php']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/template.php']); }
Listing 7
Verwendet man das XCLASS-Verfahren, so trägt die neue Klasse den Namen der abgeleiteten Klasse mit dem Präfix „ux_“, etwa „ux_template“. Über diese Namenskonvention kann TYPO3 die Ableitung der ursprünglichen Klasse automatisch identifizieren.
Alles new?
Wird XCLASS genutzt, soll auch immer ein Objekt der neuen Klasse erstellt werden. Darum darf ein solches Objekt nicht unter expliziter Angabe des Klassennamens mit dem Schlüsselwort „new“ erzeugt werden. Stattdessen lässt man TYPO3 entweder den Klassennamen ermitteln oder das Objekt direkt erstellen.
// Klassennamen ermitteln lassen und Objekt erstellen $templateClass = t3lib_div::makeInstanceClassName('template'); $template = new $templateClass(); // oder Objekt direkt erstellen $template = t3lib_div::makeInstance('template');
Listing 8
Es ist offensichtlich, dass Extensions, die dieses Verfahren nicht konsequent anwenden, nur mühsam erweiterbar sind. Jede Stelle, die Objekte explizit erzeugt, müsste überschrieben werden, um die neue Funktion zu unterstützen.
Static calls
Externe statische Attributzugriffe beziehungsweise Methodenaufrufe einer Klasse sind nur unter Angabe des Klassennamens möglich. Da hier das selbe Dilemma entsteht wie bei der Erzeugung von Objekten unter Angabe des Klassennamens, sollten statische Aufrufe vermieden werden.
Falle OOP
Beim XCLASS-Verfahren wird mit Ableitungen gearbeitet. Das bedeutet, die Sichtbarkeitsdirektiven der objektorientierten Programmierung [3] greifen. Wurden Attribute oder Methoden als „private“ deklariert, ist die Erweiterbarkeit eingeschränkt. Attribute sind so nur noch über Getter- und Setter-Methoden zugänglich. Wurden diese Methoden in der Oberklasse jedoch nicht implementiert, so können sie der abgeleiteten Klasse auch nicht hinzugefügt werden, da diese keinen Zugriff auf die geschützten Attribute hat. Um abgeleiteten Klassen den Zugriff auf diese Attribute und Methoden zu gestatten, sollten diese besser als „protected“ deklariert werden.
Umfangreiche Methoden
Entwickler sollten davon absehen, Methoden mit mehreren hundert Zeilen Code zu erstellen. Eine Methode hat genau eine Aufgabe und sollte diese – als Faustregel – mit 50 bis 100 Zeilen Code bewältigen können, sonst gilt: Teile und herrsche. Dies ermöglicht nicht nur präziseres Ersetzen von Funktionalität über das XCLASS-Verfahren, es vereinfacht überdies auch das isolierte Testen einzelner Methoden.
Fazit
Die erfolgreichsten Extensions bieten umfangreiche Konfigurationsmöglichkeiten und machen es Entwicklern leicht, mit TypoScript, Hooks oder XCLASS benötigte Funktionalität zu ergänzen oder sogar zu ersetzen. Erweiterbarkeit ist nicht nur eine Sache des TYPO3-Kerns, Extensions stehen dieselben Möglichkeiten zur Verfügung. Eine solide Extension, die die Erweiterung „barrierefrei“ zulässt, ist im Endeffekt leistungsfähiger als ein nicht erweiterbarer vermeintlicher „Alleskönner“.