Flexi-Templates

Bis die Doku vervollständigt worden ist (Freiwillige vor..), hier die Folien vom letzten Vortrag: Attach:flexi.pdf

S5 Folien: http://mainland.virtuos.uos.de/projects/studip/browser/personal/mlunzena/entwicklerweiterbildung/flexi_templates/flexi_templates.xml?rev=5265&format=raw

Beispiel 1: "Hello World"

Wie es sich gehört, kommt als erstes Beispiel das bekannte "Hello world". Dafür brauchen wir zwei Sachen:

  • eine Template-Datei, die wie ein Lückentext funktioniert,
  • ein PHP-Skript, das diesen Lückentext füllt und ausgibt.

Die Template-Datei liegt aus Hygienegründen in einem eigenen Verzeichnis templates. Damit sieht dann das Beispiel so aus:

  index.php
  templates/hello_world.php

Der Lückentext ist in der Datei templates/hello_world.php gespeichert. Die Flexi_Template-Engine benutzt die Endung einer Template-Datei, um die Art dieser zu erkennen. Eine Endung ".php" weißt dabei auf ein Flexi_PhpTemplate hin. Diese Art von Template ist einfach ein plain vanilla PHP-Skript. Wie sieht also unser Template aus?

  1. <h1>Hello, <?= $name ?>!</h1>

Offenbar wird der Platzhalter $name verwendet, um den Namen des Gegrüßten anzuzeigen.

Wie füllt man also dann diesen Lückentext? Schauen wir uns doch die Datei index.php an:

  1. <?php
  2.  
  3. # load flexi lib
  4. require_once dirname(__FILE__) . '/../../vendor/flexi/flexi.php';
  5.  
  6. # where are the templates
  7. $path_to_the_templates = dirname(__FILE__) . '/templates';
  8.  
  9. # we need a template factory
  10. $factory = new Flexi_TemplateFactory($path_to_the_templates);
  11.  
  12. # open template
  13. $template = $factory->open('hello_world');
  14.  
  15. # set name of the greetee
  16. $template->set_attribute('name', 'Axel');
  17.  
  18. # render template
  19. echo $template->render();

Zunächst wird offenbar die Flexi-Bibliothek geladen, daraufhin eine Variable mit dem Pfad zum Verzeichnis, wo unser Template liegt, gefüllt und dann mit dieser eine Flexi_TemplateFactory erzeugt.

Wie der Name schon andeutet, wird diese factory dazu benutzt, Templates herzustellen. Und genau das passiert als nächstes. Indem man der factory die Nachricht #open schickt, erhält man ein Template-Objekt. Dazu muss man als Argument nur den Namen der Template-Datei mitgeben. Da die factory ein wenig schlau ist, reicht ihr dabei der Name der Datei ohne Endung (die man aber natürlich auch mitangeben dürfte; man muss es eben nur nicht..). Für unser Template hello_world.php genügt also ein "hello_world".

Die Verwendung des Namens ohne Endung erlaubt ein Feature, auf das wir später noch einmal eingehen werden.

Zurück zum Thema: In einem weiteren Schritt setzen wir für das Template das Attribut "name" auf den Wert "Axel". Und zum Schluss lassen wir das Template auswerten und geben das Ergebnis (einen String) aus.

Wenig überraschend erhält man nach Ausführung im Browser:

Beispiel 2: "Darf's ein bisschen mehr sein?"

Eben haben wir gerade eine "Lücke" mit einem String gefüllt. Als nächstes probieren wir das mal mit anderen Sachen als Strings.

Schauen wir uns als erstes einmal das PHP-Skript an, das unser Template füllen wird.

  1. <?php
  2.  
  3. # load flexi lib
  4. require_once dirname(__FILE__) . '/../../vendor/flexi/flexi.php';
  5.  
  6. # where are the templates
  7. $path_to_the_templates = dirname(__FILE__) . '/templates';
  8.  
  9. # we need a template factory
  10. $factory = new Flexi_TemplateFactory($path_to_the_templates);
  11.  
  12. # open template
  13. $template = $factory->open('quotes');
  14.  
  15.  
  16. # set quotes
  17. $quotes = array(
  18.   array('author' => 'August Strindberg',
  19.         'quote'  => 'Der Mensch ist ein wunderliches Tier.'),
  20.   array('author' => 'Pierre Reverdy',
  21.         'quote'  => 'Der Mensch ist ein Tier, das sich selbst gezähmt hat.'),
  22.   array('author' => 'Thomas Niederreuther',
  23.         'quote'  => 'Der Mensch ist das einzige Tier, das sich für einen Menschen hält.'),
  24.   array('author' => 'Durs Grünbein',
  25.         'quote'  => 'Der Mensch ist das Tier, das Kaugummi kaut.'),
  26.   array('author' => 'Mark Twain',
  27.         'quote'  => 'Der Mensch ist das einzige Tier, das erröten kann - oder sollte.'));
  28.  
  29. # select one randomly
  30. shuffle($quotes);
  31. $quote_of_the_day = array_shift($quotes);
  32.  
  33. $template->set_attributes(array('quotes'           => $quotes,
  34.                                 'quote_of_the_day' => $quote_of_the_day));
  35.  
  36.  
  37. # set current time
  38. $time = time();
  39. $template->set_attribute('time', $time);
  40.  
  41.  
  42. # render template
  43. echo $template->render();

Hier erwartet uns nichts besonderes. Die Zeilen 1-13 sind dieselben, die wir schon im ersten Beispiel hatten. Die Flexi-Bibliothek wird geladen, der Pfad zu den Templates wird gesetzt und mit ihm eine Template-Factory erzeugt, die wir dann verwenden, um das Template namens "quotes" zu öffnen.

Danach (Zeilen 16-27) wird ein Vektor von Zitaten angelegt, um dann in den Zeilen 29-31 diesen Vektor zu mischen und den ersten zum Zitat des Tages zu kören.

Interessanter wird es dann in Zeile 33. Dort senden wir an unser Template eine neue Nachricht #set_attributes. Anstatt also zweimal hintereinander #set_attribute aufzurufen, was so aussehen würde:

  1. template->set_attribute('quotes',           $quotes);
  2. template->set_attribute('quote_of_the_day', $quote_of_the_day);

setzen wir stattdessen direkt ein Array von Schlüssel-Wert-Paaren.

Die Zeilen 37-39 demonstrieren, dass man hinterher gerne weitere Attribute wie gewohnt setzen kann. Auch andersherum wäre das kein Problem gewesen (also zunächst #set_attribute und dann #set_attributes). Die Nachricht #set_attributes überschreibt nämlich nur, löscht also nicht alle vorher eingetragenen Attribute.

Die Zeilen 42-43 sollten einem dann wieder bekannt vorkommen. Wir evaluieren die Attribute im Kontext der Template-Datei und geben diese aus.

Die Template-Datei ist wieder ein Flexi_PhpTemplate also ein gewöhnliches PHP-Skript. Diesmal haben wir aber eine kleine Überraschung eingebaut. Es soll nämlich ein bisschen Ausgabelogik demonstriert werden:

  1. <h1>Zitat des Tages (<?= date('d.m.Y', $time) ?>)</h1>
  2. <p>
  3.   <em>
  4.     &#8222;<?= $quote_of_the_day['quote'] ?>&#8220;
  5.   </em>
  6.   (<?= $quote_of_the_day['author'] ?>)
  7. </p>
  8.  
  9.  
  10. <? if (sizeof($quotes)) : ?>
  11.   <h1>Mehr Zitate</h1>
  12.   <? foreach ($quotes as $quote) : ?>
  13.     <p>
  14.       <em>
  15.         &#8222;<?= $quote['quote'] ?>&#8220;
  16.       </em>
  17.       (<?= $quote['author'] ?>)
  18.     </p>
  19.   <? endforeach ?>
  20. <? endif ?>

Interessant sind hier wohl die Aufrufe von Ausgabefunktionen wie #date in Zeile 1, die Verwendung eines if-Konstrukts in Zeile 10 (und natürlich dessen Ende in Zeile 20) und die Verwendung von foreach in Zeile 12 (und 19).

Wenn man also von der Verwendung der alternativen Syntax für if und foreach (http://de.php.net/manual/en/control-structures.alternative-syntax.php) absieht, sollte der Inhalt des Templates für einen wahren PHP-Connoisseur absolut Standardcode sein.

Eine Beispielausgabe sieht dann also ungefähr so aus:

Beispiel 3: "Und nun in hübsch"

Wenn man viele verschiedene Templates fertig gestellt hat, fällt einem irgendwann auf, dass sich darin zu Beginn und zum Ende eines Templates Text wiederholt. Nicht selten liegt dann ungefähr folgender Aufbau in den Templates vor:

  1. <!-- hier steht ein "header" -->
  2.  
  3. <!-- dann folgt der inhalt -->
  4. Hello World
  5.  
  6. <!-- und zum schluss noch ein footer -->

Da Header und Footer in allen Dateien gleich ist, liegt es nahe, sich nicht immer zu wiederholen (DRY - Don't Repeat Yourself). Für die Flexi-Templates gibt es speziell zu diesem Zweck einen Mechanismus: "Layouts".

Im folgenden wird nun die Zitatensammlung aus Beispiel 2 in ein Layout eingebettet.

Zunächst aber die theoretische Seite: Layouts sind ein Beispiel für Martin Fowlers "Decorator Pattern". Templates werden dazu in andere Layout-Templates eingebettet. Diese Layout-Templates bilden eine gemeinsame Struktur für die eingebetteten Inhalts-Templates. Das Layout-Template entscheidet, wohin der Inhalt der eingebetteten Templates eingefügt wird.

Layout-Templates sind dabei ganz normale Templates, allerdings mit zwei zusätzlichen Eigenschaften:

  • Die Ausgabe des Inhalttemplates wird im Attribut "content_for_layout" zur Verfügung gestellt.
  • Alle Attribute, die das Inhalts-Template erhält, ebenso wie alle Variablen, die das Inhalts-Template während seiner Evaluierung setzt, werden an das Layout-Template vererbt.

Ein Layout-Template sieht dann also im Prinzip so aus:

  1. header
  2. <?= $content_for_layout ?>
  3. footer

Wenn dann das Inhalt-Template folgende Ausgabe erzeugt:

  1. Hello, world!

wäre das Endergebnis dann:

  1. header
  2. Hello, world!
  3. footer

Um also nun einem Template ein Layout zuzuordnen, ruft man einfach die Methode #set_layout auf:

  1. $template->set_layout('my_chunky_layout');

Zurück zur Zitatensammlung aus Beispiel 2. Um unsere Zitate in ein Layout einzubetten, müssen wir lediglich:

  • dem Template-Objekt die Nachricht #set_layout senden
  • ein Layout-Template erstellen

Der erste Punk ist schnell erledigt. In dem PHP-Skript, das in Beispiel 2 unser Template-Objekt erzeugt hat, fügen wir folgende Zeile hinzu:

  1. [..]
  2. # open template
  3. $template = $factory->open('quotes');
  4.  
  5.  
  6. # set layout
  7. $template->set_layout('layout');
  8.  
  9.  
  10. # set quotes
  11. [..]

Damit bleibt nur noch Punkt 2: ein Layout-Template namens 'layout' erstellen:

  1. <html>
  2. <head>
  3.   <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
  4.   <title><?= $title ?></title>
  5.   <link rel="stylesheet" type="text/css" href="style.css" media="screen"/>
  6. </head>
  7. <body>
  8.   <?= $content_for_layout ?>
  9. </body>
  10. </html>

Das Stylesheet wird an dieser Stelle nicht wiedergegeben. Wichtig ist ja auch nur Zeile 8, in der die Ausgabe des Inhalts-Templates eingefügt wird.

Zusätzlich wird nun noch der Einsatz von in Inhalt-Templates gesetzten Variablen demonstriert. Gegenüber dem in Beispiel 2 verwendeten Template 'quotes', enthält dieses nun ausserdem folgende Zeile:

  1. [..]
  2. <? $title = "Zitate"; ?>
  3. [..]

Da nun im Inhalts-Template die Variable 'title' gesetzt wurde, kann diese im Layout-Template verwendet werden. (siehe dazu Zeile 4 im Layout-Template oben)

Damit sind nun alle wichtigen Mechanismen der Flexi-Templates vorgestellt worden. Es folgen nun noch ein paar Gimmicks...

Meanwhile, in another place …

Bevor wir zu den Gadgets kommen, noch ein kurzer Überblick über die API, die die Flexi-Templates bietet.

Zunächst kurz die Methoden, die ein Flexi_Template-Objekt bietet. Anzumerken ist, dass diese Objekte dieser Klasse nicht direkt instanziiert werden können, da man dafür eine Template-Factory benötigt.

  1. class Flexi_Template {
  2.  
  3.   function get_attribute($name);
  4.   function get_attributes();
  5.  
  6.   function set_attribute($name, $value);
  7.   function set_attributes($attributes);
  8.  
  9.   function clear_attributes();
  10.   function clear_attribute($name);
  11.  
  12.   function render($attributes = null, $layout = null);
  13.  
  14.   function set_layout($layout);
  15. }

Die ersten sechs Methoden:

  • #get_attribute
  • #get_attributes
  • #set_attribute
  • #set_attributes
  • #clear_attributes
  • #clear_attribute

dienen zum Setzen, Abfragen und Entfernen von Attributen. Für gewöhnlich werden wohl nur die beiden Setter

  • #set_attribute
  • #set_attributes

benötigt. Während #set_attribute einem Schlüssel einen Wert zuordnet:

  1. $template->set_attribute('key', new Value());

Mit der Methode #set_attributes kann man gleich ein ganzes (assoziatives) Array von Schlüssel-Wert-Paaren setzen:

  1. $attributes = array();
  2. $attributes['title'] = "a title";
  3. $attributes['content'] = "some content";
  4.  
  5. $template->set_attributes($attributes);

Anzumerken ist, dass diese Methode #set_attributes die bereits gesetzten Attribute nicht entfernt, sondern nur bereits vorhandene Schlüssel aktualisiert:

  1.  
  2. $template->set_attribute('key', 'value');
  3. $template->set_attribute('title', 'former title');
  4.  
  5.  
  6. $attributes = array();
  7. $attributes['title'] = "a title";
  8. $attributes['content'] = "some content";
  9.  
  10. $template->set_attributes($attributes);

Während also das #set_attributes den alten Wert des Attributs 'title' gegen den neuen Wert ersetzt, bleibt das Attribut 'key' erhalten.

Nun bleiben also noch die Methoden #set_layout und #render.

Die erste Methode #set_layout wurde schon in Beispiel 3 vorgestellt und hat als einzigen Parameter das Template, welches als Layout-Template verwendet werden soll.

Die letzte Methode #render wurde auch schon verwendet, hat allerdings zwei zusätzliche Parameter, die bisher nicht gezeigt wurden. Diese dienen aber lediglich dem Komfort. Während wir bisher folgende Verwendung gesehen haben:

  1. $template = $factory->open('hello_world');
  2.  
  3. $template->set_attribute('name', 'Axel');
  4.  
  5. $template->set_layout('layout');
  6.  
  7. echo $template->render();

kann mit dieser Code mit den zwei zusätzlichen Methodenparametern so geschrieben werden:

  1. $template = $factory->open('hello_world');
  2. echo $template->render(array('name' => 'Axel'), 'layout');

Letzte Änderung am April 02, 2011, at 03:27 AM von tthelen.