Pratiques pour les développeurs

Installation

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

composer require latte/latte

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

version compatible avec PHP
PHP 8.0 – 8.2 – Latte 3.0 – PHP 8.0 – 8.2  

Comment rendre un modèle

Comment rendre un modèle ? Il suffit d'utiliser ce code simple :

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

$params = [ /* variables de modèle */ ];
// ou $params = new TemplateParameters(/* ... */);

// rendre vers la sortie
$latte->render('template.latte', $params);
// ou rendu vers la variable
$output = $latte->renderToString('template.latte', $params);

Les paramètres peuvent être des tableaux ou mieux encore des objets, ce qui permettra de vérifier et de suggérer le type dans l'éditeur.

Vous pouvez également trouver des exemples d'utilisation dans le référentiel Latte examples.

Performances et mise en cache

Les modèles Latte sont extrêmement rapides, car Latte les compile directement en code PHP et les met en cache sur le disque. Ainsi, ils n'ont pas de surcharge supplémentaire par rapport aux modèles écrits en PHP pur.

Le cache est automatiquement régénéré chaque fois que vous modifiez le fichier source. Vous pouvez donc facilement modifier vos modèles Latte pendant le développement et voir les changements immédiatement dans le navigateur. Vous pouvez désactiver cette fonction dans un environnement de production et économiser un peu de performance :

$latte->setAutoRefresh(false);

Lorsqu'elle est déployée sur un serveur de production, la génération initiale du cache, en particulier pour les grandes applications, peut naturellement prendre un certain temps. Latte a une prévention intégrée contre la ruée vers le cache. Il s'agit d'une situation où le serveur reçoit un grand nombre de demandes simultanées et, comme le cache de Latte n'existe pas encore, elles le génèrent toutes en même temps. Ce qui fait grimper le CPU en flèche. Latte est intelligent, et lorsqu'il y a plusieurs demandes simultanées, seul le premier thread génère le cache, les autres attendent et l'utilisent ensuite.

Paramètres en tant que classe

Il est préférable de créer une classe plutôt que de transmettre des variables au modèle sous forme de tableaux. Vous obtenez une notation sûre, une suggestion agréable dans l'IDE et un moyen d'enregistrer 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ésactiver l'échappement automatique d'une variable

Si la variable contient une chaîne HTML, vous pouvez la marquer pour que Latte ne l'échappe pas automatiquement (et donc doublement). Cela évite d'avoir à spécifier |noescape dans le modèle.

La méthode la plus simple consiste à envelopper 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 donc créer votre propre classe dont la méthode __toString() renverra du code HTML qui ne sera pas échappé automatiquement :

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 fournir l'échappement des paramètres, sinon une vulnérabilité XSS peut se produire !

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

Comment ajouter un filtre, une fonction, une balise, etc. personnalisés à Latte ? Découvrez-le dans le chapitre consacré à l'extension de Latte. Si vous voulez réutiliser vos modifications dans différents projets ou si vous voulez les partager avec d'autres, vous devez alors créer une extension.

Tout code dans le modèle {php ...}

Seules les expressions PHP peuvent être écrites à l'intérieur de la balise {do} Vous ne pouvez donc pas, par exemple, insérer des constructions comme if ... else ou des déclarations terminées par un point-virgule.

Cependant, vous pouvez enregistrer l'extension RawPhpExtension, qui ajoute la balise {php ...}. Vous pouvez l'utiliser pour insérer n'importe quel code PHP. Elle n'est soumise à aucune règle du mode “bac à sable”, et son utilisation relève donc de la responsabilité de l'auteur du modèle.

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

Vérification du code généré

Latte compile les modèles en code PHP. Bien sûr, il s'assure que le code généré est syntaxiquement valide. Cependant, lors de l'utilisation d'extensions tierces ou de RawPhpExtension, Latte ne peut pas garantir l'exactitude du fichier généré. De plus, en PHP, vous pouvez écrire du code syntaxiquement correct mais interdit (par exemple, assigner une valeur à la variable $this) et provoquer une erreur de compilation PHP. Si vous écrivez une telle opération dans un modèle, elle sera également incluse dans le code PHP généré. Comme il existe plus de deux cents opérations interdites en PHP, Latte ne cherche pas à les détecter. PHP lui-même les signalera lors du rendu, ce qui ne pose généralement pas de problème.

Cependant, il y a des situations où vous voulez savoir pendant la compilation du modèle qu'il ne contient pas d'erreurs de compilation PHP. En particulier lorsque les modèles peuvent être édités par des utilisateurs, ou que vous utilisez Sandbox. Dans ce cas, faites vérifier les modèles pendant la compilation. Vous pouvez activer cette fonctionnalité en utilisant la méthode Engine::enablePhpLint(). Puisqu'elle doit appeler le binaire 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) {
	// attrape les erreurs de latte et aussi les erreurs de compilation en PHP
	echo 'Error: ' . $e->getMessage();
}

Locale

Latte vous permet de définir la locale, qui affecte le formatage des nombres, des dates et des tris. Elle est définie à l'aide de la méthode setLocale(). L'identifiant de la locale suit la norme de balise de langue de l'IETF, qui utilise l'extension PHP intl. Il se compose d'un code de langue et éventuellement d'un 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('cs');

Les paramètres linguistiques affectent les filtres localDate, sort, number et bytes.

Nécessite l'extension PHP intl. Les paramètres de Latte n'affectent pas les paramètres linguistiques globaux de PHP.

Mode strict

En mode d'analyse stricte, Latte vérifie l'absence de balises HTML fermantes et désactive l'utilisation de la variable $this. Pour l'activer :

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

Pour générer des modèles avec l'en-tête declare(strict_types=1), procédez comme suit :

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

Traduction dans les modèles

Utilisez l'extension TranslatorExtension pour ajouter {_...}, {translate} et le filtre translate au modèle. Ils sont utilisés pour traduire des valeurs ou des parties du modèle dans d'autres langues. Le paramètre est la méthode (appelable en PHP) qui effectue la traduction :

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

	public function translate(string $original): string
	{
		// créer $translated à partir de $original en fonction de $this->langue
		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é au moment de l'exécution lorsque le modèle est rendu. Cependant, Latte peut traduire tous les textes statiques pendant la compilation du modèle. Cela permet de gagner en performance car chaque chaîne n'est traduite qu'une seule fois et la traduction résultante est écrite dans le fichier compilé. Cela crée plusieurs versions compilées du modèle dans le répertoire de cache, une pour chaque langue. Pour ce faire, il suffit de spécifier la langue comme deuxième paramètre :

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

Par texte statique, nous entendons, par exemple, {_'hello'} ou {translate}hello{/translate}. Le texte non statique, tel que {_$foo}, continuera à être traduit au moment de l'exécution.

Le modèle peut également transmettre des paramètres supplémentaires au traducteur via {_$original, foo: bar} ou {translate foo: bar}, qu'il reçoit dans le tableau $params:

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

Débogage et Tracy

Latte essaie de rendre le développement aussi agréable que possible. Pour le débogage, il existe trois balises {dump}, {debugbreak} et {trace}.

Vous obtiendrez plus de confort en installant l'excellent outil de débogage Tracy et en activant le plugin Latte :

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

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

Vous verrez alors toutes les erreurs dans un écran rouge soigné, y compris les erreurs dans les modèles avec mise en évidence des lignes et des colonnes (vidéo). En même temps, dans le coin inférieur droit de la barre Tracy, un onglet pour Latte apparaît, où vous pouvez voir clairement tous les modèles rendus et leurs relations (y compris la possibilité de cliquer dans le modèle ou le code compilé), ainsi que les variables :

Comme Latte compile les modèles en code PHP lisible, vous pouvez facilement les parcourir dans votre IDE.

Linter : Validation de la syntaxe du modèle

L'outil Linter vous aidera à passer en revue tous les modèles et à vérifier les erreurs de syntaxe. Il est lancé à partir de la console :

vendor/bin/latte-lint <path>

Utilisez le paramètre --strict pour activer le mode strict.

Si vous utilisez des balises personnalisées, créez également votre Linter personnalisé, par exemple custom-latte-lint:

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

// entrez le chemin d'accès au fichier autoload.php
require __DIR__ . '/vendor/autoload.php';

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

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

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

Vous pouvez également transmettre votre propre objet Latte\Engine au Linter :

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

Chargement de modèles à partir d'une chaîne

Vous avez besoin de charger des modèles à partir de chaînes de caractères plutôt que de fichiers, peut-être à 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 levées dans {try} et dans le bac à sable lui sont transmises.

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

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

Recherche automatique de mise en page

En utilisant la balise {layout} le modèle détermine son modèle parent. Il est également possible de faire en sorte que la mise en page soit recherchée automatiquement, ce qui simplifiera l'écriture des modèles puisqu'ils n'auront pas besoin d'inclure la balise {layout}.

Cela s'effectue comme suit :

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// il renvoie le chemin d'accès au fichier modèle parent
		return 'automatic.layout.latte';
	}
};

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

Si le modèle ne doit pas avoir de mise en page, il l'indique avec la balise {layout none}.

version: 3.0