Erweiterte Template-Funktionen

1. Einleitung

Aufbauend auf Templates verfügt das APF über eine erweiterte Syntax für einfacheres Templating.

Im Auslieferungszustand stehen die in Kapitel 2 beschriebenen Möglichkeiten zur Verfügung, in Kapitel 3 erfahren Sie, wie die Syntax erweitert werden kann.

In Kapitel Working with view models (Englisch) finden Sie einen ausführlichen Artikel zur Nutzung von View-Models um Ihre Controller schlank und einfach testbar zu gestalten. Der Artikel nutzt die hier beschriebenen Möglichkeiten um die View-Templates einfach und übersichtlich zu gestalten.

2. Verfügbare Funktionen

Zusätzlich zu den im Kapitel Templates beschriebenen Funktionen lassen sich innerhalb von APF-Templates auch dynamische Template-Ausdrücke nutzen. Diese bieten Ihnen eine Kurzschreibweise für Platzhalter wie z.B. <html:placeholder /> sowie eine Pseudo-Sprache für den Zugriff auf Data-Attribute von APF-DOM-Knoten. Darüber hinaus lassen sich auch Methoden-Aufrufe und Listen-Zugriffe auf Data-Attribute realisieren.

Die folgenden Kapitel zeigen Ihnen die Nutzung der beiden Funktionen und geben Ihnen Anwendungsbeispiele.

2.1. Platzhalter

Neben den bekannten APF-Tags für Platzhalter wie beispielsweise

APF-Template
<html:placeholder name="foo" />

lässt sich auch die Kurzformen

APF-Template
${foo}

nutzen. Dies hilft die Größe Ihres Template-Codes zu reduzieren und gegebenfalls Probleme mit der IDE-Unterstützung für HTML-Dateien zu vermeiden.

Die Kurzschreibweise von Platzhaltern setzt sich aus ${, einem eindeutigen Bezeichner und einer schließenden Klammer - } - zusammen. Der Bezeichner darf keine weiteren Klammern enthalten. Erlaubt sind große und kleine Buchstaben sowie Binde- und Unterstriche.

Der Zugriff auf Platzhalter in der Kurzform unterscheidet sich nicht von der herkömmlichen Notation. Möchten Sie die Platzhalter des Templates

APF-Template
<@controller class="VENDOR\..\controller\SampleController" @> <div class="${css-class}"> <p> ${intro-text} </p> <p> ${detail-text} </p> <p> <a href="${link-target}">${link-label}</a> </p> </div>

füllen, so können Sie dazu den folgenen Controller-Code nutzen:

PHP-Code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $model = $this->getModel(); $this->setPlaceHolder('css-class', $model->getCssClass()); $this->setPlaceHolder('intro-text', $model->getIntroText()); $this->setPlaceHolder('detail-text', $model->getDetailText()); $this->setPlaceHolder('link-target', $model->getMoreLink()->getTarget()); $this->setPlaceHolder('link-label', $model->getMoreLink()->getLabel()); } /** * @return ContentModel */ private function getModel() { return new ContentModel(); } }

2.2. Objekt-Zugriff

Die Pseudo-Template-Sprache des APF ermöglicht Ihnen, mit einem dynamischen Ausdruck auf Data-Attribute von APF-DOM-Knoten zuzugreifen und die dort abgelegten Inhalte innerhalb von Templates auszugeben.

Das in Kapitel 2.1 beschriebene Template-Beispiel lässt sich mit Hilfe der Pseudo-Sprache wie folgt vereinfachen:

APF-Template
<@controller class="VENDOR\..\controller\SampleController" @> <div class="${news->getCssClass()}"> <p> ${news->getIntroText()} </p> <p> ${news->getDetailText()} </p> <p> <a href="${news->getMoreLink()->getLinkTarget()}"> ${news->getMoreLink()->getLinkLabel()} </a> </p> </div>

Der Controller verkürzt sich ebenfalls:

PHP-Code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $this->setData('news', $this->getModel()); } /** * @return ContentModel */ private function getModel() { return new ContentModel(); } }

Auf diese Weise lässt sich wiederholender Code aus Controllern entfernen und damit die Übersichtlichkeit erhöhen.

Grundlage für die Pseudo-Template-Sprache ist das APF-DOM-Modell. Dieses ermöglicht - analog zu HTML-Knoten - Data-Attribute zu definieren. Die Klasse Document stellt hierzu die Methoden setData() und getData() zur Verfügung. Innerhalb des BaseDocumentController können Sie mit den gleichnamigen Methoden ebenfalls auf die Data-Attribute des aktuellen Knotens zuzugreifen.

Die folgenden Kapitel stellen Ihnen die Funktionalitäten der Template-Sprache genauer vor.

2.2.1. Listen-Zugriff

Mit der Pseudo-Template-Sprache des APF lassen sich Listen-Zugriffe für Data-Attribute analog zur PHP-Syntax realisieren. Dabei werden einfach, sowie mehrfach verschachtelte Arrays mit nummerischen und alphanummerischen Adressen unterstützt.

Sie können im Template auf einfache und verschachtelte Listen mit einfachen Inhalten, aber auch auf Listen mit komplexen Inhalten (Objekte) zugreifen. Der Zugriff auf komplexe Inhalte erfordert gegebenenfalls weitere Schritte. Beachten Sie hierzu bitte Kapitel 2.2.2 und Kapitel 2.2.3.

Die folgende Code-Box zeigt Ihnen den Zugriff auf Listen im Template:

APF-Template
<@controller class="VENDOR\..\controller\SampleController" @> <!-- Zugriff auf das erste, nummerische Offset --> ${news[0]} <!-- Zugriff auf das Offset xyz --> ${news['xyz']} <!-- Zugriff auf das nummerische Offset 1 und darin auf das nummerische Offset 2 --> ${news[1][2]} <!-- Zugriff auf das nummerische Offset 1 und darin auf das alphanummerische Offset xyz --> ${news[1]['xyz']} <!-- Zugriff mit Mischformen --> ${news[1][2][3][4]} ${news[1]['two'][3]['four']}

Um mit den beschriebenen Ausdrücken auf Inhalte zugreifen zu können sind die Data-Attribute im Controller wie folgt zu befüllen:

PHP-Code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $model = $this->getModel(); // Zugriff auf das erste, nummerische Offset $this->setData( 'news', array( 0 => $model ) ); // Zugriff auf das Offset xyz $this->setData( 'news', array( 'xyz' => $model ) ); // Zugriff auf das nummerische Offset 1 und darin auf das nummerische Offset 2 $this->setData( 'news', array( 1 => array( 2 => $model ) ) ); // Zugriff auf das nummerische Offset 1 und darin auf das alphanummerische Offset xyz $this->setData( 'news', array( 1 => array( 'xyz' => $model ) ) ); // Zugriff mit Mischformen $this->setData( 'news', array( 1 => array( 2 => array( 3 => array( 4 => $model ) ) ) ) ); $this->setData( 'news', array( 1 => array( 'two' => array( 3 => array( 'four' => $model ) ) ) ) ); } /** * @return ContentModel */ private function getModel() { return new ContentModel(); } }
Implementieren die in der Liste befindlichen Objekte die __toString()-Methode, so können Sie die Ausgabe der Objekte durch einen Listen-Zugriff erzeugen ohne weitere Methoden-Aufrufe zu definieren.
2.2.2. Objekt-Zugriff

Neben dem Zugriff auf Listen, bietet die Pseudo-Template-Sprache des APF auch den Zugriff auf Objekte in Data-Attributen. Die Syntax folgt auch hier der PHP-Syntax.

Methoden-Aufrufe lassen sich in beliebiger Anzahl und Abfolge definieren und können auch in Verbindung mit Listen genutzt werden. Beachten Sie hierzu bitte die Dokumentation in Kapitel 2.2.3.

Die folgende Code-Box zeigt Ihnen Beispiele für Methoden-Aufrufe:

APF-Template
<@controller class="VENDOR\..\controller\SampleController" @> <!-- Zugriff auf die Methode getCssClass() der Klasse ContentModel --> ${news->getCssClass()} <!-- Zugriff auf die Methode getLinkLabel() der Klasse LinkModel, das von der Methode getMoreLink() der Klasse ContentModel zurückgegeben wird --> ${news->getMoreLink()->getLinkLabel()}

Um mit den beschriebenen Ausdrücken auf Inhalte zugreifen zu können muss das Data-Attribute news im Controller wie folgt zu befüllt werden:

PHP-Code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $this->setData('news', $this->getModel()); } }
Neben dem Zugriff auf Data-Attribute ist es auch möglich auf die Instanz desjenigen Tags zuzugreifen, in dem der Ausdruck definiert ist und ausgeführt wird. Hier steht Ihnen das Schlüsselwort this zur Verfügung. Möchten Sie beispielsweise den Namen des Templates ausgeben, in dem ein Ausdruck definiert ist, so können Sie dies wie folgt tun:
APF-Template
<html:template name="foo"> Template-Name: ${this->getAttribute('name')} </html:template>
2.2.3. Kombinierter-Zugriff

Die in Kapitel 2.2.1 und Kapitel 2.2.2 beschriebenen Listen- und Methoden-Zugriffe lassen sich auch zu komplexeren Abfragen kombinieren. So kann durch eine Kombination eines Listen- und ein oder mehrerer Methoden-Aufrufe der Zugriff auf eine Liste von Einträgen und deren Eigenschaften realisieren.

Bitte beachten Sie, dass mehrere Methoden-Aufrufe bzw. Listen-Zugriffe jeweils durch -> getrennt sind.

Beabsichtigen Sie in einem Template die ersten drei News-Einträge auszugeben, so lässt sich dies mit dem folgenden Template realisieren:

APF-Template
<@controller class="VENDOR\..\controller\SampleController" @> <ul class="news-list"> <li>${news[0]->getIntroText()}</li> <li>${news[1]->getIntroText()}</li> <li>${news[2]->getIntroText()}</li> </ul>

Zur Erzeugung der Ausgabe ist folgender Controller-Code notwendig:

PHP-Code
namespace VENDOR\..\controller; use APF\core\pagecontroller\BaseDocumentController; class SampleController extends BaseDocumentController { public function transformContent() { $this->setData('news', $this->getNews()); } /** * @return ContentModel[] */ private function getNews() { ... } }

Die Methode getNews() liefert dabei eine Liste von ContentModel-Objekten zurück.

Die Implementierung der Pseudo-Template-Sprache ermöglicht darüber hinaus weitere Kombinationen von Ausdrücken:

APF-Template
<!-- Aufruf von getBar() auf das dritte von getFoo() zurückgegebene Element --> ${news->getFoo()->[3]->getBar()} <!-- Aufruf von getBaz() auf das Ergebnis von getBar(), das im Offset foo des 5.ten Elements im Data-Attribut news steht --> ${news[5]['foo']->getBar()->getBaz()}
Bitte beachten Sie, dass die im letzen Code-Block aufgeführten Beispiele jeweils eine entsprechende Daten-Struktur voraussetzen! Fehlerhafte Ausdrücke führen zu Fehlern und damit zum Abbruch der Applikation.

3. Erweiterung der Syntax

Die erweiterte Templating-Syntax basiert auf einer Funktion des APF-Parsers zur Verarbeitung von logischen Ausdrücken. Dabei leitet ${ einen Ausdruck ein und } schließt diesen. Der Teil zwischen diesen beiden Elementen formuliert die eigentliche Anweisung. Auf diese Weise lassen sich Platzhalter und der Zugriff auf Data-Attribute sehr einfach und mit einer im Vergleich zu XML-Tags kürzeren Schreibweise realisieren.

Die während des Verarbeitens eines Templates oder einer Tag-Struktur gefundenen Ausdrücke werden in APF-DOM-Knoten übersetzt und an die entsprechende Stelle im Baum eingehangen. Damit können Sie auf diese innerhalb der Applikation mit den gewohnten Mechanismen zugreifen.

Zur Erweiterung der in Kapitel 2 beschriebenen Templating-Syntax lassen sich mit Hilfe der Methode Document::addTemplateExpression() - analog zu Document::addTagLib() - eigene Ausdrücke registrieren.

Die folgenden Kapitel beschreiben nun den Aufbau und den Einsatz von eigenen Ausdrücken.

3.1. Definition

Ein Template-Ausdruck definiert sich über das Interface TemplateExpression. Dieses dient dem APF-Parser zu erkennen, ob der Ausdruck für die Verarbeitung des Inhalts zwischen ${ und } zuständig ist. Falls dies zutrifft, erzeugt er einen DOM-Knoten, der die Funktionalität des Ausdrucks repräsentiert.

Das Interface definiert folgende Methoden:

PHP-Code
namespace APF\core\pagecontroller; interface TemplateExpression { public static function applies($token); public static function getDocument($token); }

Die Methode applies() nutzt der Parser um an Hand der registrierten Ausdrücke den jeweils zuständige Implementierung zu evaluieren. Hierzu übergibt der APF-Parser den zu verarbeitenden Ausdruck und erwartet die Rückgabe von true sofern die Implementierung zuständig ist. Ist dies nicht der Fall, ist der Rückgabewert false.

Wird in einem Template der Ausdruck

APF-Template
${getString(APF\modules\comments, language.ini, header.title)}

definiert, so übergibt der Parser getString(APF\modules\comments, language.ini, header.title) an die Methode applies().

Die Methode getDocument() übernimmt die Erzeugung eines DOM-Knotens zur Verarbeitung des Ausdrucks. Damit folgt das APF konsequent dem HMVC-Ansatz beim Aufbau von GUI-Komponenten und kapselt die Funktionalität in einem Tag.

3.2. Implementierung

Die Implementierung eines Template-Ausdrucks umfasst die Implementierung des TemplateExpression-Interfaces, die wiederum eine Tag-Implementierung als Rückgabe der getDocument()-Methode verwendet. Die TemplateExpression-Implementierung beschreibt dabei den Ausdruck, der Tag implementiert die konkrete Funktionalität des Ausdrucks.

Als Beispiel für dieses Kapitel soll die verkürzte Syntax für den <html:getstring />-Tag dienen. Dieser gibt je nach Sprache der Anwendung einen lokalisierten Inhalt aus einer Sprach-Datei aus.

Die folgende Code-Box beinhaltet eine Implementierung für die verkürzte <html:getstring />-Syntax:

PHP-Code
namespace VENDOR\..\expression; class GetStringTemplateExpression implements TemplateExpression { const START_TOKEN = 'getString('; const END_TOKEN = ')'; public static function applies($token) { return strpos($token, self::START_TOKEN) !== false && strpos($token, self::END_TOKEN) !== false; } public static function getDocument($token) { $startTokenPos = strpos($token, self::START_TOKEN); $endTokenPos = strpos($token, self::END_TOKEN, $startTokenPos + 1); $arguments = explode(',', substr($token, $startTokenPos + 10, $endTokenPos - $startTokenPos - 10)); $object = new LanguageLabelTag(); $object->setAttribute('namespace', trim($arguments[0])); $object->setAttribute('config', trim($arguments[1])); $object->setAttribute('entry', trim($arguments[2])); return $object; } }

Innerhalb der applies()-Methode wird zunächst festgestellt, ob die vorliegende Implementierung für die Verarbeitung zuständig ist. Dies geschieht an Hand des erwarteten öffnenden und schließenden Token.

Bitte beachten Sie, dass die Verarbeitung von Template-Ausdrücken an Hand von Zeichenketten und nicht an Hand von XML-Strukturen erfolgt. Bitte stellen Sie daher bei der Implementierung von eigenen Ausdrücken sicher, dass diese innerhalb eines Projektes eindeutig zu erkennen sind.

Die getDocument()-Methode erzeugt im Anschluss den einen Tag, der die Verarbeitung des Ausdrucks übernimmt. Im Fall des getString()-Ausdrucks basiert die Implementierung auf dem im APF vorhandenen LanguageLabelTag-Tag der an Hand der Attribute namespace, config und entry eine Sprach-abhängige Ausgabe erzeugt.

Hinweise zur Implementierung von eigenen Tags finden Sie unter Implementierung von Tags.

3.3. Konfiguration

Möchten Sie den im vorangegangenen Kapitel erstellten Template-Ausdruck nutzen, so muss dieser in der Bootstrap-Datei registriert werden. Hierzu können Sie folgenden Code nutzen:

PHP-Code
Document::addTemplateExpression('VENDOR\..\expression\GetStringTemplateExpression');

Anschließend lässt sich der Ausdruck in einem Template wie folgt nutzen:

APF-Template
<h2>Beispiel</h2> <p> ${getString(APF\modules\comments, language.ini, header.title)} </p>

4. Bedingte Ausgabe

Ein häufiger Anwendungsfall in Web-Anwendungen ist die bedingte Ausgabe von Inhalten. Als Lösung bietet das APF zwei Tag-Implementierungen, die einfache sowie komplexe Anwendungsszenarien abdecken.

Der <cond:placeholder />-Tag erlaubt die Ausgabe von Inhalten sofern eine definierte Bedingung erfüllt wurde. Der <cond:template />-Tag ist für komplexere Ausgaben wie die bedingte Ausgabe von komplexen Inhalten gedacht.

<cond:placeholder /> und <cond:template /> kombinieren die Definition der Ausgabe mit der Ausgabe-Bedingung direkt im Template. Dadurch erhöht sich nicht nur die Übersichtlichkeit, sondern hilft auch den Controller-Code einfach zu gestalten.

Die folgenden Kapitel bringen Ihnen die Verwendung der beiden Tags an Hand von ausführlichen Beispielen näher.

4.1. Platzhalter

Die Signatur des <cond:placeholder />-Tags gestaltet sich wie folgt:

APF-Template
<cond:placeholder name="" [condition=""]> ... ${content} ... </cond:placeholder>
Beschreibung der Attribute:
  • name: Name des Platzhalters. Über den Namen kann auf das Element zugegriffen werden - z.B. im Controller. (Zeichen: [A-Za-z0-9-_])
  • condition (optional): Definition der Bedingung, die über die Ausgabe des Inhalts entscheidet (Standard: notEmpty()). Details zu den verfügbaren Bedingungen entnehmen Sie bitte Kapitel 4.3.
  • ${content}: Mit Hilfe des inneren Platzhalters content lässt sich der im Controller gesetzte Inhalt innerhalb der bedingten Ausgabe platzieren.

Das folgende Beispiel zeigt die Ausgabe eines Teasers, der eine optionale Zwischen-Überschrift besitzt. Durch den Einsatz des <cond:placeholder />-Tags lässt sich die bedingte Ausgabe sehr einfach realisieren:

APF-Template
<h2 class="...">${headline}</h2> <cond:placeholder name="sub-headline"> <h3 class="...">${content}</h3> </cond:placeholder> <p> ${content} </p>

Der <cond:placeholder />-Tag verhält sich innerhalb eines Templates wie ein "normaler" Platzhalter (siehe Standard TagLibs). Damit lässt er sich innerhalb eines Controllers sehr einfach mit anderen Platzhalter kombinieren.

Der Controller gestaltet sich damit wie folgt:

PHP-Code
class TeaserController extends BaseDocumentController { public function transformContent() { $teaser = $this->getTeaser(); $this->setPlaceHolders([ 'headline' => $teaser->getHeadline(), 'sub-headline' => $teaser->getSubHeadline(), 'content' => $teaser->getContent() ]); } }

Die Zwischen-Überschrift wird nun nur dann ausgegeben, sofern die Methode getSubHeadline() einen nicht leeren Inhalt liefern.

Soll die Zwischen-Überschrift nur dann angezeigt werden, wenn Sie eine Länge von mindestens 5 und maximal 20 Zeichen besitzt, so lässt sich dies durch Anpassung im Template wie folgt realisieren:

APF-Template
<h2 class="...">${headline}</h2> <cond:placeholder name="sub-headline" condition="between(5,20)"> <h3 class="...">${content}</h3> </cond:placeholder> <p> ${content} </p>
Die Liste der verfügbaren Bedingungen entnehmen Sie bitte Kapitel 4.3.

Innerhalb des <cond:placeholder />-Tags lässt sich ebenfalls die erweiterte Templating-Syntax anwenden. Damit können Sie mit Hilfe von ${content} auch Listen bzw. Objekte darstellen.

Das folgende Beispiel definiert zusätzlich zur optionalen Zwischen-Überschrift noch einen optionalen, weiterführenden Link:

APF-Template
<h2 class="...">${headline}</h2> <cond:placeholder name="sub-headline"> <h3 class="...">${content}</h3> </cond:placeholder> <p> ${content} </p> <cond:placeholder name="link"> <a href="${content->getUrl()}">${content->getLabel()}</a> </cond:placeholder>

Der Controller muss zur Ausgabe des Links wie folgt erweitert werden:

PHP-Code
class TeaserController extends BaseDocumentController { public function transformContent() { $teaser = $this->getTeaser(); $this->setPlaceHolders([ 'headline' => $teaser->getHeadline(), 'sub-headline' => $teaser->getSubHeadline(), 'content' => $teaser->getContent(), 'link' => $teaser->getMoreLink() ]); } }

Liefert die Methode getMoreLink() ein assoziatives Array mit den Offsets more-link und more-label zurück so kann die Ausgabe wie folgt vorgenommen werden:

APF-Template
<cond:placeholder name="link"> <a href="${content['more-link']}">${content['more-label']}</a> </cond:placeholder>

Ein komplexeres Szenario ergibt sich, sofern bei nicht gepflegtem Link ein Verweis auf die Startseite angezeigt werden soll. Der folgende Template-Code zeigt - sofern vorhanden - den weiterführenden Link oder einen Verweis auf die Startseite an:

APF-Template
<cond:placeholder name="link" condition="empty()"> <a href="/">Startseite</a> </cond:placeholder> <cond:placeholder name="link"> <a href="${content->getUrl()}">${content->getLabel()}</a> </cond:placeholder>

4.2. Template

Die Signatur des <cond:template />-Tags gestaltet sich wie folgt:

APF-Template
<cond:template content-mapping="" expression="" [condition=""]> ... </cond:template>
Beschreibung der Attribute:
  • content-mapping: Definiert, welcher Inhalt aus dem Eltern-Dokument zur Ausgabe genutzt werden soll. Die Evaluierung wird dabei mit Hilfe der erweiterten Templating-Syntax (siehe Kapitel 2) vorgenommen. Das Ergebnis steht innerhalb des Tags dann im Data-Attribut content zur weiteren Nutzung zur Verfügung.
  • expression: Mit Hilfe des im Attribut expression definierten Ausdrucks wird der Vergleichswert errechnet. Dieser wird dann gegen die im Attribut condition definierten Bedingung geprüft um zu entscheiden, ob der Inhalt ausgegeben werden soll oder nicht. Die Evaluierung wird dabei ebenfalls mit Hilfe der erweiterten Templating-Syntax (siehe Kapitel 2) vorgenommen.
  • condition (optional): Definiert die Bedingung, die über die Ausgabe des Inhalts entscheidet (Standard: notEmpty()). Details zu den verfügbaren Bedingungen entnehmen Sie bitte Kapitel 4.3.
Die Attribute des Tags lassen sich auch wie folgt lesen: content-mapping definiert den Kontext der Ausgabe und mit Hilfe von expression wird der Wert evaluiert, der mit Hilfe der condition zur Ausgabesteuerung bewertet wird.

Template-Fragmente - wie beispielsweise auch das <html:template />-Tag - sind für die Ausgabe von sich wiederholenden oder nur unter bestimmten Bedingungen anzuzeigenden Inhalten gedacht. Nutzen Sie das <html:template />-Tag, übernimmt der Controller die Steuerung der Evaluierung der Bedingung und die Ausgabe. Mit dem <cond:template />-Tag lässt sich die Anzeige-Logik komplett an das Template delegieren um den Controller schlank zu halten.

Der <cond:template />-Tag bietet Ihnen die Möglichkeit, komplexe, bedingte Ausgaben im Template zu formulieren. Soll der in Kapitel 4.1 beschriebene Teaser nur dann ausgegeben werden, wenn er für die Darstellung freigegeben ist, so kann die Ausgabe im Template wie folgt erledigt werden:

APF-Template
<cond:template content-mapping="teaser" expression="content->displayIt()" condition="true()"> <h2 class="...">${content->getHeadline()}</h2> <cond:template content-mapping="content" expression="content->getSubHeadline()" condition="notEmpty()"> <h3 class="...">${content->getSubHeadline()}</h3> </cond:template> <p>${content->getText()}</p> <cond:template content-mapping="content->getMoreLink()" expression="content" condition="notEmpty()"> <a href="${content->getUrl()}">${content->getLabel()}</a> </cond:template> </cond:template>
Die Bennenung der Variablen bzw. Data-Attribute kann vollständig frei definiert werden. Bitte beachten Sie, dass die Namen der Data-Attribute in Controller und Template übereinstimmen müssen!

Da die Darstellung komplett dem Template überlassen ist, lässt sich innerhalb des Controllers sehr einfach mit einem View-Model (Englisch) arbeiten. Dies hilft Ihnen dabei, eine klare Datenstruktur aufzubauen und mit dem Inhalt verbundene Logik im Domänen-Objekt bzw. View-Model zu kapseln. Dies hilft Ihnen die Testbarkeit und damit die Qualität Ihrer Software zu erhöhen.

Zur Ausgabe eines Teasers ist folgender Controller-Code erforderlich:

PHP-Code
class TeaserController extends BaseDocumentController { public function transformContent() { $this->setData('teaser', $this->getTeaser()); } }

Die Funktion getTeaser() liefert dabei eine Instanz der Klasse Teaser mit folgenden Methoden zurück:

PHP-Code
class Teaser { public function displayIt() { ... } public function getHeadline() { ... } public function getSubHeadline() { ... } public function getText() { ... } public function getMoreLink() { ... } }

getMoreLink() gibt eine Instanz der Klasse MoreLink mit folgenden Methoden zurück:

PHP-Code
class MoreLink { public function getUrl() { ... } public function getLabel() { ... } }
Die genannten Methoden können mit Hilfe der erweiterten Templating-Syntax (siehe Kapitel 2) zur Ausgabe von Inhalten sowie zur Formulierung von Mappings und Bedingungen genutzt werden.

Mit Hilfe der umschließenden Tag-Definition

APF-Template
<cond:template content-mapping="teaser" expression="content->displayIt()" condition="true()"> ... </cond:template>

werden folgende Dinge definiert:

  • Das Attribut content-mapping definiert, welcher Inhalt innerhalb des Templates in der Variable content zur weiteren Verarbeitung und Ausgabe zur Verfügung stehen soll (Kontext der Ausgabe). In diesem Fall wird das Data-Attribut teaser aus dem Eltern-Dokument genutzt, das gemäß Controller-Code eine Instanz der Klasse Teaser enthält.
  • Der Inhalt des expression-Attributs evaluiert denjenigen Wert, der mit der im Attribut condition formulierten Bedingung verglichen werden soll. Auf Basis des content-mapping, kann im Ausdruck auf das Data-Attribut content verwendet werden.
    In diesem Fall wird die Methode displayIt() der Klasse Teaser genutzt, die einen boolschen Wert zurück liefert.
  • Die im Attribut condition formulierte Bedingung legt fest, ob der Inhalt des Templates ausgegeben wird oder nicht. Trifft die Bedingung true() zu - bzw. liefert die Methode displayIt() den Wert true -, so wird das Template dargestellt.

Innerhalb des Templates sind zwei weitere <cond:template />-Tags definiert, die sich um die optionale Ausgabe der Zwischen-Überschrift und des weiterführenden Links kümmern.

Die Zwischenüberschrift wird mit Hilfe der Tag-Definition

APF-Template
<cond:template content-mapping="content" expression="content->getSubHeadline()" condition="notEmpty()"> <h3 class="...">${content->getSubHeadline()}</h3> </cond:template>

dann ausgegeben, wenn die Methode getSubHeadline() einen nicht leeren Inhalt zurück liefert. Die Tag-Definition liest sich wie folgt:

  • Als Inhalt (Kontext der Ausgabe) wird der Inhalt des Data-Attributs content des Eltern-Elements genutzt werden. Dies wird durch den Ausdruck im Attribut content-mapping festgelegt. Dabei handelt es sich auch hier um die Instanz der Klasse Teaser.
  • Die expression definiert, dass die von der Methode getSubHeadline() zurückgegebene Zwischenüberschrift zur Steuerung der Ausgabe heran gezogen werden soll.
  • Mit Hilfe der Bedingung notEmpty() wird überprüft, ob die Zwischenüberschrift vorhanden ist. Ist die Zeichenkette nicht leer, wird das HTML-Gerüst inklusive der Überschrift ausgegeben.

Ähnlich verhält es sich mit dem weiterführenden Link. Hier wurde das content-mapping allerdings dazu genutzt, die Instanz der Klasse MoreLink, die von der Methode geMoreLink() zurückgegeben wird, im Data-Attribut content zur Verfügung zu stellen. Dies erleichtert nicht nur die Formulierung der Bedingungen, sondern auch die Ausgabe innerhalb des Templates.

Der weiterführende Link lässt sich basierend auf dem Vorhandensein eines Links in der Teaser-Instanz wie folgt bewerkstelligen:

APF-Template
<cond:template content-mapping="content->getMoreLink()" expression="content" condition="notEmpty()"> <a href="${content->getUrl()}">${content->getLabel()}</a> </cond:template>

Die Tag-Definition lässt sich folgendermaßen interpretieren:

  • Als Inhalt (Kontext der Ausgabe) wird der Rückgabe-Wert der Methode getMoreLink() der Teaser-Instanz im Data-Attributs content des Eltern-Elements genutzt. Die Methode gibt entweder eine Instanz der Klasse MoreLink oder null zurück.
  • Zur Ausgabe-Steuerung soll ebenfalls der Rückgabe-Wert der Methode getMoreLink() genutzt werden. Dies wird im Attribut expression definiert indem direkt auf das Data-Attribut contemnt verwiesen wird.
  • Die im Attribut condition definierte Bedingung prüft nun, ob der weiterführende Link vorhanden ist (Data-Attribut content enthält eine Instanz der Klasse MoreLink) und gibt das Template zur Ausgabe frei.
Die Schachtelungstiefe von <cond:template />-Tags ist nicht begrenzt. Damit lassen sich auch noch komplexere Konstrukte definieren.
Mit Hilfe der in Kapitel 2 beschriebenen erweiterten Templating-Syntax kann sich innerhalb eines Templates auch auf ausserhalb definierte Inhalte zugreifen. Wird im Controller ein zusätzliches Data-Attribut headline-color definiert, kann dies wie folgt zur Ausgabe-Formatierung verwendet werden:
APF-Template
<cond:template ...> <h2 class="${this->getParentObject()->getParentObject()->getData('headline-color')}"> ... </h2> ... </cond:template>

4.3. Verfügbare Bedingungen

Zur Ausgabe-Steuerung stehen folgende Bedingungen zur Verfügung:

  • true(): Die Prüfung ist erfolgreich wenn der zu prüfende Wert true ist.
  • false(): Die Prüfung ist erfolgreich wenn der zu prüfende Wert false ist.
  • empty(): Die Prüfung ist erfolgreich wenn der zu prüfende Wert leer ist. Dies lässt sich sowohl auf Zeichenketten als auch auf Objekte anwenden.
  • notEmpty(): Die Prüfung ist erfolgreich wenn der zu prüfende Wert nicht leer ist. Dies lässt sich sowohl auf Zeichenketten als auch auf Objekte anwenden.
  • matches(<Zeichenkette>): Die Prüfung ist erfolgreich wenn der zu prüfende Wert mit dem übergebenen Wert übereinstimmt. Der Vergleich lässt sich mit Zeichenketten und Ziffern durchführen.
  • contains(<Zeichenkette>): Die Prüfung ist erfolgreich wenn der zu prüfende Wert im übergebenen Wert enthalten ist.
  • longerThan(<Zahl>): Die Prüfung ist erfolgreich wenn der zu prüfende Wert mehr Zeichen besitzt als im übergebenen Wert definiert wurde.
  • shorterThan(<Zahl>): Die Prüfung ist erfolgreich wenn der zu prüfende Wert weniger Zeichen besitzt als im übergebenen Wert definiert wurde.
  • length(<Zahl>): Die Prüfung ist erfolgreich wenn der zu prüfende Wert exakt die Anzahl an Zeichen besitzt die im übergebenen Wert definiert wurde.
  • between(<Zahl>,<Zahl>): Die Prüfung ist erfolgreich wenn der zu prüfende Wert eine definierte Anzahl von Zeichen besitzt (Miminal- und Maximal-Werte eingeschlossen).
Mehrere Argumente werden jeweils durch ein Komma getrennt, Zeichenketten mit Leerzeichen müssen mit einfachen Anführungszeichen umschlossen werden!

5. Iterative Ausgabe

Ein weiterer häufiger Anwendungsfall in Web-Anwendungen ist die Ausgabe von sich wiederholenden Inhalten. Das APF bietet für die Realisierung von beliebigen Listen eine einfache Umsetzung mit Hilfe von Templates an.

Bitte beachten Sie, dass der <loop:template />-Tag für einfache Anwendungsfälle gedacht ist. Für komplexere Anwendungsfälle wie beispielsweise der Ausgabe von verschachtelten Listen empfiehlt das APF-Team die Nutzung des Iterator-Tags.

Der <loop:template />-Tag erlaubt die Definition eines HTML-Gerüsts, das das Aussehen eines Listen-Elements repräsentiert. Das HTML-Markup einer unsortierte Liste lässt sich damit durch den umliegenden HTML-Codes (Beginn und Ende der Liste) und des Inhalts des Schleifen-Templates definieren.

Die Signatur des Tags gestaltet sich wie folgt:

APF-Template
<loop:template content-mapping="" [name=""]> ... </loop:template>
Beschreibung der Attribute:
  • content-mapping: Definiert, welcher Inhalt aus dem Template zur Ausgabe genutzt werden soll. Die Evaluierung wird dabei mit Hilfe der erweiterten Templating-Syntax (siehe Kapitel 2) vorgenommen. Das Ergebnis steht innerhalb des Tags dann im Data-Attribut content zur weiteren Nutzung zur Verfügung.
  • name: Name des Templates. Über den Namen kann auf das Element zugegriffen werden. (Zeichen: [A-Za-z0-9-_]).

Möchten Sie eine unsortierte Liste von Links generieren, so lässt sich das Template wie folgt definieren:

APF-Template
<ul> <loop:template name="list" content-mapping="items"> <li><a href="${content['url']}">${content['title']}</a></li> </loop:template> </ul>

Zur Ausgabe der Liste ist folgender Controller-Code nötig:

PHP-Code
$template = $this->getTemplate('list'); $template->setData( 'items', [ ['url' => '/shop', 'title' => 'Web-Shop'], ['url' => '/about', 'title' => 'Über uns'], ['url' => '/contact', 'title' => 'Kontakt-Formular'] ] ); $template->transformOnPlace();

Neben der Ausgabe von sich wiederholenden Inhalten können im Template auch statische Platzhalter definiert werden. Soll jedes Listen-Element eine bestimmte, dynamische CSS-Klasse erhalten, so kann dies wie folgt erreicht werden:

APF-Template
<ul> <loop:template name="list" content-mapping="items"> <li class="${css-class}"><a href="${content['url']}">${content['title']}</a></li> </loop:template> </ul>

Im Controller kann das als ganz normaler Platzhalter injiziert werden:

PHP-Code
$template = $this->getTemplate('list'); $template->setData( 'items', [ ['url' => '/shop', 'title' => 'Web-Shop'], ['url' => '/about', 'title' => 'Über uns'], ['url' => '/contact', 'title' => 'Kontakt-Formular'] ] ); $template->setPlaceHolder('css-class', 'foo'); $template->transformOnPlace();

Neben den beschriebenen Möglichkeiten lassen sich alle Funktionalitäten des <html:template />-Tags nutzen. Zur Ausgabe von Inhalten können Sie neben dem Zugriff auf Array-Offsets auch den Zugriff auf Objekte nutzen. Details hierzu entnehmen Sie bitte Kapitel 3.

Injizieren Sie im Controller per
PHP-Code
$this->setData( 'items', [ ['url' => '/shop', 'title' => 'Web-Shop'], ['url' => '/about', 'title' => 'Über uns'], ['url' => '/contact', 'title' => 'Kontakt-Formular'] ] );
Inhalt in das Eltern-Dokument, so kann dieser mit folgender Templating-Syntax zur Ausgabe der Liste genutzt werden:
APF-Template
<ul> <loop:template name="list" content-mapping="this->getParentObject()->getData('items')"> <li><a href="${content['url']}">${content['title']}</a></li> </loop:template> </ul>

Kommentare

Möchten Sie den Artikel eine Anmerkung hinzufügen, oder haben Sie ergänzende Hinweise? Dann können Sie diese hier einfügen. Die bereits verfassten Anmerkungen und Kommentare finden Sie in der untenstehenden Liste.
Für diesen Artikel liegen aktuell keine Kommentare vor.