Dienstag, 20. Juni 2006
Serendipity XML/XSLT + PHP Engines
Dieses Wochenende hat mich Davey im Chat darauf angesprochen, dass ihn Smarty nervt und er für seine neues Blogdesign gerne darauf verzichten würde, auch wegen des Overheads.
Da bin ich prinzipiell geteilter Meinung: Smarty macht Templates schon um so vieles hübscher und wartbarer, dass ich den Overhead auch als erfahrener Programmierer in Kauf nehme. Wer es aber auf Omas Performancepfennige abgesehen hat und PHP selbst schon als Templatesprache empfindet, sieht das anders - und das kann ich auch verstehen.
Smarty hat zum Glück eine sehr, sehr einfache API. Alles was Smarty braucht ist letztlich die assign und display Methode. Ein paar weitere Convenience-Funktionen bedarf es schon, aber die lassen wir mal beiseite.
Mit dieser Tatsache als Ausgangsbasis habe ich dann in sehr kurzer Zeit eine PHP- und eine XML-Engine aus dem Boden gestampft, die Smarty komplett umgeht:
Da bin ich prinzipiell geteilter Meinung: Smarty macht Templates schon um so vieles hübscher und wartbarer, dass ich den Overhead auch als erfahrener Programmierer in Kauf nehme. Wer es aber auf Omas Performancepfennige abgesehen hat und PHP selbst schon als Templatesprache empfindet, sieht das anders - und das kann ich auch verstehen.
Smarty hat zum Glück eine sehr, sehr einfache API. Alles was Smarty braucht ist letztlich die assign und display Methode. Ein paar weitere Convenience-Funktionen bedarf es schon, aber die lassen wir mal beiseite.
Mit dieser Tatsache als Ausgangsbasis habe ich dann in sehr kurzer Zeit eine PHP- und eine XML-Engine aus dem Boden gestampft, die Smarty komplett umgeht:
Alles was dazu notwendig ist, ist ein "Smarty-Emulationslayer". Dieser stellt das $serendipity['smarty']-Objekt derart zur Verfügung, dass die nach aussen aufrufbaren Smarty-Methoden auch für andere Template-Engines aufgreifbar sind.
Für Serendipity endete das in einer extrem simplen, neuen "template_api.inc.php" Datei: SVN Repository.
Die Datei stellt eine Klasse zur Verfügung, die das eigene Serendipity-Frontend instanzieren muss, und dann in den PHP-Templates verwendet werden kann. Die bisherigen Smarty-Anweisungen im Serendipity-Code werden dabei weiterhin ausgeführt, und die Ausgabevariablen einfach in den globalen Namensraum in ein Array gepackt. Die normalen *.tpl Dateien von Serendipity können dann einfachen PHP Code ausführen. So etwas sieht dann so aus.
Und, ja - ich finde, das sieht ne ganze Menge hässlicher aus. Vorteil ist jedoch, dass die Wrapper-Funktionen wie z.B. Plugin-API Aufrufe nicht mehr durch das Smarty-Konstrukt gejagt werden müssen, sondern nativ ansprechbar sind.
Die andere Engine von der ich sprach, ist eine XML-Ausgabe. Die dafür notwendige Klasse befindet sich ebenfalls in genannter template_api.inc.php Datei, und ist noch viel simpler als die PHP-Ausgabe. Alle assign() Methodenaufrufe geben dort einfach die Variable direkt via echo an den Browser als rohes XML aus.
Das klingt erstmal nicht ganz so cool, aber die Möglichkeiten daraus sind recht interessant: Mittels (browserbasierter oder PHP-seitiger) XSLT Umformungen kann so die XML-Ausgabe in beliebige XHTML Ausgaben transformiert werden. Evtl. reicht sogar schon ein einfaches XSL-Stylesheet aus, um die XML Ausgabe zu verschönern. Richtig cool ist es dann, wenn man einen User-Agent-Aware XSLT-Transformer benutzt, der z.B. für Handys automatisch das XML anders formt als für den normalen Browser.
Soviel zu den Möglichkeiten -- denn praktisch habe ich mit XSLT noch nichts gemacht. Daher ist dieser Codeteil auch eher nur "Proof of Concept".
Das einzige, was ich bisher richtig unschön empfinde (und ab hier freue ich mich auf konkretes Feedback ) ist die assign()-Methode, die Smarty implementiert. Die sieht ungefähr so aus:
Wenn ich als nun im PHP-Space folgendes mache:
dann wird beim Funktionsaufruf für das große Array eine Kopie abgelegt. Hübscher wäre es daher, diese Variablen direkt als Referenz zu übergeben.
Leider bietet Smarty aber durch seine Methodendeklaration zwei Möglichkeiten der assign()-Methode:
Beide Aufrufe machen $array im Template verfügbar: Im einen Fall hat man später die Variable {$Ja} und {$Nein}, im zweiten Fall {$array.Ja} und {$array.Nein}.
Das Problem ist, dass wenn man den zweiten Parameter weglässt, der Default-Wert " = null" aus der Methodendeklaration genommen wird. Sobald man solche Default-Parameter setzt, kann man eine Variable dummerweise nicht als Referenz übergeben. Zumindest in allen PHP-Versionen, die ich kenne.
Die erste Variable wiederrum könnte man als Referenz übergeben, was aber halt in Variante B zu keiner Verbesserung führen würde.
Klassischer Fall also von "Bei der API nicht richtig nachgedacht". Denn es würde viel Zeit kosten, den ganzen Serendipity-Code auf Variante A umzuschreiben, zumal dann einige Arrays auch verändert werden müsste. Bei den zahlreichen Plugins ist das eigentlich fast unmöglich, zumal mir ja die Backwards-Compatibility immer sehr wichtig war und ist.
Schade, Schokolade.
Aber zurück zum Ausgangspunkt: Wer mit den neuen Änderungen im SVN trunk (1.1 alpha versionen) etwas spielt und Ergebnisse produziert, möge sich doch bitte melden. Und selbst wenn dieses Spaßexperiment keinen Nutzen hat: Es hat nur ne Stunde gedauert.
Für Serendipity endete das in einer extrem simplen, neuen "template_api.inc.php" Datei: SVN Repository.
Die Datei stellt eine Klasse zur Verfügung, die das eigene Serendipity-Frontend instanzieren muss, und dann in den PHP-Templates verwendet werden kann. Die bisherigen Smarty-Anweisungen im Serendipity-Code werden dabei weiterhin ausgeführt, und die Ausgabevariablen einfach in den globalen Namensraum in ein Array gepackt. Die normalen *.tpl Dateien von Serendipity können dann einfachen PHP Code ausführen. So etwas sieht dann so aus.
Und, ja - ich finde, das sieht ne ganze Menge hässlicher aus. Vorteil ist jedoch, dass die Wrapper-Funktionen wie z.B. Plugin-API Aufrufe nicht mehr durch das Smarty-Konstrukt gejagt werden müssen, sondern nativ ansprechbar sind.
Die andere Engine von der ich sprach, ist eine XML-Ausgabe. Die dafür notwendige Klasse befindet sich ebenfalls in genannter template_api.inc.php Datei, und ist noch viel simpler als die PHP-Ausgabe. Alle assign() Methodenaufrufe geben dort einfach die Variable direkt via echo an den Browser als rohes XML aus.
Das klingt erstmal nicht ganz so cool, aber die Möglichkeiten daraus sind recht interessant: Mittels (browserbasierter oder PHP-seitiger) XSLT Umformungen kann so die XML-Ausgabe in beliebige XHTML Ausgaben transformiert werden. Evtl. reicht sogar schon ein einfaches XSL-Stylesheet aus, um die XML Ausgabe zu verschönern. Richtig cool ist es dann, wenn man einen User-Agent-Aware XSLT-Transformer benutzt, der z.B. für Handys automatisch das XML anders formt als für den normalen Browser.
Soviel zu den Möglichkeiten -- denn praktisch habe ich mit XSLT noch nichts gemacht. Daher ist dieser Codeteil auch eher nur "Proof of Concept".
Das einzige, was ich bisher richtig unschön empfinde (und ab hier freue ich mich auf konkretes Feedback ) ist die assign()-Methode, die Smarty implementiert. Die sieht ungefähr so aus:
CODE:
function assign($tpl_var, $value = null) {
Wenn ich als nun im PHP-Space folgendes mache:
CODE:
$dickes_array = array(...);
$serendipity['smarty']->assign('dick', $dickes_array);
$serendipity['smarty']->assign('dick', $dickes_array);
dann wird beim Funktionsaufruf für das große Array eine Kopie abgelegt. Hübscher wäre es daher, diese Variablen direkt als Referenz zu übergeben.
Leider bietet Smarty aber durch seine Methodendeklaration zwei Möglichkeiten der assign()-Methode:
CODE:
$array = array('Ja' => 'Yes', 'Nein' => No');
$smarty->assign($array); // Variante A
$smarty->assign('array', $array); // Variante B
$smarty->assign($array); // Variante A
$smarty->assign('array', $array); // Variante B
Beide Aufrufe machen $array im Template verfügbar: Im einen Fall hat man später die Variable {$Ja} und {$Nein}, im zweiten Fall {$array.Ja} und {$array.Nein}.
Das Problem ist, dass wenn man den zweiten Parameter weglässt, der Default-Wert " = null" aus der Methodendeklaration genommen wird. Sobald man solche Default-Parameter setzt, kann man eine Variable dummerweise nicht als Referenz übergeben. Zumindest in allen PHP-Versionen, die ich kenne.
Die erste Variable wiederrum könnte man als Referenz übergeben, was aber halt in Variante B zu keiner Verbesserung führen würde.
Klassischer Fall also von "Bei der API nicht richtig nachgedacht". Denn es würde viel Zeit kosten, den ganzen Serendipity-Code auf Variante A umzuschreiben, zumal dann einige Arrays auch verändert werden müsste. Bei den zahlreichen Plugins ist das eigentlich fast unmöglich, zumal mir ja die Backwards-Compatibility immer sehr wichtig war und ist.
Schade, Schokolade.
Aber zurück zum Ausgangspunkt: Wer mit den neuen Änderungen im SVN trunk (1.1 alpha versionen) etwas spielt und Ergebnisse produziert, möge sich doch bitte melden. Und selbst wenn dieses Spaßexperiment keinen Nutzen hat: Es hat nur ne Stunde gedauert.
Trackbacks
Trackback-URL für diesen Eintrag
Kommentare
Ansicht der Kommentare:
(Linear | Verschachtelt)
Korrigier mich bitte: Mit der Methode assign_by_ref kann man doch das dicke_array als Referenz übergeben!?
Das stimmt, aber leider ist halt im Serendipity Code immer assign() genutzt worden und nicht assign_by_ref().
Das müsste man anscheinend mal ändern, denke ich - dürfte durchaus einiges bringen. Ist aber leider auch einiges an Arbeit.
Das müsste man anscheinend mal ändern, denke ich - dürfte durchaus einiges bringen. Ist aber leider auch einiges an Arbeit.