Praktiken für Entwickler

Installation

Der beste Weg, Latte zu installieren, ist die Verwendung eines Composers:

composer require latte/latte

Unterstützte PHP-Versionen (gilt für die neuesten Patch-Latte-Versionen):

Version kompatibel mit PHP
Latte 3.0 PHP 8.0 – 8.2

Wie man eine Vorlage rendert

Wie rendert man eine Vorlage? Verwenden Sie einfach diesen einfachen Code:

$latte = new Latte\Engine;
// Cache-Verzeichnis
$latte->setTempDirectory('/path/to/tempdir');

$params = [ /* Template-Variablen */ ];
// oder $params = new TemplateParameters(/* ... */);

// zur Ausgabe rendern
$latte->render('template.latte', $params);
// oder in eine Variable rendern
$output = $latte->renderToString('template.latte', $params);

Parameter können Arrays oder noch besser Objekte sein, die eine Typüberprüfung und Vorschläge im Editor bieten.

Anwendungsbeispiele finden Sie auch im Repository Latte examples.

Leistung und Caching

Latte-Vorlagen sind extrem schnell, weil Latte sie direkt in PHP-Code kompiliert und auf der Festplatte zwischenspeichert. Daher haben sie keinen zusätzlichen Overhead im Vergleich zu Vorlagen, die in reinem PHP geschrieben sind.

Der Cache wird jedes Mal automatisch neu generiert, wenn Sie die Quelldatei ändern. So können Sie Ihre Latte-Vorlagen bequem während der Entwicklung bearbeiten und die Änderungen sofort im Browser sehen. In einer Produktionsumgebung können Sie diese Funktion deaktivieren und so ein wenig Leistung einsparen:

$latte->setAutoRefresh(false);

Beim Einsatz auf einem Produktionsserver kann die anfängliche Cache-Generierung, insbesondere bei größeren Anwendungen, verständlicherweise eine Weile dauern. Latte hat einen eingebauten Schutz gegen Cache Stampede. Dabei handelt es sich um eine Situation, in der ein Server eine große Anzahl gleichzeitiger Anfragen erhält, die alle gleichzeitig generiert werden, da der Cache von Latte noch nicht vorhanden ist. Das belastet die CPU. Latte ist schlau, und wenn es mehrere gleichzeitige Anfragen gibt, erzeugt nur der erste Thread den Cache, die anderen warten und verwenden ihn dann.

Parameter als Klasse

Besser als Variablen als Arrays an die Vorlage zu übergeben ist es, eine Klasse zu erstellen. Sie erhalten eine typsichere Notation, nette Vorschläge in der IDE und eine Möglichkeit, Filter und Funktionen zu registrieren.

class MailTemplateParameters
{
	public function __construct(
		public string $lang,
		public Address $address,
		public string $subject,
		public array $items,
		public ?float $price = null,
	) {}
}

$latte->render('mail.latte', new MailTemplateParameters(
	lang: $this->lang,
	subject: $title,
	price: $this->getPrice(),
	items: [],
	address: $userAddress,
));

Auto-Escaping von Variablen deaktivieren

Wenn die Variable eine HTML-Zeichenkette enthält, können Sie sie so markieren, dass Latte sie nicht automatisch (und damit doppelt) umbricht. Auf diese Weise müssen Sie nicht |noescape in der Vorlage angeben.

Am einfachsten ist es, die Zeichenkette in ein Latte\Runtime\Html Objekt zu verpacken:

$params = [
	'articleBody' => new Latte\Runtime\Html($article->htmlBody),
];

Latte entschlüsselt auch nicht alle Objekte, die die Schnittstelle Latte\HtmlStringable implementieren. Sie können also eine eigene Klasse erstellen, deren Methode __toString() HTML-Code zurückgibt, der nicht automatisch escaped wird:

class Emphasis extends Latte\HtmlStringable
{
	public function __construct(
		private string $str,
	) {
	}

	public function __toString(): string
	{
		return '<em>' . htmlspecialchars($this->str) . '</em>';
	}
}

$params = [
	'foo' => new Emphasis('hello'),
];

Die Methode __toString muss korrektes HTML zurückgeben und die Parameter escapen, sonst kann eine XSS-Schwachstelle entstehen!

Wie man Latte mit Filtern, Tags, etc. erweitert

Wie fügt man Latte einen eigenen Filter, eine Funktion, ein Tag usw. hinzu? Das erfahren Sie im Kapitel Latte erweitern. Wenn Sie Ihre Änderungen in verschiedenen Projekten wiederverwenden oder sie mit anderen teilen wollen, sollten Sie eine Erweiterung erstellen.

Beliebiger Code in der Vorlage {php ...}

Nur PHP-Ausdrücke können innerhalb des {do} Tags geschrieben werden, d.h. Sie können z.B. keine Konstrukte wie if ... else oder mit Semikolon beendete Anweisungen einfügen.

Sie können jedoch die Erweiterung RawPhpExtension registrieren, die das Tag {php ...} hinzufügt. Damit können Sie beliebigen PHP-Code einfügen. Sie unterliegt nicht den Regeln des Sandbox-Modus, so dass die Verwendung in der Verantwortung des Vorlagenautors liegt.

$latte->addExtension(new Latte\Essential\RawPhpExtension);

Überprüfung von generiertem Code

Latte kompiliert Vorlagen in PHP-Code. Natürlich stellt es sicher, dass der generierte Code syntaktisch korrekt ist. Bei der Verwendung von Erweiterungen von Drittanbietern oder RawPhpExtension kann Latte jedoch nicht für die Korrektheit der generierten Datei garantieren. Außerdem können Sie in PHP Code schreiben, der zwar syntaktisch korrekt, aber verboten ist (z. B. Zuweisung eines Wertes an die Variable $this) und einen PHP-Kompilierfehler verursacht. Wenn Sie eine solche Operation in eine Vorlage schreiben, wird sie auch im generierten PHP-Code enthalten sein. Da es in PHP über zweihundert verschiedene verbotene Operationen gibt, ist es nicht das Ziel von Latte, diese zu erkennen. PHP selbst wird sie beim Rendern markieren, was normalerweise kein Problem darstellt.

Es gibt jedoch Situationen, in denen Sie während der Kompilierung der Vorlage wissen möchten, dass sie keine PHP-Kompilierungsfehler enthält. Vor allem, wenn die Vorlagen von Benutzern bearbeitet werden können oder Sie eine Sandbox verwenden. In einem solchen Fall sollten Sie die Vorlagen während der Kompilierung überprüfen lassen. Sie können diese Funktionalität mit der Methode Engine::enablePhpLint() aktivieren. Da sie für die Prüfung das PHP-Binary aufrufen muss, übergeben Sie dessen Pfad als Parameter:

$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// fängt Latte Fehler und auch Compile Fehler in PHP
	echo 'Error: ' . $e->getMessage();
}

Schauplatz

Mit Latte können Sie das Gebietsschema festlegen, das sich auf die Formatierung von Zahlen, Daten und die Sortierung auswirkt. Sie wird mit der Methode setLocale() festgelegt. Der Locale-Identifikator folgt dem IETF-Standard für Sprachtags, der die PHP-Erweiterung intl verwendet. Er besteht aus einem Sprachcode und möglicherweise einem Ländercode, z. B. en_US für Englisch in den Vereinigten Staaten, de_DE für Deutsch in Deutschland usw.

$latte = new Latte\Engine;
$latte->setLocale('cs');

Die Locale-Einstellung wirkt sich auf die Filter localDate, sort, number und bytes aus.

Erfordert die PHP-Erweiterung intl. Die Einstellung in Latte hat keinen Einfluss auf die globale Locale-Einstellung in PHP.

Strenger Modus

Im Strict-Parsing-Modus prüft Latte auf fehlende schließende HTML-Tags und deaktiviert die Verwendung der Variable $this. Um dies zu aktivieren:

$latte = new Latte\Engine;
$latte->setStrictParsing();

Um Vorlagen mit der Kopfzeile declare(strict_types=1) zu erzeugen, gehen Sie wie folgt vor:

$latte = new Latte\Engine;
$latte->setStrictTypes();

Übersetzung in Schablonen

Verwenden Sie die Erweiterung TranslatorExtension zum Hinzufügen von {_...}, {translate} und Filter translate zur Vorlage hinzuzufügen. Sie werden verwendet, um Werte oder Teile der Vorlage in andere Sprachen zu übersetzen. Der Parameter ist die Methode (PHP Callable), die die Übersetzung durchführt:

class MyTranslator
{
	public function __construct(private string $lang)
	{}

	public function translate(string $original): string
	{
		// $translated aus $original gemäß $this->lang erstellen
		return $translated;
	}
}

$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...), // [$translator, 'translate'] in PHP 8.0
);
$latte->addExtension($extension);

Der Übersetzer wird zur Laufzeit aufgerufen, wenn die Vorlage gerendert wird. Latte kann jedoch alle statischen Texte während der Kompilierung der Vorlage übersetzen. Dies spart Leistung, da jede Zeichenkette nur einmal übersetzt wird und die resultierende Übersetzung in die kompilierte Datei 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:

$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...),
	$lang,
);

Unter statischem Text verstehen wir z. B. {_'hello'} oder {translate}hello{/translate}. Nicht-statischer Text, wie z. B. {_$foo}, wird zur Laufzeit weiter übersetzt.

Die Vorlage kann dem Übersetzer auch zusätzliche Parameter über {_$original, foo: bar} oder {translate foo: bar} übergeben, die er als Array $params erhält:

public function translate(string $original, ...$params): string
{
	// $params['foo'] === 'bar'
}

Fehlersuche und Tracy

Latte versucht, die Entwicklung so angenehm wie möglich zu gestalten. Für die Fehlersuche gibt es drei Tags {dump}, {debugbreak} und {trace}.

Den größten Komfort erhalten Sie, wenn Sie das großartige Debugging-Tool Tracy installieren und das Latte-Plugin aktivieren:

// aktiviert Tracy
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// Aktiviert Tracys Nebenstelle
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Sie sehen nun alle Fehler in einem übersichtlichen roten Bildschirm, einschließlich Fehlern in Vorlagen mit Zeilen- und Spaltenhervorhebung (Video). Gleichzeitig erscheint unten rechts in der so genannten Tracy-Bar ein Reiter für Latte, in dem Sie alle gerenderten Vorlagen und ihre Beziehungen (einschließlich der Möglichkeit, in die Vorlage oder den kompilierten Code zu klicken) sowie die Variablen übersichtlich sehen können:

Da Latte die Vorlagen in lesbaren PHP-Code kompiliert, können Sie sie bequem in Ihrer IDE durchgehen.

Linter: Validierung der Vorlagensyntax

Das Tool Linter hilft Ihnen, alle Vorlagen durchzugehen und auf Syntaxfehler zu prüfen. Es wird von der Konsole aus gestartet:

vendor/bin/latte-lint <path>

Verwenden Sie den Parameter --strict, um den strengen Modus zu aktivieren.

Wenn Sie benutzerdefinierte Tags verwenden, erstellen Sie auch Ihren eigenen Linter, z. B. custom-latte-lint:

#!/usr/bin/env php
<?php

// den aktuellen Pfad zur Datei autoload.php eingeben
require __DIR__ . '/vendor/autoload.php';

$path = $argv[1] ?? '.';

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// fügen Sie hier Ihre individuellen Erweiterungen hinzu
$latte->addExtension(/* ... */);

$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);

Alternativ können Sie dem Linter auch Ihr eigenes Latte\Engine Objekt übergeben:

$latte = new Latte\Engine;
// hier konfigurieren wir das $latte-Objekt
$linter = new Latte\Tools\Linter(engine: $latte);

Laden von Templates aus einem String

Müssen Sie Vorlagen aus Strings statt aus Dateien laden, vielleicht zu Testzwecken? StringLoader wird Ihnen helfen:

$latte->setLoader(new Latte\Loaders\StringLoader([
	'main.file' => '{include other.file}',
	'other.file' => '{if true} {$var} {/if}',
]));

$latte->render('main.file', $params);

Exception Handler

Sie können Ihren eigenen Handler für erwartete Ausnahmen definieren. Ausnahmen, die innerhalb von {try} und in der Sandbox ausgelöste Ausnahmen werden an ihn übergeben.

$loggingHandler = function (Throwable $e, Latte\Runtime\Template $template) use ($logger) {
	$logger->log($e);
};

$latte = new Latte\Engine;
$latte->setExceptionHandler($loggingHandler);

Automatisches Layout-Lookup

Mit Hilfe des Tags {layout} bestimmt die Vorlage ihre übergeordnete Vorlage. Es ist auch möglich, das Layout automatisch suchen zu lassen, was das Schreiben von Vorlagen vereinfacht, da sie das Tag {layout} nicht enthalten müssen.

Dies wird wie folgt erreicht:

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// gibt er den Pfad zur übergeordneten Vorlagendatei zurück
		return 'automatic.layout.latte';
	}
};

$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);

Wenn die Vorlage kein Layout haben soll, wird dies mit dem Tag {layout none} angezeigt.

Version: 3.0