«

»

Dez
06

TYPO3 4.5 um stdWrap.replacement erweitern

Hamburg, den 5.12.2011:

Hin und wieder stößt man in seinem Job auf Probleme, welche durch die aktuellste Version eines genutzten Systems nicht existent wären.
Wer kennt es nicht – der Kunde hat ein Problem, welches man ja ganz schnell und einfach lösen kann. Ja wenn, ja wenn da nur nicht das kleine Problem wäre das es dieses Feature, welches ich dazu benötige,  in dieser Version noch nicht verfügbar ist.

Ich glaube die FLOW3 Pioniere können davon ein Lied singen. Sie entwickeln irgendwie etwas super tolles und müssen dann wohl oder übel wieder einmal in den Alltag zurückkehren und müssen dann mit Extbase vorlieb nehmen. Und siehe da alle tollen Dinge, die sie kennen gehen nicht mehr.

Aber zurück zu meinem Problem. Der Kunde nutzte auf Grund des Long Term Supports TYPO3 4.5 und hatte nun den Wunsch das seine Seitentitel etwas von dem im Backend eingegeben Seitentitel abweichen. Natürlich wurden diese in der Navigation auch genutzt und man konnte nicht einfach sagen: “Ja OK, dann bennen wir sie eben um!”

Es blieben mir also mehrere Möglichkeiten um das Problem zu lösen.

  • Man könnte für den Seitentitel ein anderes Feld nutzen. Zum Beispiel den Subtitle. Was aber auch mehr Aufwand für die Redakteure bedeutet und vor allem muss man den Redakteuren dieses Problem dann auch erklären.
  • Ich könnte eine userFunc erstellen und mit eben dieser das Problem lösen.
  • Oder und das ist die in meinen Augen schönste Lösung ich schaue einmal was mir TYPO3 noch an zusätzlichen Mitteln bietet. Natürlich bin ich auch fündig geworden. Nur leider kann man stdWrap.replacement erst ab TYPO3 4.6 nutzen. Die in meinen Augen schönste Lösung war also ich brauche diese replacement Funktion :)

Doch wie stellt man das nun an. Ich könnte nun eine userFunc erstellen und einfach die Funktionen aus TYPO3 4.6 dann dafür nutzen. Doch ich finde ein Integrator sollte es so einfach wie möglich haben. Und da die Integratoren auch mit TYPO3 4.6 arbeiten kennen sie die stdWrap Funktion ja eh besser als ich (Entwickler).

In diesem Sinne sollen sie diese Funktion einfach nutzen als ob sie von TYPO3 kommt. Nur eben in TYPO3 4.5! Seit TYPO3 4.2 ist es möglich den stdWrap mit 4 Hooks zu erweitern.

stdWrapPreProcess
Dieser stdWrap Hook wird vor jeder anderen stdWrap funktion aufgerufen. Also auch vor jeder Funktion, die Daten holt wie field, data etc. Achtung! wird vor override aufgerufen.
stdWrapOverride
Wird direkt nach preUserFunc aufgerufen. Zu diesem ist das holen der Daten abgeschlossen, diese wurden jedoch noch nicht überprüft (ifEmpty etc) oder verarbeitet (wrap etc.).
stdWrapProcess
Wird nach der ersten Überprüfung und Vorverarbeitung der Daten (ifEmpty, trim, listNum) und direkt nach dem rekursiven Aufruf von stdWrap aufgerufen.
stdWrapPostProcess
Wird nach jeder anderen stdWrap Funktion außer der Debugausgabe aufgerufen. Auch nach prefixComment, editIcons etc!

(Quelle: TYPO3 Wiki )

Dann möchte ich euch einmal zeigen wie ihr diese Hooks nutzen könnt und somit dann auch die Änderungen aus 4.6 in Version 4.5 zur Verfügung habt.

Schritt 1:

Ihr wählt eine Extension aus in der ihr den Hook anmelden möchtet. Ich habe eine Extension namens tmpl_base. In dieser Extension befindet sich sämtliches TypoScript, CSS, JS und vieles mehr. Also eigentlich alles was das Frontend betrifft findet man in dieser Extension.

Hier habe ich nun einen Ordner classes angelegt und in diesem Ordner habe ich wiederum einen Ordner hooks angelegt. In diesem Ordner werden nun sämtliche Klassen abgelegt, die einen Hook implementieren.

Meine erstellte Datei heisst nun:

class_tx_tmplbase_stdwrap_extend.php

Schritt 2:

Öffnet nun die Datei und fügt erst einmal folgenden Code ein.

<?php
require_once(PATH_typo3.'/sysext/cms/tslib/interfaces/interface.tslib_content_stdwraphook.php');
 
class tx_tmplbase_stdwrap_extend implements tslib_content_stdWrapHook {
	function stdWrapPreProcess($content, array $configuration, tslib_cObj &amp;$parentObject) {
		return $content;
	}
 
	function stdWrapOverride($content, array $configuration, tslib_cObj &amp;$parentObject) {
		return $content;
	}
 
	function stdWrapProcess($content, array $conf, tslib_cObj &amp;$parentObject) {
		return $content;
	}
 
	function stdWrapPostProcess($content, array $configuration, tslib_cObj &amp;$parentObject) {
		return $content;
	}
 
	public function processReplacement($content, array $configuration) {
		return $content;
	}
}
if (defined('TYPO3_MODE') &amp;&amp; $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/tmpl_base/classes/hooks/class.tx_tmplbase_stdwrap_extend.php'])	{
	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/tmpl_base/classes/hooks/class.tx_tmplbase_stdwrap_extend.php']);
}
?>

Nun habt ihr Ein Grundgerüst das auf tslib_content_stdWrapHook basiert. Zur Zeit wird in diesem Hook noch rein gar nichts gemacht. Er wird noch nicht einmal gerufen. Damit wir den Hook nutzen können müssen wir ihn anmelden.

Schritt 3:

Wie schon in Schritt 2 erwähnt, um einen Hook nutzen zu können müssen wir ihn anmelden. Dafür müssen wir folgende Dinge tun:

  1. Erstellen der Datei ext_autoload.php und die Hook Klasse eintragen.
  2. Erstellen von ext_localconf.php und den Hook anmelden.

Unter Umständen gibt es diese Dateien schon. Das ist nicht weiter tragisch. In diesem Fall fügt ihr einfach das Hook spezifische hinzu.

Zu 1.

Wir öffnen die ext_autoload.php und fügen folgenden Code hinzu:

$extensionPath = t3lib_extMgm::extPath('tmpl_base');
return array(
	'tx_tmplbase_stdwrap_extend' =&gt; $extensionPath . 'classes/hooks/class_tx_tmplbase_stdwrap_extend.php'
);

Bitte die Pfade gemäß eurer Extension anpassen und lieber mehrmals prüfen. Wenn man sich sicher ist einfach die Datei speichern und schon sind wir mit der ext_autoload.php fertig.

Zu 2.

Wir öffnen die ext_localconf.php und fügen folgenden Code hinzu:

if (!defined ("TYPO3_MODE")) die ("Access denied.");
 
$TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap'][] = 'EXT:tmpl_base/classes/hooks/class_tx_tmplbase_stdwrap_extend.php:&amp;tx_tmplbase_stdwrap_extend';

Wie schon bei der ext_autoload.php gilt auch hier – unbedingt die Pfade prüfen bevor wir die Datei speichern und schliessen. Nun haben wir den Hook durch den Autoloader geladen und durch die localconf.php bei TYPO3 angemeldet. Das bedeutet nun kann es mit dem Hook an sich los gehen.

Schritt 4:

Dann wollen wir dem Hook einmal die gewünschte Funktion spendieren. In meinem Anwendungsfall habe ich mich für die stdWrapProcess Funktion des Hooks entschieden. Warum ich diesen genutzt habe könnt ihr weiter oben oder im TYPO3 Wiki nachlesen. Das gute ist das wir die replacement Funktion nicht selbst implementieren müssen. Wir wissen das es dieses Feature ab TYPO3 4.6 gibt. Das bedeutet wir begeben uns auf Forge und suchen uns den passenden Patch. Alles was wir benötigen könnt ihr im Issue unter Forge nachlesen und vor allem finden wir auch unseren Patch, welcher sämtlichen benötigten Code enthält, um das Feature in TYPO3 4.5 zum laufen zu bringen.

Zurück in unserem Hook ändern wir die stdWrapProcess Funktion wie folgt ab:

function stdWrapProcess($content, array $conf, tslib_cObj &amp;$parentObject) {
		// in TYPO3 version 4.6 this is not necessary anymore because the stdWrap has
		// a replacement function out of the box
	if (isset($conf['replacement.'])) {
		$content = $this-&gt;processReplacement($content, $conf['replacement.']);
	}
	return $content;
}

Wie wir sehen wird nun in unserem Hook die Funktion processReplacement gerufen. Diese können wir aus dem Patch kopieren und fügen noch den folgenden Code in unserem Hook ein.

/**
* Processes ordered replacements on content data.
*
* @param	string		$content: The content to be processed
* @param	array		$configuration: The TypoScript configuration for stdWrap.replacement
* @return	string		The processed content data
*/
public function processReplacement($content, array $configuration) {
	// Sorts actions in configuration:
	ksort($configuration);
 
	foreach ($configuration as $index =&gt; $action) {
			// Checks whether we have an valid action and a numeric key ending with a dot ("10."):
		if (is_array($action) &amp;&amp; substr($index, -1) === '.' &amp;&amp; t3lib_div::testInt(substr($index, 0, -1))) {
			$content = $this-&gt;processReplacementAction($content, $action);
		}
	}
 
	return $content;
}
 
/**
 * Processes a single search/replace on content data.
 *
 * @param	string		$content: The content to be processed
 * @param	array		$configuration: The TypoScript of the search/replace action to be processed
 * @return	string		The processed content data
 */
protected function processReplacementAction($content, array $configuration) {
	if ((isset($configuration['search']) || isset($configuration['search.']))
	&amp;&amp; (isset($configuration['replace']) || isset($configuration['replace.']))) {
 
		// Gets the search needle:
		$search = tslib_cObj::stdWrap($configuration['search'], $configuration['search.']);
		// Determines whether regular expression shall be used:
		if (isset($configuration['useRegExp']) || $configuration['useRegExp.']) {
			$useRegularExpression = tslib_cObj::stdWrap($configuration['useRegExp'], $configuration['useRegExp.']);
		}
		// Performs a replacement by preg_replace():
		if ($useRegularExpression) {
			$replace = tslib_cObj::stdWrap($configuration['replace'], $configuration['replace.']);
			$content = preg_replace($search, $replace, $content);
			// Checks whether the search needle is part of the content:
		} elseif (strpos($content, $search) !== false) {
			$replace = tslib_cObj::stdWrap($configuration['replace'], $configuration['replace.']);
			$content = str_replace($search, $replace, $content);
		}
	}
	return $content;
}

Wie man schnell sieht muss im Code des Patches $this->stdWrap() angepasst werden. Denn wir können über $this nicht auf die Funktion stdWrap zugreifen. An Stelle von $this->stdWrap greifen wir nun einfach mit tslib_cObj::stdWrap() auf die Funktion zu.

Grundsätzlich sollte es das auch gewesen sein. Nun kann man immer wenn man den stdWrap nutzen kann auch die Funktion replacement benutzen.
Das bedeutet wir können nun folgendes TypoScript benutzen:

10 = TEXT
10 {
	value = Te___st
	replacement {
		10 {
			search = _
			replace.char = 32
		}
	}
}

Und als Ausgabe erhalten wir dank unseres Hooks und des Patches für TYPO3 4.6 nicht Te___st sondern Test.

Falls ich etwas nicht zu 100% richtig beschrieben habt weist mich ruhig darauf hin. Ich bin noch Azubi und keiner ist perfekt. In diesem Sinne viel Spaß beim nachbauen des stdWrap Hooks.

Hinterlasse eine Antwort

Ihre E-Mail-Adresse wir nicht veröffentlicht

Sie können diese HTML-Tags verwenden: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">