Entwicklerpraktiken
Installation
Der beste Weg, Latte zu installieren, ist über Composer:
composer require latte/latte
Unterstützte PHP-Versionen (gilt für die letzten Patch-Versionen von Latte):
Version | Kompatibel mit PHP |
---|---|
Latte 3.0 | PHP 8.0 – 8.2 |
Wie rendert man ein Template?
Wie rendert man ein Template? Dafür genügt dieser einfache Code:
$latte = new Latte\Engine;
// Verzeichnis für den Cache
$latte->setTempDirectory('/path/to/tempdir');
$params = [ /* Template-Variablen */ ];
// oder $params = new TemplateParameters(/* ... */);
// in die Ausgabe rendern
$latte->render('template.latte', $params);
// in eine Variable rendern
$output = $latte->renderToString('template.latte', $params);
Parameter können Arrays sein oder noch besser ein Objekt, das Typprüfung und Autovervollständigung in Editoren sicherstellt.
Anwendungsbeispiele finden Sie auch im Repository Latte examples.
Leistung und Cache
Templates in Latte sind extrem schnell, da Latte sie direkt in PHP-Code kompiliert und auf der Festplatte zwischenspeichert. Sie haben also keinen zusätzlichen Overhead gegenüber Templates, die in reinem PHP geschrieben sind.
Der Cache wird automatisch jedes Mal neu generiert, wenn Sie die Quelldatei ändern. Während der Entwicklung können Sie also bequem Ihre Latte-Templates bearbeiten und die Änderungen sofort im Browser sehen. Sie können diese Funktion in der Produktionsumgebung deaktivieren, um ein wenig Leistung zu sparen:
$latte->setAutoRefresh(false);
Bei der Bereitstellung auf einem Produktionsserver kann die anfängliche Generierung des Caches, insbesondere bei größeren Anwendungen, natürlich einen Moment dauern. Latte verfügt über eine integrierte Prävention gegen Cache Stampede. Dies ist eine Situation, in der eine größere Anzahl gleichzeitiger Anfragen eintrifft, die Latte starten, und da der Cache noch nicht existiert, würden sie alle gleichzeitig mit der Generierung beginnen. Dies würde den Server unverhältnismäßig belasten. Latte ist intelligent und bei mehreren gleichzeitigen Anfragen generiert nur der erste Thread den Cache, die anderen warten und nutzen ihn anschließend.
Parameter als Klasse
Besser als Variablen als Array an das Template zu übergeben, ist es, eine Klasse zu erstellen. Sie erhalten so eine typsichere Schreibweise, angenehme Autovervollständigung in IDEs und einen Weg zur Registrierung von Filtern und Funktionen.
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,
));
Deaktivieren des automatischen Escapings einer Variablen
Wenn eine Variable eine Zeichenkette in HTML enthält, können Sie sie so markieren, dass Latte sie nicht automatisch (und
somit doppelt) escapet. Sie vermeiden so die Notwendigkeit, |noescape
im Template anzugeben.
Der einfachste Weg ist, die Zeichenkette in ein Latte\Runtime\Html
-Objekt zu verpacken:
$params = [
'articleBody' => new Latte\Runtime\Html($article->htmlBody),
];
Latte escapet außerdem keine Objekte, die das Interface Latte\HtmlStringable
implementieren. Sie können also
eine eigene Klasse erstellen, deren __toString()
-Methode HTML-Code zurückgibt, der nicht automatisch
escapet 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 __toString
-Methode muss korrektes HTML zurückgeben und das Escaping von Parametern
sicherstellen, andernfalls kann eine XSS-Schwachstelle entstehen!
Wie erweitert man Latte um Filter, Tags usw.?
Wie fügt man Latte eigene Filter, Funktionen, Tags usw. hinzu? Dies wird im Kapitel Latte erweitern behandelt. Wenn Sie Ihre Anpassungen in verschiedenen Projekten wiederverwenden oder mit anderen teilen möchten, sollten Sie eine Erweiterung erstellen.
Beliebiger Code im Template {php ...}
Innerhalb des Tags {do}
können nur PHP-Ausdrücke
geschrieben werden, Sie können also keine Konstrukte wie if ... else
oder Anweisungen, die mit einem Semikolon
enden, 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. Für ihn gelten keine Sandbox-Regeln, die Verwendung liegt also in der
Verantwortung des Template-Autors.
$latte->addExtension(new Latte\Essential\RawPhpExtension);
Überprüfung des generierten Codes
Latte kompiliert Templates in PHP-Code. Natürlich achtet es darauf, dass der generierte Code syntaktisch valide ist. Bei
Verwendung von Drittanbieter-Erweiterungen oder RawPhpExtension
kann Latte jedoch die Korrektheit der generierten
Datei nicht garantieren. Außerdem kann man in PHP Code schreiben, der zwar syntaktisch korrekt ist, aber verboten ist (z. B.
Zuweisung eines Wertes zur Variablen $this
) und einen PHP Compile Error verursacht. Wenn Sie eine solche Operation im
Template schreiben, gelangt sie auch in den generierten PHP-Code. Da es in PHP über zweihundert verschiedene verbotene
Operationen gibt, hat Latte nicht den Ehrgeiz, sie alle aufzudecken. PHP selbst weist erst beim Rendern darauf hin, was
normalerweise kein Problem darstellt.
Es gibt jedoch Situationen, in denen Sie bereits zur Kompilierungszeit des Templates wissen möchten, dass es keinen PHP
Compile Error enthält. Insbesondere dann, wenn Templates von Benutzern bearbeitet werden können oder Sie die Sandbox verwenden. In diesem Fall lassen Sie die Templates bereits zur
Kompilierungszeit überprüfen. Diese Funktionalität aktivieren Sie mit der Methode Engine::enablePhpLint()
. Da zur
Überprüfung die PHP-Binärdatei aufgerufen werden muss, übergeben Sie den Pfad dorthin als Parameter:
$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');
try {
$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
// fängt Fehler in Latte und auch Compile Errors in PHP ab
echo 'Error: ' . $e->getMessage();
}
Spracheinstellung
Latte ermöglicht die Einstellung der Spracheinstellung, die die Formatierung von Zahlen, Daten und die Sortierung beeinflusst.
Sie wird mit der Methode setLocale()
eingestellt. Der Sprachbezeichner folgt dem IETF-Sprach-Tag-Standard, der von
der PHP-Erweiterung intl
verwendet wird. Er besteht aus dem Sprachcode und optional dem 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('de'); // Deutsch
Die Spracheinstellung beeinflusst die Filter localDate, sort, number und bytes.
Erfordert die PHP-Erweiterung intl
. Die Einstellung in Latte beeinflusst nicht die globale
Locale-Einstellung in PHP.
Strikter Modus
Im strikten Parsing-Modus prüft Latte, ob schließende HTML-Tags fehlen und verbietet außerdem die Verwendung der Variablen
$this
. Sie aktivieren ihn so:
$latte = new Latte\Engine;
$latte->setStrictParsing();
Die Generierung von Templates mit dem Header declare(strict_types=1)
aktivieren Sie so:
$latte = new Latte\Engine;
$latte->setStrictTypes();
Übersetzung in Templates
Mit der Erweiterung TranslatorExtension
fügen Sie dem Template die Tags {_...}
, {translate}
und den Filter translate
hinzu. Sie dienen zur Übersetzung von Werten
oder Teilen des Templates in andere Sprachen. Als Parameter geben wir eine Methode (PHP callable) an, die die Übersetzung
durchführt:
class MyTranslator
{
public function __construct(private string $lang)
{}
public function translate(string $original): string
{
// aus $original erstellen wir $translated gemäß $this->lang
return $translated;
}
}
$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
$translator->translate(...), // [$translator, 'translate'] in PHP 8.0
);
$latte->addExtension($extension);
Der Translator wird zur Laufzeit beim Rendern des Templates aufgerufen. Latte kann jedoch alle statischen Texte bereits während der Kompilierung des Templates übersetzen. Dadurch wird Leistung gespart, da jede Zeichenkette nur einmal übersetzt wird und die resultierende Übersetzung in die kompilierte Form geschrieben wird. Im Cache-Verzeichnis entstehen so mehrere kompilierte Versionen des Templates, eine für jede Sprache. Dazu genügt es, die Sprache als zweiten Parameter anzugeben:
$extension = new Latte\Essential\TranslatorExtension(
$translator->translate(...),
$lang,
);
Statischer Text bedeutet z. B. {_'hello'}
oder {translate}hello{/translate}
. Nicht-statische Texte,
wie z. B. {_$foo}
, werden weiterhin zur Laufzeit übersetzt.
Dem Übersetzer können aus dem Template auch zusätzliche Parameter übergeben werden, mittels
{_$original, foo: bar}
oder {translate foo: bar}
, die er als Array $params
erhält:
public function translate(string $original, ...$params): string
{
// $params['foo'] === 'bar'
}
Debugging und Tracy
Latte versucht Ihnen die Entwicklung so angenehm wie möglich zu gestalten. Direkt für Debugging-Zwecke gibt es drei Tags: {dump}
, {debugbreak}
und {trace}
.
Den größten Komfort erhalten Sie, wenn Sie zusätzlich das hervorragende Debugging-Werkzeug Tracy installieren und das Add-on für Latte aktivieren:
// schaltet Tracy ein
Tracy\Debugger::enable();
$latte = new Latte\Engine;
// aktiviert die Erweiterung für Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
Nun werden Ihnen alle Fehler in einem übersichtlichen roten Bildschirm angezeigt, einschließlich Fehlern in Templates mit Hervorhebung von Zeile und Spalte (Video). Gleichzeitig erscheint unten rechts in der sogenannten Tracy Bar ein Tab für Latte, wo alle gerenderten Templates und ihre gegenseitigen Beziehungen übersichtlich dargestellt werden (einschließlich der Möglichkeit, zum Template oder zum kompilierten Code durchzuklicken) sowie die Variablen:

Da Latte Templates in übersichtlichen PHP-Code kompiliert, können Sie sie bequem in Ihrer IDE schrittweise debuggen.
Linter: Syntaxvalidierung von Templates
Um alle Templates durchzugehen und zu überprüfen, ob sie Syntaxfehler enthalten, hilft Ihnen das Werkzeug Linter. Es wird von der Konsole aus gestartet:
vendor/bin/latte-lint <pfad>
Mit dem Parameter --strict
aktivieren Sie den strikten Modus.
Wenn Sie eigene Tags verwenden, erstellen Sie sich auch eine eigene Version des Linters, z. B.
custom-latte-lint
:
#!/usr/bin/env php
<?php
// Geben Sie den tatsächlichen Pfad zur Datei autoload.php an
require __DIR__ . '/vendor/autoload.php';
$path = $argv[1] ?? '.';
$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// hier fügen Sie Ihre einzelnen Erweiterungen hinzu
$latte->addExtension(/* ... */);
$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);
Alternativ können Sie ein eigenes Latte\Engine
-Objekt an den Linter übergeben:
$latte = new Latte\Engine;
// hier konfigurieren wir das Objekt $latte
$linter = new Latte\Tools\Linter(engine: $latte);
Laden von Templates aus einer Zeichenkette
Müssen Sie Templates aus Zeichenketten anstelle von Dateien laden, z. B. zu Testzwecken? Der StringLoader hilft Ihnen dabei:
$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 einen eigenen Handler für erwartete Ausnahmen definieren. Ihm werden Ausnahmen übergeben, die innerhalb von {try}
und in der Sandbox entstehen.
$loggingHandler = function (Throwable $e, Latte\Runtime\Template $template) use ($logger) {
$logger->log($e);
};
$latte = new Latte\Engine;
$latte->setExceptionHandler($loggingHandler);
Automatisches Suchen des Layouts
Mit dem Tag {layout}
bestimmt ein Template sein übergeordnetes Template. Es ist auch möglich, das Layout automatisch suchen zu lassen, was das
Schreiben von Templates vereinfacht, da das Tag {layout}
darin nicht notwendig ist.
Dies wird auf folgende Weise erreicht:
$finder = function (Latte\Runtime\Template $template) {
if (!$template->getReferenceType()) {
// gibt den Pfad zur Layout-Datei zurück
return 'automatic.layout.latte';
}
};
$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);
Wenn ein Template kein Layout haben soll, teilt es dies mit dem Tag {layout none}
mit.