am 11. November 2008
Manchmal geschieht es, dass Träume war werden. Ein alter Traum im World-Wide-Web ist es die Dreieinigkeit von Inhalt, Logik und Layout zu trennen und immer wieder werden Technologien vorgeschlagen die diesen Traum verwirklichen sollen. Eine besonders erfolgreiche Technologie sind Cascading Style Sheets, die es weitestgehend ermöglichen die semantischen Inhalte von der bildhaften Gestaltung einer Web-Seite zu trennen. Die CSS-Designer-Web-Seite mag hier als Beispiel dienen wie unterschiedlich der selbe HTML-Code allein durch das Austauschen der CSS-Dateien dargestellt werden kann. In wie weit sich die hier präsentierten Schmuckstücke auf reale Problem anwenden lassen sei einmal dahin gestellt. Fakt ist, CSS hat dem Wahnsinn der verschachtelten Tabellen-Layouts ein Ende bereitet und das Arbeitsleben eine HTMLers um einiges komfortabler gestaltet.
Mit dieser Technik ist man dem Traum Logik, Inhalt und Layout zu trennen ein großes Stück weiter gekommen. Dennoch muss immer noch das zugrunde liegende HTML – welches von CSS in Form gebracht wird – irgendwo herkommen. Bei vielen dynamischen Webseiten wird es bei Bedarf mittels eines PHP-Skriptes generiert. Doch anstatt einfach “echo” für die Ausgabe zu verwenden, kann hier eine weitere Technologie eingesetzt werden, die einem dabei hilft Logik, Layout und Inhalt getrennt zu halten. Die Rede ist hier von Template-Engines. Das ist natürlich auch nichts neues und auch die Engine, die ich vorstellen möchte ist schon recht alt. Allerdings hat sich gezeigt, dass trotz dem Hype, der um XSLT als Traum, der in Erfüllung geht gemacht wurde, Template-Engines nach wie vor ihre Berechtigung haben.
Vor allem dann, wenn es sich um die beste aller Template-Engines: patTemplate handelt! (Was wäre ich für ein mieser Autor, wenn ich nicht von dem was ich schreibe überzeugt wäre.) Von weitem betrachtet funktioniert patTemplate wie alle anderen Template-Engines: Der Rahmen des Zieldokumentes (meist HTML) wird als Template angelegt. Dieses enthält dann Dokumentfragmente (HTML-Schnipsel), Platzhalter und beliebig viele Untertemplates, die wiederum Fragmente, Platzhalter und Untertemplates enthalten können. Kontrolliert wird das alles von einem PHP-Skript, welches konkrete Inhalte an die Template-Engine (patTemplate) übergibt, die damit ihrerseits die Platzhalter mit Leben füllen kann.
<patTemplate:tmpl name="itinerary">
<!-- Template mit XML Tags -->
<p>
Nächster Halt <strong><patTemplate:var name="stop" /></strong>
um <patTemplate:var name="eta" />
(Verspätung <patTemplate:var name="delay" /> min).
</p>
</patTemplate:tmpl>
<patTemplate:tmpl name="itinerary_next">
<!-- Die Kurzform der Platzhalter gestaltet Templats lesbarer -->
<p>
Nächster Halt <strong>{STOP}</strong> um {ETA}
(Verspätung {DALAY} min).
</p>
</patTemplate:tmpl>
<?php
$tmpl = new patTemplate();
$tmpl->setRoot('template');
$tmpl->readTeamplatesFromInput('itinerary_next.tmpl');
$tmpl->addVar('itinerary_next', 'stop', 'Fulda');
$tmpl->addVar('itinerary_next', 'eta', '2008-11-02 21:52:00');
$tmpl->addVar('itinerary_next', 'delay', '7');
$tmpl->displayParsedTemplate();
?>
Die Template-Dateien selbst verwenden XML-Tags um Untertemplates, Platzhalter und Template-Funktionen auszuzeichnen. Auf diese Weise fügen sie sich nahtlos in HTML-Dokumente ein und machen das Erlernen von patTemplate-Tags für den geübten HTMLer zum Kinderspiel. Natürlich enthalten die Templates keinerlei Programmcode. Die gesamte Logik welche Inhalte dargestellt werden sollen ist in der PHP-Datei enthalten. Dennoch hat der HTMLer die Möglichkeit Logik in die Templates zu packen. Dies geschieht mit “condition”-Templates. Somit ist es dem HTMLer möglich die Darstellungslogik zu verändern, ohne dem PHPler in die Quere zu kommen – also ohne, dass Änderungen im PHP-Code notwendig wären.
<patTemplate:tmpl name="itinerary">
<!-- Die Kurzform der Platzhalter gestaltet Templats lesbarer -->
<p>
Nächster Halt <strong>{STOP}</strong> um {ETA}
<patTemplate:tmpl type="condition" conditionvar="delay" varscope="__parent">
<patTemplate:sub condition="0">
<!-- keine Verspätung -->
</patTemplate:sub>
<patTemplate:sub condition="__default">
(Verspätung {DALAY} min)
</patTemplate:sub>
</patTemplate:tmpl>
</p>
</patTemplate:tmpl>
Zu den weiteren Grundelementen eines jeden Template-Systems sind wiederholbare Blöcke. Bei patTemplate werden dazu einfach Untertemplates verwendet, die so oft wiederholt werden, wie Datensätze vorhanden sind. Damit lassen sich ganz leicht Templates für Listen und Tabellen erstellen. Auch der PHPler muss im Grunde nichts neues Lernen, alles was er tun muss, ist diese Liste an patTemplate zu übergeben.
<?php
$tmpl = new patTemplate();
$tmpl->readTemplatesFromInput('itinerary_list');
$base = array(
'start' => 'Frankfurt (Main) Hbf',
'des' => 'Dresden Hbf',
'train' => 'ICE'
'no' => '1545'
);
$tmpl->addVars('reiseplan', $base);
$list = array();
$list[] = array(
'stop' => 'Frankfurt'
'eta' => '2008-10-29 17:20:00'
);
$list[] = array(
'stop' => 'Fulda'
'eta' => '2008-10-29 18:11:00'
);
$list[] = array(
'stop' => 'Eisenach
'eta' => '2008-10-29 18:59:00'
);
$list[] = array(
'stop' => 'Erefurt
'eta' => '2008-10-29 19:32:00'
);
$tmpl->addVar('list', $list);
$tmpl->displayParsedTemplate();
?>
<patTemplate:tmpl name="itinerary">
<ol>
<patTemplate:tmpl>
<li>
<strong>{STOP}</strong> {ETA}
</li<
</patTemplate:tmpl>
</ol>
</patTemplate:tmpl>
Damit geht der Traum von der Trennung von Darstellung und Inhalt schon ein Stück weit in Erfüllung und kombiniert man dieses Werkzeug mit CSS kommt man schon sehr weit. Vorallem aber bleibt so der PHP- und HTML-Code sauber getrennt, was eine Voraussetzung für die Wartbarkeit ist.
Die bis hier gezeigten Features beherrschen eigentlich allesTemplate-Engines – die meisten können noch viel mehr. PatTemplate natürlich auch. Um aber nicht den Rahmen zu sprengen und niemanden ins Land der Träume zu schicken möchte ich an dieser Stelle auf die umfangreichen Beispiele [1] verweisen.
Ein mächtiges Feature möchte ich aber noch kurz vorstellen:
Variablen-Modifier. In den bisher gezeigten Beispielen wurde die Ankunftszeit der Züge in dem Format ausgegeben wie es z.B. in der Datenbank gespeichert wird. Das ist für den Programmierer (PHPler) praktisch, aber für den Anwender wäre es besser die Uhrzeit in einem gängigeren Format auszugeben.
Diese Anpassung ließe sich natürlich mit einem simplen Funktionsaufruf im PHP-Code bewerkstelligen, aber eigentlich handelt es doch um ein Problem der Darstellung und gehört ins Template. Ist damit der Traum von der Trennung von Code und Layout zerstört?
Abhilfe für dieses Problem schafft der Variablen-Modifier Dateformat. Dieser ist in der Lage einen Zeitstempel wie gewünscht zu formatieren. Das gewünschte Format wird einfach als Attribute des XML-Tags übergeben. Natürlich ist der Modifier nichts weiter als eine Klasse, die ihrerseits die normalen PHP-Funktionen verwendet um die Uhrzeit zu formatieren. Der Vorteil besteht darin, dass der Funktionsaufruf aus dem Template heraus erfolgt. Schließlich ist das Format der Uhrzeit eine Sache der Darstellung und hat nichts mit der eigentlichen Programmlogik zu tun.
<patTemplate:tmpl name="itinerary">
<ol>
<patTemplate:tmpl>
<li>
<strong>{STOP}</strong>
<patTemplate:var name="eta" modifier="dateformat" format="%h:%m" />
</li<
</patTemplate:tmpl>
</ol>
</patTemplate:tmpl>
Weitere Beispiele für Modifier die bereits mit patTemplate mitgeliefert werden sind Truncate (zum Abschneiden von Texten), Wordwrap (fügt Zeilenumbrüche ein) oder Numberformat (formatiert Zahlen). Werden spezielle Modifier benötigt, muss lediglich eine Klasse implementiert werden die von patTemplate_Modifier abgeleitet ist. Außerdem muss patTemplate mitgeteilt werden in welchem Verzeichnis die speziellen Modifier zu finden sind.
Auf diese Weise kann patTemplate Variablen-Modifier aus beliebig vielen Verzeichnissen automatisch bei Bedarf nachladen. Übrigens ist es mit dem gleichen Mechanismus möglich alle patTemplate Module (wie InputFilter oder TemplateReader) zu erweitern oder zu ersetzen.
Obwohl bestimmt noch einige Fragen offen bleiben und Template-Engines nicht der Weisheit letzter Schluss sind, geht der Traum von der Trennung von Inhalt, Layout und Logik zumindest teilweise in Erfüllung. Außerdem wir durch den Einsatz einer Template-Engine, insbesondere patTemplate viel leichter die die Programmlogik modular zu halten. Zumindest aber geht Nils Traum in Erfüllung: er hat nämlich einen Artikel über patTemplate für sein Blog bekommen.
[0] PHP-Application-Tools Homepage
[1] patTemplate Beispiele
[2] Daily snapshots
[3] patTemplate Trac