Vorlagen

Nette verwendet das Vorlagensystem Latte. Latte wird verwendet, weil es das sicherste Vorlagensystem für PHP und gleichzeitig das intuitivste System ist. Sie müssen nicht viel Neues lernen, Sie müssen nur PHP und ein paar Latte-Tags kennen.

In der Regel wird die Seite aus der Layout-Vorlage und der Aktionsvorlage erstellt. So könnte eine Layout-Vorlage aussehen, beachten Sie die Blöcke {block} und den Tag {include}:

<!DOCTYPE html>
<html>
<head>
	<title>{block title}My App{/block}</title>
</head>
<body>
	<header>...</header>
	{include content}
	<footer>...</footer>
</body>
</html>

Und dies könnte die Aktionsvorlage sein:

{block title}Homepage{/block}

{block content}
<h1>Homepage</h1>
...
{/block}

Sie definiert den Block content, der anstelle von {include content} in das Layout eingefügt wird, und definiert auch den Block title neu, der {block title} im Layout überschreibt. Versuchen Sie, sich das Ergebnis vorzustellen.

Vorlage nachschlagen

In Presentern müssen Sie nicht angeben, welche Vorlage gerendert werden soll; das Framework bestimmt den Pfad automatisch, was die Codierung für Sie einfacher macht.

Wenn Sie eine Verzeichnisstruktur verwenden, in der jeder Präsentator sein eigenes Verzeichnis hat, legen Sie die Vorlage einfach in diesem Verzeichnis unter dem Namen der Aktion (d. h. der Ansicht) ab. Verwenden Sie zum Beispiel für die Aktion default die Vorlage default.latte:

app/
└── UI/
    └── Home/
        ├── HomePresenter.php
        └── default.latte

Wenn Sie eine Struktur verwenden, bei der sich die Präsentatoren in einem Verzeichnis und die Vorlagen in einem Ordner templates befinden, speichern Sie sie entweder in einer Datei <Presenter>.<view>.latte oder <Presenter>/<view>.latte:

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── Home.default.latte  ← 1st variant
        └── Home/
            └── default.latte   ← 2nd variant

Das Verzeichnis templates kann auch eine Ebene höher platziert werden, auf derselben Ebene wie das Verzeichnis mit den Presenter-Klassen.

Wenn die Vorlage nicht gefunden wird, antwortet der Präsentator mit dem Fehler 404 – Seite nicht gefunden.

Sie können die Ansicht mit $this->setView('anotherView') ändern. Es ist auch möglich, die Vorlagendatei direkt mit $this->template->setFile('/path/to/template.latte') anzugeben.

Dateien, in denen Vorlagen gesucht werden, können durch Überschreiben der Methode formatTemplateFiles() geändert werden, die ein Array mit möglichen Dateinamen zurückgibt.

Layout-Vorlagen-Suche

Nette sucht auch automatisch nach der Layout-Datei.

Wenn Sie eine Verzeichnisstruktur verwenden, in der jeder Präsentator sein eigenes Verzeichnis hat, legen Sie das Layout entweder in dem Ordner mit dem Präsentator ab, wenn es nur für diesen spezifisch ist, oder eine Ebene höher, wenn es für mehrere Präsentatoren gemeinsam ist:

app/
└── UI/
    ├── @layout.latte           ← common layout
    └── Home/
        ├── @layout.latte       ← only for Home presenter
        ├── HomePresenter.php
        └── default.latte

Wenn Sie eine Struktur verwenden, bei der die Vortragenden in einem Verzeichnis zusammengefasst sind und sich die Vorlagen in einem Ordner templates befinden, wird das Layout an den folgenden Stellen erwartet:

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── @layout.latte       ← common layout
        ├── Home.@layout.latte  ← only for Home, 1st variant
        └── Home/
            └── @layout.latte   ← only for Home, 2nd variant

Befindet sich der Präsentator in einem Modul, wird er auch weiter oben im Verzeichnisbaum entsprechend der Verschachtelung des Moduls gesucht.

Der Name des Layouts kann mit $this->setLayout('layoutAdmin') geändert werden und wird dann in der Datei @layoutAdmin.latte erwartet. Sie können die Layout-Vorlagendatei auch direkt mit $this->setLayout('/path/to/template.latte') angeben.

Die Verwendung von $this->setLayout(false) oder des Tags {layout none} innerhalb der Vorlage deaktiviert die Layout-Suche.

Die Dateien, in denen Layoutvorlagen gesucht werden, können durch Überschreiben der Methode formatLayoutTemplateFiles() geändert werden, die ein Array mit möglichen Dateinamen zurückgibt.

Variablen in der Vorlage

Variablen werden an die Vorlage übergeben, indem sie in $this->template geschrieben werden, und sind dann in der Vorlage als lokale Variablen verfügbar:

$this->template->article = $this->articles->getById($id);

Auf diese Weise können wir problemlos beliebige Variablen an die Vorlagen übergeben. Bei der Entwicklung robuster Anwendungen ist es jedoch oft sinnvoller, sich einzuschränken. Zum Beispiel durch die explizite Definition einer Liste von Variablen, die die Vorlage erwartet, und deren Typen. Auf diese Weise kann PHP eine Typüberprüfung durchführen, die IDE eine korrekte Autovervollständigung vornehmen und die statische Analyse Fehler erkennen.

Und wie definieren wir eine solche Aufzählung? Einfach in Form einer Klasse und ihrer Eigenschaften. Wir nennen sie ähnlich wie presenter, aber mit Template am Ende:

/**
 * @property-read ArticleTemplate $template
 */
class ArticlePresenter extends Nette\Application\UI\Presenter
{
}

class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
	public Model\Article $article;
	public Nette\Security\User $user;

	// und andere Variablen
}

Das Objekt $this->template im Presenter wird nun eine Instanz der Klasse ArticleTemplate sein. PHP wird also die deklarierten Typen überprüfen, wenn sie geschrieben werden. Und ab PHP 8.2 wird auch vor dem Schreiben in eine nicht existierende Variable gewarnt. In früheren Versionen kann dasselbe mit der Nette\SmartObject-Eigenschaft erreicht werden.

Die @property-read Annotation ist für die IDE und die statische Analyse, sie sorgt dafür, dass die Autovervollständigung funktioniert, siehe PhpStorm and code completion for $this->template.

Sie können sich auch den Luxus gönnen, in Vorlagen zu flüstern. Installieren Sie einfach das Latte-Plugin in PhpStorm und geben Sie den Klassennamen am Anfang der Vorlage an, siehe den Artikel Latte: how to type system:

{templateType App\UI\Article\ArticleTemplate}
...

So funktionieren Templates auch in Komponenten, folgen Sie einfach der Namenskonvention und erstellen Sie eine Template-Klasse FifteenTemplate für die Komponente, z.B. FifteenControl.

Wenn Sie eine $template als Instanz einer anderen Klasse erstellen müssen, verwenden Sie die Methode createTemplate():

public function renderDefault(): void
{
	$template = $this->createTemplate(SpecialTemplate::class);
	$template->foo = 123;
	// ...
	$this->sendTemplate($template);
}

Standard-Variablen

Presenter und Komponenten übergeben automatisch mehrere nützliche Variablen an Vorlagen:

  • $basePath ist ein absoluter URL-Pfad zum Stammverzeichnis (z. B. /CD-collection)
  • $baseUrl ist eine absolute URL zum Stammverzeichnis (z. B. http://localhost/CD-collection)
  • $user ist ein Objekt , das den Benutzer repräsentiert
  • $presenter ist der aktuelle Präsentator
  • $control ist die aktuelle Komponente oder der aktuelle Präsentator
  • $flashes Liste der von der Methode gesendeten Nachrichten flashMessage()

Wenn Sie eine benutzerdefinierte Vorlagenklasse verwenden, werden diese Variablen übergeben, wenn Sie eine Eigenschaft für sie erstellen.

In der Vorlage erstellen wir Links zu anderen Präsentatoren und Aktionen wie folgt:

<a n:href="Product:show">detail</a>

Das Attribut n:href ist sehr praktisch für HTML-Tags <a>. Wenn wir den Link an anderer Stelle, zum Beispiel im Text, ausgeben wollen, verwenden wir {link}:

URL is: {link Home:default}

Weitere Informationen finden Sie unter Links erstellen.

Benutzerdefinierte Filter, Tags, etc.

Das Latte-Vorlagensystem kann mit benutzerdefinierten Filtern, Funktionen, Tags usw. erweitert werden. Dies kann direkt in der render<View> oder beforeRender() Methode erfolgen:

public function beforeRender(): void
{
	// Hinzufügen eines Filters
	$this->template->addFilter('foo', /* ... */);

	// oder das Latte\Engine-Objekt direkt konfigurieren
	$latte = $this->template->getLatte();
	$latte->addFilterLoader(/* ... */);
}

Latte Version 3 bietet einen fortgeschritteneren Weg, indem es eine Erweiterung für jedes Webprojekt erstellt. Hier ist ein grobes Beispiel für eine solche Klasse:

namespace App\UI\Accessory;

final class LatteExtension extends Latte\Extension
{
	public function __construct(
		private App\Model\Facade $facade,
		private Nette\Security\User $user,
		// ...
	) {
	}

	public function getFilters(): array
	{
		return [
			'timeAgoInWords' => $this->filterTimeAgoInWords(...),
			'money' => $this->filterMoney(...),
			// ...
		];
	}

	public function getFunctions(): array
	{
		return [
			'canEditArticle' =>
				fn($article) => $this->facade->canEditArticle($article, $this->user->getId()),
			// ...
		];
	}

	// ...
}

Wir registrieren sie mit configuration:

latte:
	extensions:
		- App\UI\Accessory\LatteExtension

Übersetzen

Wenn Sie eine mehrsprachige Anwendung programmieren, werden Sie wahrscheinlich einen Teil des Textes in der Vorlage in verschiedenen Sprachen ausgeben müssen. Zu diesem Zweck definiert das Nette Framework eine Übersetzungsschnittstelle Nette\Localization\Translator, die über eine einzige Methode translate() verfügt. Diese akzeptiert die Nachricht $message, bei der es sich in der Regel um eine Zeichenkette handelt, und beliebige andere Parameter. Die Aufgabe besteht darin, die übersetzte Zeichenkette zurückzugeben. Es gibt keine Standardimplementierung in Nette, Sie können nach Ihren Bedürfnissen aus mehreren fertigen Lösungen wählen, die Sie auf Componette finden. Die Dokumentation erklärt Ihnen, wie Sie den Übersetzer konfigurieren können.

Vorlagen können mit einem Übersetzer eingerichtet werden, den wir mit der Methode setTranslator() an uns übergeben:

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator);
}

Alternativ kann der Übersetzer auch über die Konfiguration eingestellt werden:

latte:
	extensions:
		- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)

Der Übersetzer kann dann z.B. als Filter |translate verwendet werden, wobei zusätzliche Parameter an die Methode translate() übergeben werden (siehe foo, bar):

<a href="basket">{='Basket'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>

Oder als Unterstrich-Tag:

<a href="basket">{_'Basket'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>

Für die Übersetzung von Vorlagenabschnitten gibt es ein gepaartes Tag {translate} (seit Latte 2.11, vorher wurde das Tag {_} verwendet):

<a href="order">{translate}Order{/translate}</a>
<a href="order">{translate foo, bar}Order{/translate}</a>

Der Translator wird standardmäßig zur Laufzeit beim Rendern der Vorlage aufgerufen. Latte Version 3 kann jedoch den gesamten statischen Text während der Kompilierung der Vorlage übersetzen. Dies spart Leistung, da jede Zeichenkette nur einmal übersetzt wird und die resultierende Übersetzung in das kompilierte Formular geschrieben wird. Dadurch werden mehrere kompilierte Versionen der Vorlage im Cache-Verzeichnis erstellt, eine für jede Sprache. Dazu müssen Sie nur die Sprache als zweiten Parameter angeben:

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator, $lang);
}

Unter statischem Text verstehen wir z. B. {_'hello'} oder {translate}hello{/translate}. Nicht-statischer Text, wie z. B. {_$foo}, wird weiterhin im laufenden Betrieb kompiliert.

Version: 4.0