Pratiques de développement

Installation

La meilleure façon d'installer Latte est d'utiliser Composer :

composer require latte/latte

Versions PHP supportées (s'applique aux dernières versions mineures de Latte) :

version compatible avec PHP
Latte 3.0 PHP 8.0 – 8.2

Comment rendre un template

Comment rendre un template ? Il suffit de ce simple code :

$latte = new Latte\Engine;
// répertoire pour le cache
$latte->setTempDirectory('/path/to/tempdir');

$params = [ /* variables du template */ ];
// ou $params = new TemplateParameters(/* ... */);

// rend vers la sortie
$latte->render('template.latte', $params);
// rend dans une variable
$output = $latte->renderToString('template.latte', $params);

Les paramètres peuvent être un tableau ou, encore mieux, un objet, qui assure le contrôle de type et l'autocomplétion dans les éditeurs.

Vous trouverez également des exemples d'utilisation dans le dépôt Latte examples.

Performance et cache

Les templates dans Latte sont extrêmement rapides, car Latte les compile directement en code PHP et les stocke dans un cache sur disque. Ils n'ont donc aucune surcharge par rapport aux templates écrits en PHP pur.

Le cache est automatiquement régénéré chaque fois que vous modifiez le fichier source. Ainsi, pendant le développement, vous pouvez confortablement éditer vos templates Latte et voir les changements immédiatement dans le navigateur. Vous pouvez désactiver cette fonctionnalité dans l'environnement de production pour économiser un peu de performance :

$latte->setAutoRefresh(false);

Lors du déploiement sur un serveur de production, la génération initiale du cache, en particulier pour les applications plus importantes, peut bien sûr prendre un certain temps. Latte intègre une prévention contre le cache stampede. Il s'agit d'une situation où un grand nombre de requêtes simultanées arrivent, déclenchant Latte, et comme le cache n'existe pas encore, toutes commenceraient à le générer en même temps. Ce qui surchargerait indûment le serveur. Latte est intelligent et, en cas de requêtes simultanées multiples, seul le premier thread génère le cache, les autres attendent puis l'utilisent.

Paramètres en tant que classe

Plutôt que de passer des variables au template sous forme de tableau, il est préférable de créer une classe. Vous obtiendrez ainsi une écriture typée, une autocomplétion agréable dans l'IDE et un moyen pour l'enregistrement des filtres et des fonctions.

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,
));

Désactivation de l'échappement automatique des variables

Si une variable contient une chaîne HTML, vous pouvez la marquer pour que Latte ne l'échappe pas automatiquement (et donc doublement). Vous éviterez ainsi d'avoir à utiliser |noescape dans le template.

Le moyen le plus simple est d'encapsuler la chaîne dans un objet Latte\Runtime\Html :

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

Latte n'échappe pas non plus tous les objets qui implémentent l'interface Latte\HtmlStringable. Vous pouvez ainsi créer votre propre classe dont la méthode __toString() retournera du code HTML qui ne sera pas automatiquement échappé :

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'),
];

La méthode __toString doit retourner du HTML correct et assurer l'échappement des paramètres, sinon une vulnérabilité XSS peut survenir !

Comment étendre Latte avec des filtres, des balises, etc.

Comment ajouter un filtre, une fonction, une balise personnalisée, etc. à Latte ? C'est ce que traite le chapitre étendre Latte. Si vous souhaitez réutiliser vos modifications dans différents projets ou les partager avec d'autres, vous devriez créer une extension.

Code arbitraire dans le template {php ...}

À l'intérieur de la balise {do}, seules les expressions PHP peuvent être écrites, vous ne pouvez donc pas insérer de constructions comme if ... else ou des instructions terminées par un point-virgule.

Cependant, vous pouvez enregistrer l'extension RawPhpExtension, qui ajoute la balise {php ...}. Grâce à elle, vous pouvez insérer n'importe quel code PHP. Aucune règle du mode sandbox ne s'applique à elle, son utilisation relève donc de la responsabilité de l'auteur du template.

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

Vérification du code généré

Latte compile les templates en code PHP. Bien sûr, il veille à ce que le code généré soit syntaxiquement valide. Cependant, lors de l'utilisation d'extensions tierces ou de RawPhpExtension, Latte ne peut garantir l'exactitude du fichier généré. Il est également possible d'écrire en PHP du code qui est syntaxiquement correct, mais interdit (par exemple, l'affectation d'une valeur à la variable $this) et provoque une erreur de compilation PHP (PHP Compile Error). Si vous écrivez une telle opération dans un template, elle se retrouvera également dans le code PHP généré. Comme il existe environ deux cents opérations interdites différentes en PHP, Latte n'a pas l'ambition de les détecter toutes. C'est PHP lui-même qui les signalera lors du rendu, ce qui n'est généralement pas un problème.

Cependant, il existe des situations où vous voulez savoir dès la compilation du template qu'il ne contient aucune erreur de compilation PHP. C'est notamment le cas si les templates peuvent être édités par les utilisateurs, ou si vous utilisez Sandbox. Dans ce cas, faites vérifier vos templates dès la compilation. Cette fonctionnalité est activée par la méthode Engine::enablePhpLint(). Comme elle nécessite d'appeler l'exécutable PHP pour la vérification, passez son chemin en paramètre :

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

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// capture les erreurs Latte et aussi les Compile Error en PHP
	echo 'Error: ' . $e->getMessage();
}

Paramètres régionaux

Latte permet de définir les paramètres régionaux, qui influencent le formatage des nombres, des dates et le tri. Ils sont définis à l'aide de la méthode setLocale(). L'identifiant des paramètres régionaux suit la norme IETF language tag, utilisée par l'extension PHP intl. Il se compose du code de langue et éventuellement du code de pays, par exemple en_US pour l'anglais aux États-Unis, de_DE pour l'allemand en Allemagne, etc.

$latte = new Latte\Engine;
$latte->setLocale('fr_FR'); // Exemple pour le français en France

La définition des paramètres régionaux affecte les filtres localDate, sort, number et bytes.

Nécessite l'extension PHP intl. La configuration dans Latte n'affecte pas les paramètres régionaux globaux de PHP.

Mode strict

En mode d'analyse strict, Latte vérifie si les balises HTML de fermeture ne manquent pas et interdit également l'utilisation de la variable $this. Activez-le comme suit :

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

Pour générer des templates avec l'en-tête declare(strict_types=1), activez-le comme suit :

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

Traduction dans les templates

Avec l'extension TranslatorExtension, vous ajoutez au template les balises {_...}, {translate} et le filtre translate. Ils servent à traduire des valeurs ou des parties du template dans d'autres langues. Comme paramètre, nous spécifions la méthode (PHP callable) effectuant la traduction :

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

	public function translate(string $original): string
	{
		// à partir de $original, nous créons $translated selon $this->lang
		return $translated;
	}
}

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

Le traducteur est appelé à l'exécution lors du rendu du template. Cependant, Latte peut traduire tous les textes statiques dès la compilation du template. Cela économise des performances, car chaque chaîne n'est traduite qu'une seule fois et la traduction résultante est écrite dans la forme compilée. Ainsi, dans le répertoire cache, plusieurs versions compilées du template sont créées, une pour chaque langue. Pour cela, il suffit de spécifier la langue comme deuxième paramètre :

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

Par texte statique, on entend par exemple {_'hello'} ou {translate}hello{/translate}. Les textes non statiques, comme {_$foo}, continueront d'être traduits à l'exécution.

Il est également possible de passer des paramètres supplémentaires au traducteur depuis le template en utilisant {_$original, foo: bar} ou {translate foo: bar}, qu'il recevra sous forme de tableau $params :

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

Débogage et Tracy

Latte essaie de rendre votre développement aussi agréable que possible. Directement à des fins de débogage, il existe un trio de balises {dump}, {debugbreak} et {trace}.

Vous obtiendrez le plus grand confort si vous installez également l'excellent outil de débogage Tracy et activez le plugin pour Latte :

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

$latte = new Latte\Engine;
// active l'extension pour Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Désormais, toutes les erreurs s'afficheront dans un écran rouge clair, y compris les erreurs dans les templates avec mise en évidence de la ligne et de la colonne (vidéo). En même temps, dans le coin inférieur droit, dans ce qu'on appelle la barre Tracy, un onglet pour Latte apparaîtra, où tous les templates rendus et leurs relations mutuelles sont clairement visibles (y compris la possibilité de cliquer pour accéder au template ou au code compilé) ainsi que les variables :

Comme Latte compile les templates en code PHP clair, vous pouvez facilement les parcourir pas à pas dans votre IDE.

Linter : validation de la syntaxe des templates

L'outil Linter vous aide à parcourir tous les templates et à vérifier s'ils contiennent des erreurs de syntaxe. Il se lance depuis la console :

vendor/bin/latte-lint <chemin>

Le paramètre --strict active le mode strict.

Si vous utilisez des balises personnalisées, créez également votre propre version du Linter, par ex. custom-latte-lint :

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

// spécifiez le chemin réel vers le fichier autoload.php
require __DIR__ . '/vendor/autoload.php';

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

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// ajoutez ici vos extensions individuelles
$latte->addExtension(/* ... */);

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

Alternativement, vous pouvez passer votre propre objet Latte\Engine au Linter :

$latte = new Latte\Engine;
// ici nous configurons l'objet $latte
$linter = new Latte\Tools\Linter(engine: $latte);

Chargement de templates depuis une chaîne

Avez-vous besoin de charger des templates à partir de chaînes plutôt que de fichiers, par exemple à des fins de test ? StringLoader vous aidera :

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

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

Gestionnaire d'exceptions

Vous pouvez définir votre propre gestionnaire pour les exceptions attendues. Les exceptions survenant à l'intérieur de {try} et dans le sandbox lui seront transmises.

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

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

Recherche automatique de layout

Avec la balise {layout}, le template spécifie son template parent. Il est également possible de laisser la recherche du layout se faire automatiquement, ce qui simplifie l'écriture des templates, car il ne sera pas nécessaire d'y inclure la balise {layout}.

Cela s'obtient de la manière suivante :

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// retourne le chemin vers le fichier de layout
		return 'automatic.layout.latte';
	}
};

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

Si le template ne doit pas avoir de layout, il l'indique avec la balise {layout none}.

version: 3.0