5. März 2015

#Template-Engine

#Tutorial

Tutorial: Einführung in die Template-Engine Smarty

Schon wieder hat der Designer mit seinen Grundkenntnissen in HTML an Ihrem funktionalen PHP-Quellcode Änderungen vorgenommen, weil er das Design nach seinen Vorgaben anpassen wollte? Oft entstehen durch keine klaren Abgrenzungen von Funktion und Design ärgerliche Missgeschicke, welche häufig eine Menge unnötige Arbeit verursachen. Das so genannte Templating Framework Smarty schafft hier Abhilfe.

Die Template-Engine Smarty sorgt dafür, dass bei der Entwicklung einer Webanwendung die Applikations-Logik klar von dem Design/Ausgabe getrennt ist. Die Darstellung des Designs erfolgt bei Smarty mit der Hilfe von Templates. In diesen Templates wird mit einer Kombination von HTML, CSS und Smarty-Template-Tags festgelegt, wie die Informationen dargestellt werden sollen. Durch diese Trennung kann das Design jederzeit auf ein zeitgemäßes Layout angepasst werden, ohne dabei eine Änderung der kompletten Applikation vorzunehmen. Dieses Tutorial wird Ihnen anhand eines Beispielprojekts die Basics von Smarty näher bringen.

Anforderungen

  • Webserver mit PHP ≥ 4.0.6

Vorbereitung/Installation

Vorbereitung und Installation der Smarty-Template-Engine

Zu Beginn erstellen wir ein neues Projekt und nennen dies einfachheitshalber „smarty_tutorial“. In diesem Projekt werden als nächstes die Datei „index.php“ und der Ordner „lib“ und erzeugt. Im Ordner „lib“ werden die Datei „smtemplate.php“ sowie der Ordner „views“ erstellt. Jetzt können wir das Framework von der offiziellen Smarty Seite herunterladen und entpacken. Der Ordner des Archives „demo“ enthält Demo-Dateien, welche wir für unser Beispielprojekt nicht benötigen. Wichtig für uns ist der Ordner „libs“, welchen wir in „smarty“ umbenennen in dann in unser zuvor erstelltes Projekt „smarty_tutorial“ in den Ordner „lib“ einfügen. Um zu einem späteren Zeitpunkt den Update-Vorgang zu vereinfachen, sollten die Smarty-Dateien im Ordner „smarty“ nicht verändert werden. Des Weiteren benötigt Smarty die Ordner „templates_c“, „cache“ und „config“, welche wir im Ordner „smarty“ anlegen. Smarty benötigt Schreibrechte (755) auf den Inhalt des Ordners „smarty“. Die Struktur unseres Projekts sollte nun wie folgt aussehen:

Konfiguration

Als nächstes erstellen wir eine Datei „smtemplate.php“ im Ordner „lib“, welche eine Klasse für unsere Smarty Template Engine darstellt. In dem Konstruktor dieser Klasse müssen die Pfade zu den Unterverzeichnissen im „smarty“-Ordner konfiguriert werden. Für die Realisierung dieser Konfiguration gibt es zwei Möglichkeiten: zum einen die Angabe der Pfade als Klassenkonstanten direkt in der „smtemplate.php“-Datei oder zum anderen die Definition der Pfade in einer Konfig-Datei. Wir definieren unsere Einstellungen über eine Konfig-Datei, weil sich auf diese Weise alle Smarty-Konfigurationen über diese Datei regeln lassen. Also erstellen wir zunächst eine Datei „smtemplate_config.php“ und speichern die Pfade in einem Array.

$smtemplate_config =
 array(
      'template_dir' => 'views/',
      'compile_dir' => 'lib/smarty/templates_c/',
      'cache_dir' => 'lib/smarty/cache/',
      'config_dir' => 'lib/smarty/config/',
);

Jetzt können wir unsere Konfig-Datei in die Datei „smtemplate-php“ einbinden und die Konfiguration wie im Folgenden zu sehen ist vornehmen.

/* Smarty-Dateien laden */
require_once('smarty/Smarty.class.php');
require_once('smtemplate_config.php');

/* An dieser Stelle können Applikations spezifische Bibliotheken geladen werden * Bsp: require(bib.lib.php); * */
class SMTemplate extends Smarty { /**   * Konstruktor.   * Erzeugt eine neue Smarty-Instanz und konfiguriert die Smarty-Pfade   */
  function __construct(){   parent::__construct();   global $smtemplate_config;   $this->template_dir = $smtemplate_config['template_dir'];   $this->compile_dir = $smtemplate_config['compile_dir'];   $this->cache_dir = $smtemplate_config['cache_dir'];   $this->config_dir = $smtemplate_config['config_dir'];   } }

Erstes Template erstellen und darstellen

Um ein Template darstellen zu können, benötigt die SMTemplate-Klasse eine Funktion „render“, welche dies übernimmt.

function render($template){
     $this->display($template . '.tpl');
}

Als nächsten Schritt erstellen wir im Ordner „views“ eine Template mit dem Namen „hello.tpl“ und folgendem Inhalt.

<html>
    <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
         <title>Home</title>
    </head>
  <body>   <p>Hello, World!</p>   </body>
</html>

Zur Darstellung des Templates wird in der Datei “index.php” die Funktion “render” unserer Smarty-Klasse aufgerufen.

require_once('lib/smtemplate.php');
$tpl = new SMTemplate(); $tpl->render('hello');

Der Aufruf der Seite „index.php“ sollte „Hello, World!“ ausgeben.


Übergabe von Variablen

Bei dem jetzigen Stand der Beispielanwendung können wir noch keine dynamischen Inhalte darstellen. Für diesen Fall verwendet Smarty Variablen, welche in einem Template benutzt werden können. Eine Übergabe dieser Variablen erfolgt durch die Übergabe eines Daten-Arrays an die Render-Funktion oder durch die Übergabe von Objekten, welche anschließend zu einem Array umgewandelt werden. In einem Template können die Variablen durch {$variablenname} aufgerufen werden. Um unsere Beispielapplikation etwas mit Leben zu füllen, muss zunächst die Render-Funktion angepasst werden, sodass diese das übergebene Daten-Array mit Hilfe der Funktion „assign“ an Smarty weitergibt.

function render($template, $data = array()){
     foreach($data as $key => $value) {
         $this->assign($key, $value);
     }
     $this->display($template . '.tpl');
}

In der Datei „index.php“ wird ein Array mit Daten gefüllt und an die Render-Funktion weitergeleitet.

$data = array(
     'user' => 'Coding Pioneers',
     'date' => time()
);

$tpl = new SMTemplate(); $tpl->render('hello', $data);

Auf die Variablen “user” und “date” können wir jetzt in dem Template “hello.tpl” zugreifen.

<body>
    <p>Hello {$user}! Date: {$date}</p>
</body>

Der Aufruf der Seite „index.php” gibt nun „Hello Coding Pioneers! Date: …“ aus. Zu sehen ist, dass das Datum noch unformatiert ist. Auch dazu bietet Smarty eine Lösung: Formatierung von Variablen.

Formatierung von Variablen

Smarty ermöglicht neben der einfachen Übergabe auch die Formatierung der übergebenen Variablen durch sogenannte Modifier, welche durch eine Pipe (|) angegeben werden. Zum Beispiel verwenden wir an unserer Variablen {$user} den Modifier „upper“, welcher den Inhalt in Großbuchstaben darstellt. Auch das Datum lässt sich mit Hilfe eines Modifiers formatieren. Ändern wir also unser Template „hello.tpl“ und verwenden die zuvor beschriebenen Modifier.

<body>
    <p>Hello {$user|upper}! Date: {$date|date_format:"%d %B"}</p>
</body>

Es ist zu sehen, dass der User-Name in Großbuchstaben dargestellt wird und das Datum formatiert ist. Neben dem Aufruf eines einzelnen Modifiers lassen sich diese durch {$var|mod1|mod2|mod3} kombinieren. Eine Liste aller in Smarty verfügbaren Modifier befindet sich in der ausführlichen Doku ab Seite 40. Reichen die rund 20 Modifier nicht aus, ermöglicht Smarty das Erstellen eigener Modifier.


Eigene Variablenmodifier

Für einen eigenen Variablenmodifier muss lediglich eine PHP-Funktion geschrieben werden. Dazu erstellen wir in dem Ordner „smarty/plugins“ die Datei „smarty_modifier_minimize“. Die Funktion minimiert HTML-Code, indem unnötige Leerzeichen, Umbrüche und Tabstopps entfernt werden.

function smarty_modifier_minimize($input) {
  // Input Kürzen   // s+ - mehrere Whitespaces aufeinanderfolgend   // \n - Zeilenumbruch   // \r - Zeilenumbruch   // \t - Tab
  $input = preg_replace('/^\s+|\n|\r|\t$/m', '', $input);
  /* Kommentare entfernen */   $input = preg_replace('//sU', '', $input);
  return $input; }

Auf dem aktuellen Standpunkt unserer Beispielanwendung können wir diesen Modifier noch nicht sinnvoll verwenden, da wir uns bisher nur mit dem Übergeben von Variablen mit einfachen Werten beschäftigt haben. Den Minimize-Modifier werden wir verwenden, nachdem wir uns die Layouts in Smarty näher angeschaut haben.

Layouts

Smarty verfügt über die Möglichkeit Templates zu laden, diese als Text zurückzugeben und in einer Variablen zu speichern. Diese Methode ermöglicht es, die Struktur der Seite in einem Template zu speichern und den dynamischen Inhalt an die gewünschte Position im Layout zu laden. Als erstes erstellen wir im Hauptverzeichnis des Projekts einen Ordner „layouts“ und in diesem Ordner ein neues Template mit dem Namen „page.tpl“ und den im folgenden Code dargestellten Inhalt. Die Smarty-Variable, welche ein Template als Text beinhalten soll, erhält zur Unterscheidung von normalen Variablen zwei Unterstriche. An dieser Stelle lässt sich der zuvor erstellte Variablenmodifier „minimize“ verwenden um die Inhaltsseite zu minieren.

<html>
     <head>
         <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
         <title>Home</title>
     </head>
  <body>   <header>   <h2>Header Content</h2>   <hr />   </header>
  <div>   {$__content|minimize}   </div>
  <footer>   <hr />   <h2>Footer Content</h2>   </footer>   </body> </html>

Im Ordner „views“ erstellen wir zwei neue Templates „start“ und „about“, welche die dynamischen Inhalte repräsentieren, mit folgendem Inhalt:

start.tpl

<h1>Start<h1/> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean aliquet dignissim diam at vulputate. Aenean nec ligula ac dolor fringilla pharetra. Cras in augue ac tellus dictum pellentesque. Integer elementum tempus lectus, non rutrum sem viverra a. Sed tincidunt sollicitudin dolor, ut blandit magna auctor non. </p>
about.tpl
<h1>Start<h1/> <p> Maecenas sed nibh felis. Donec dictum porta ante at faucibus. Morbi massa tellus, pulvinar id porta id, imperdiet vel nibh. Donec lectus nulla, porttitor a tempor id, cursus vitae leo. </p>

Im nächsten Schritt muss der Pfad zu dem Layout-Ordner in der Smarty-Engine konfiguriert werden. Dazu fügen wir zunächst ein neues Element in das smtemplate_config-Array.

$smtemplate_config =
 array(
      'layouts_dir' => 'layouts',
      'template_dir' => 'views/',
      'compile_dir' => 'lib/smarty/templates_c/',
      'cache_dir' => 'lib/smarty/cache/',
      'config_dir' => 'lib/smarty/config/',
);

In der SMTemplate-Klasse müssen wir den Layout-Ordner als weiteren Template-Ordner angeben, wobei zu beachten ist, dass Views und Layouts nicht den gleichen Namen besitzen dürfen, da Smarty nicht zwischen View- und Layout-Templates unterscheiden kann. Als Lösung des Problems können die Präfixe „view_“ und „layout_“ verwendet werden. Als nächstes muss die Render-Funktion angepasst werden, sodass sie eine View als Text lädt und diese in dem Layout „page“ darstellt. Um mit Smarty ein Template zu laden und dieses als Text zurückzugeben anstatt darzustellen, wird die Funktion „fetch“ verwendet und mit der bekannten Funktion „assign“ an die Smarty-Variable „__content“ übergeben. Das Layout „page“ wird wie zuvor mit der Funktion „display“ dargestellt.

function __construct(){
     parent::__construct();
         
     global $smtemplate_config;
     $this->template_dir = $smtemplate_config['template_dir'];
     $this->addTemplateDir($smtemplate_config['layouts_dir']);
     $this->compile_dir = $smtemplate_config['compile_dir'];
     $this->cache_dir = $smtemplate_config['cache_dir'];
     $this->config_dir = $smtemplate_config['config_dir'];
}
function render($template, $data = array(), $layout = 'page') {   foreach($data as $key => $value){   $this->assign($key, $value);   }
  $content = $this->fetch($template . '.tpl');   $this->assign('__content', $content);   $this->display($layout . '.tpl'); }

Um den Seiteninhalt in dem Layout darzustellen, wird in der „index.php“ wie gewohnt die Render-Funktion mit dem Inhaltstemplate „start“ aufgerufen.

$tpl = new SMTemplate();
$tpl->render('start');
Einfache Startseite mit Smarty
Einfache About-Seite mit Smarty

Der Aufrufe von “index.php” liefert folgende Ausgabe, indem unser „start“-Template in dem Layout „page“ dargestellt wird:



Wird das Template in „about“ geändert, ist zu erkennen, dass sich der Inhalt bei gleichbleibendem Layout geändert hat.



Header und Footer

Auf einer Webseite sind Header und Footer meistens auf jeder Seite identisch. Bei einem Layout für einen Blogbeitrag und das Impressum ändert sich oft an Header und Footer nichts außer dem Titel der Seite (<head><title>Titel</title></head>). Aus diesem Grund ist es sinnvoll, Header und Footer in Templates auszulagern. In Smarty können Templates durch den Befehl „include“ in andere Templates eingebunden werden. Des Weiteren besteht die Möglichkeit, dem Template, welches mit Hilfe von „include“ eingebunden wird, eine Variable als Attribut zu übergeben, wodurch sich z.B. ein sich ändernder Seitentitel realisieren lässt. Der Befehl {include file=“header.tpl“ title=“Start“} entspricht dem Einbinden eines Headertemplates und der Übergabe des Wertes „Start“ an die Variable {$title}. Um das beschriebene Vorgehen in der Praxis umzusetzen, erstellen wir die Templates „header.tpl“ und „footer.tpl“ im Ordner „layouts“.

header.tpl
<html>   <head>   <meta http-equiv="Content-type" content="text/html; charset=utf-8" />   <title>{$title|default:"Title"} | Smarty Tutorial</title>   </head>
  <body>   <header>   <h2>Header Content</h2>   <hr />   </header>
  <div>   footer.tpl   </div>
  <footer>   <hr />   <h2>Footer Content</h2>   </footer>
  </body>
</html>

Als nächstes erstellen wir ein neues Seitenlayout „page-head-foot“, binden die zwei Templates ein und übergeben dem Header die Variable $title.

{include file="../layouts/header.tpl" title="$title"}
     {$__content|minimize}
{include file="../layouts/footer.tpl"}

Danach muss die Funktion “render” angepasst werden, sodass sie den Seitentitel an die Smarty-Engine übergibt.

function render($template, $data = array(), $layout = 'page', $pagetitle = '') {
     foreach($data as $key => $value){
         $this->assign($key, $value);
     }
  $content = $this->fetch($template . '.tpl');   $this->assign('__content', $content);   $this->assign('title', $pagetitle);   $this->display($layout . '.tpl'); }

In der Datei „index.php“ muss der Aufruf des „start“-Templates durch den Seitentitel und das neue Layout ergänzt werden.

$tpl = new SMTemplate();
$tpl->render('start', $data, 'page_head_foot', 'Start');
Einfache Startseite mit Smarty

Der Aufruf der Seite „index.php” stellt den inkludierten Header mit Titel, den Inhalt des Templates „start” sowie den Footer dar.



Wiederkehrende Elemente

Die zuvor beschriebene Funktion kann ebenfalls für wiederkehrende Elemente verwendet werden. Zum Beispiel hat jede Seite einen Seitentitel (<h1>), welcher zwecks einheitlichem Erscheinungsbild der Webseite immer das gleiche Layout aufweisen sollte. Dazu erstellen wir ein Template im Ordner „layouts“ mit dem Namen „pagetitle“ und folgendem Inhalt:

<h1 style="color: red;">{$pagetitle|default:"Pagetitle"}</h1>

Dieses Template inkludieren wir in dem Inhaltstemplate „start”, um den Seitentitel jederzeit individuell, bei gleichbleibendem Layout, anpassen zu können.

{ include file="../layouts/pagetitle.tpl" pagetitle="Startpagetitle" }
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean aliquet dignissim diam at vulputate.
Aenean nec ligula ac dolor fringilla pharetra. Cras in augue ac tellus dictum pellentesque.
Integer elementum tempus lectus, non rutrum sem viverra a. Sed tincidunt sollicitudin dolor, ut blandit magna auctor non. </p>
Einfache Startseite mit wiederkehrenden Elementen

Ein erneuter Aufruf der Datei “index.php” zeigt, dass sich der Titel in “Startpagetitle” geändert hat und rot dargestellt wird, welches zeigt, dass das „pagetitle“-Template verwendet wird.

War das schon alles?

Wie durch die aufgezeigten Möglichkeiten von Smarty zu sehen ist, lässt sich durch die Verwendung von Smarty das Design einer Webanwendung einfach von dem funktionalen Quellcode trennen. Smarty bietet weitaus mehr Funktionen als die hier dargestellten, welche ich im Rahmen dieses Tutorials nicht weiter ausführen möchte. Der weitere Funktionsumfang umfasst unter anderem Schleifen, IF-Abfragen, weitere Plugins (nicht nur Variablenmodifier) sowie das Caching der geladenen Seiten. Eine ausführliche Dokumentation zu Smarty, in der die zuvor genannten Funktionen näher beschrieben sind, befindet sich auf der offiziellen Smarty-Seite.


Quellen