Ich versuche hier einen Einblick in die Mysterien von Hooks innerhalb von TYPO3 zu geben. Folgende Fragen will ich alle aufgreifen:
- 1. Was ist ein Hook?
- 2. Was kann ich damit machen?
- 3. Hook vs. XCLASS – was ist besser?
- 4. Welche Hooks werden schon jetzt auf meinem System verwendet?
- 5. Wie finde ich Hooks?
- 6. Wie kann ich einen Hook anwenden?
- 7. Wie kann ich einen Hook in meine Extension einbauen?
- 8. Gibt es weitere Dokumentationen zu Hooks?
Los gehts:
1. Was ist ein Hook?
In der Programmierung bezeichnet der Begriff Hook eine Schnittstelle, mit der fremder Programmcode in eine bestehende Anwendung integriert werden kann, um diese zu erweitern, deren Ablauf zu modifizieren oder um bestimmte Ereignisse abzufangen (soviel mal wieder von Wikipedia).
In vereinfachter und speziell auf TYPO3 ausgelegter Formulierung würde ich sagen, dass man einen Hook (im T3 Source oder in einer Extension) dazu verwenden kann, um eine vorhande Funktion abzuändern oder um eine weitere Funktion bei einer Aktion auszulösen; und das alles ohne den Code der Ausgangsfunktion zu ändern.
2. Was kann ich damit machen?
2.1. Was ich mit Hooks mache
Am häufigsten verwende ich Hooks, wenn ich eine Extension erweitern will. Eine gute und umfangreiche T3 Erweiterung bringt von Haus auf ein paar Hooks mit, damit man in einen Ablauf eingreifen kann (falls eine Extension eurer Meinung nach unbedingt noch einen neuen Hook braucht, wird der Autor sicher nicht nicht nein sagen, wenn ihr diesen mit ein wenig Code unterstützt und die Implementation gut begründet). Natürlich bietet auch der T3 Core eine Menge Hooks, die z.B. die FE Ausgabe beeinflussen können.
2.2. Konkrete Beispiele
- Ich will tt_news in der Singleansicht um einen neuen Marker erweitern, der mir irgendeinen Wert zur aktuellen News ausgibt (Beispiel).
- Ich will die Empfänger eines Powermail Formulares kurz vor dem Versand manipulieren (siehe wt_dynamictarget).
- Ich will den gerenderten HTML Quelltext von TYPO3 kurz vor der Ausgabe manipulieren (siehe spamshield).
- Ich will bei einer Bestellung in commerce einen weiteren Prozess anstoßen (Hooks in commerce).
3. Hook vs. XCLASS – was ist besser?
3.1. XCLASS
Vielleicht habt ihr euch schon mal gefragt, warum der Kickstarter am Ende jeder relevanten Datei so eine Zeile einfügt:
if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/wt_directory/pi1/class.tx_wtdirectory_pi1.php']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/wt_directory/pi1/class.tx_wtdirectory_pi1.php']); } |
Nahezu jede Extension- und auch viele Core- Dateien bieten die Möglichkeit über XCLASS nicht die eigentlichen Skripte auszuführen sondern alternative Skripte (Beispiel) – somit kann eine komplett andere Datei als die eigentlich vorbestimmte verwendet werden.
3.2. Hook
Während man also über die XCLASS ganze Dateien ersetzen kann, ist ein Hook „nur“ dazu gedacht, einen definierten Bereich zu manipulieren – Beispiel:
$content = 'ergebnis'; if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['hook'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][$this->extKey]['hook'] as $_classRef) { $_procObj = &t3lib_div::getUserObj($_classRef); $_procObj->functionName($content); } } return $content; |
3.3. Was ist besser und warum?
Es liegt auf der Hand, warum die Verwendung eines Hooks zu bevorzugen ist:
Bei Updates der Ausgangsextension ist die Ablaufänderung weiterhin möglich (sofern der Autor nicht den Hook entfernt oder abändert) und Änderung können einfließen, während bei der Benutzung der XCLASS ein Update an der Ausgangsdatei keine Wirkung zeigt (die Datei wird ja nicht mehr verwendet). Desweiteren kann man einen Hook öfters und parallel nutzen (wenn richtig eingerichtet), während die XCLASS nur max. einmal verwendet werden kann.
4. Welche Hooks werden schon jetzt auf meinem System verwendet?
Vermutlich werden bereits jetzt schon einige Hooks auf deinem System verwendet. Hier hilft ein Blick in die Konfiguration (linkes Menü: Punkt „Konfiguration“, dann $TYPO3_CONF_VARS, dann z.B. Baum EXTCONF aufklappen):
5. Wie finde ich Hooks?
Einige Erweiterungen dokumentieren die verwendeten Hooks im Manual oder bringen eine eigene XLS Datei mit. Bei einigen bringt wohl auch nur der Blick in den Code wirklich etwas. Ähnlich verhält es sich derzeit mit den Hooks im T3 Sourcecode.
Eine ganz neuer Ansatz wie man Hooks auf die Spur kommt, beschreibt Tim in seinem Beitrag vom Juli 2007.
6. Wie kann ich einen Hook anwenden?
6.1. Info
Wenn du also einen Hook gefunden hast, den du in einer Erweiterung selbst aufgreifen willst, dann geht der Weg meist über die ext_localconf.php. Dort machst du die Zuweisung zu einer eigenen Klasse oder Funktion (Beispiel unten)
6.2. Beispiel – Vorgegebener Hook
6.2.1. Code
$content = 10; if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extensionkey']['hook'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extensionkey']['hook'] as $_classRef) { $_procObj = &t3lib_div::getUserObj($_classRef); $_procObj->main($content, $this); } } return $content; |
Erklärung: Ausgeschrieben würden diese Zeilen wohl folgendes tun: Falls der Hook $GLOBALS[‚TYPO3_CONF_VARS‘][‚EXTCONF‘][‚extensionkey‘][‚hook‘] gesetzt ist, wird eine Schleife geöffnet, die jeden Hook (kann ja schließlich mehrfach verwendet werden) durchgeht. Zuerst wird eine Referenz zu dem von dir gesetzten Objekt erstellt, danach wird die Funktion „main“ mit 2 Parametern aufgerufen.
Falls unberührt vom Hook würde einfach nur die Variable $content (mit Inhalt „10“) aus- bzw. zurückgegeben werden.
6.2.2. ext_localconf.php
Ein Aufruf in der ext_localconf.php kann so aussehen:
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extensionkey']['hook'][] = 'EXT:extension/class.ext_hook.php:ext_hook'; |
Erklärung: Hier wird die Zieldatei und Klasse gesetzt (in unserem Beispiel also – Datei: class.ext_hook.php, Klasse: ext_hook)
6.2.3. Datei class.ext_hook.php
Beispielinhalt:
class ext_hook { function main(&$content, $obj) { $content += 1; // erhöhe $content um 1 } } |
Da die Funktion mit Namen main in unserem Beispiel vorgegeben ist, wird diese aufgerufen und dieser werden 2 Paramter übergeben. In unserem Beispiel erhöhen wir $content um den wert 1.
Durch die Verwendung der Referenz &$content beim Funktionsaufruf wird somit auch $content in der ursprünglichen Datei um 1 erhöht.
7. Wie kann ich einen Hook in meine Extension einbauen?
7.1. Alternatives Beispiel
Vermutlich dient Punkt 6 schon dem Verständnis, wie man einen Hook integrieren kann.
Als alternatives Beispiel kann man einen Hook auch so integrieren, ohne dass der Funktionsname fest vorgegeben wird:
if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extName']['hook']) { foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extName']['hook'] as $_funcRef) { if ($_funcRef) { t3lib_div::callUserFunction($_funcRef, $content, $this); } } } |
Beispielintegration in eurer ext_localconf.php:
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extName']['hook'][] = 'EXT:extension/class.tx_ext.php:tx_ext->start'; |
Beispieldatei:
class tx_ext { function start(&$content, $obj) { $content = 'neuer Wert'; } } |
7.2. By the way
– Übergabe von $this: In meinen Beispielen wird beim Methodenaufruf in den Hooks immer $this übergeben. Der Sinn darin besteht, dass man nahezu jedes zuvor definierte Objekt oder Methode mit $this->bla aufrufen und ändern kann. Also beim Extension Entwickeln lieber $this->content statt $content verwenden (wenn möglich und sinnvoll)
– Hooks sollten immer so angelegt werden, dass diese öfters verwendet werden können (siehe Beispiele oben). Man weiß nie wieviele Erweiterungen gleichzeitig einen Hook nutzen
– Macht euch Gedanken wo in eurer Extension ein Hook Sinn macht. Was könnte also jemand anderes beeinflussen wollen? Macht ein Hook überhaupt Sinn?
8. Gibt es weitere Dokumentationen zu Hooks?
Puh, hoffentlich habe ich nicht zu viel (Mist) geschrieben – ist ja auch ein trockenes Thema. Habe ich etwas wichtiges vergessen? Freue mich auf Feedback!
Grüße, Alex