Nette Documentation Preview

syntax
Étendre Latte
*************

.[perex]
Latte est conçu pour être extensible. Si son jeu standard de balises, de filtres et de fonctions couvre déjà beaucoup de cas, vous avez souvent besoin d'ajouter votre propre logique ou vos propres utilitaires. Cette page donne un aperçu des façons d'étendre Latte pour coller parfaitement aux besoins de votre projet, du simple utilitaire à la nouvelle syntaxe complexe.


Façons d'étendre Latte
======================

Voici un aperçu rapide des principaux moyens de personnaliser et d'étendre Latte :

- **[Filtres personnalisés|custom-filters] :** pour formater ou transformer des données directement dans la sortie du template (par ex. `{$var|myFilter}`). Idéal pour le formatage de dates, la manipulation de texte ou l'application d'un échappement particulier. Vous pouvez aussi vous en servir pour modifier de plus gros blocs de contenu HTML, en enveloppant le contenu dans un [`{block}` |tags#{block}] anonyme auquel vous appliquez un filtre personnalisé.
- **[Fonctions personnalisées|custom-functions] :** pour ajouter une logique réutilisable appelable dans les expressions du template (par ex. `{myFunction($arg1, $arg2)}`). Utile pour les calculs, l'accès aux utilitaires de l'application ou la génération de petits fragments de contenu.
- **[Balises personnalisées|custom-tags] :** pour créer de toutes nouvelles constructions de langage (`{mytag}...{/mytag}` ou `n:mytag`). Les balises offrent le plus de puissance : elles permettent de définir des structures propres, de contrôler l'analyse du template et d'implémenter une logique de rendu complexe.
- **[Passes de compilation|compiler-passes] :** fonctions qui modifient l'arbre syntaxique abstrait (AST) du template après l'analyse, mais avant la génération du code PHP. Elles servent aux optimisations avancées, aux contrôles de sécurité (comme le Sandbox) ou aux modifications automatiques du code.
- **[Loaders personnalisés|loaders] :** pour changer la manière dont Latte trouve et charge les fichiers de template (chargement depuis une base de données, un stockage chiffré, etc.).

Choisir la bonne méthode d'extension est essentiel. Avant de créer une balise complexe, demandez-vous si un simple filtre ou une simple fonction ne suffirait pas. Prenons un exemple : implémenter un générateur *Lorem ipsum* qui prend en argument le nombre de mots à générer.

- **Comme balise ?** `{lipsum 40}` - possible, mais les balises conviennent mieux aux structures de contrôle ou à la génération de balisage complexe. Elles ne peuvent pas être utilisées directement dans les expressions.
- **Comme filtre ?** `{=40|lipsum}` - techniquement, cela fonctionne, mais les filtres sont faits pour *transformer* une entrée. Ici, `40` est un *argument*, pas la valeur transformée. C'est sémantiquement bancal.
- **Comme fonction ?** `{lipsum(40)}` - c'est la solution la plus naturelle ! Les fonctions acceptent des arguments et retournent des valeurs, ce qui les rend parfaites au sein de n'importe quelle expression : `{var $text = lipsum(40)}`.

**Recommandation générale :** utilisez les fonctions pour le calcul et la génération, les filtres pour la transformation et les balises pour les nouvelles structures de langage ou le balisage complexe. Utilisez les passes pour manipuler l'AST et les loaders pour obtenir les templates.


Enregistrement direct
=====================

Pour les utilitaires propres à un projet ou les ajouts rapides, Latte permet d'enregistrer directement filtres et fonctions sur l'objet `Latte\Engine`.

Utilisez `addFilter()` pour enregistrer un filtre. Le premier argument de votre fonction de filtre sera la valeur placée avant la barre verticale `|`, les arguments suivants étant ceux passés après le deux-points `:`.

```php
$latte = new Latte\Engine;

// Définition du filtre (callable : fonction, méthode statique, etc.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);

// Enregistrement
$latte->addFilter('truncate', $myTruncate);

// Utilisation dans le template : {$text|truncate} ou {$text|truncate:100}
```

Utilisez `addFunction()` pour enregistrer une fonction utilisable dans les expressions du template.

```php
$latte = new Latte\Engine;

// Définition de la fonction
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;

// Enregistrement
$latte->addFunction('isWeekend', $isWeekend);

// Utilisation dans le template : {if isWeekend($myDate)}Weekend!{/if}
```

Pour plus de détails, voyez [Création de filtres personnalisés|custom-filters] et [Fonctions|custom-functions].


La méthode robuste : l'extension Latte .{toc: Latte Extension}
==============================================================

L'enregistrement direct est simple, mais la façon standard et recommandée de regrouper et de distribuer des personnalisations de Latte passe par les classes **Extension**. Une Extension sert de point de configuration central pour enregistrer plusieurs balises, filtres, fonctions, passes de compilation et bien d'autres choses.

Pourquoi utiliser les Extensions ?

- **Organisation :** elles gardent au même endroit, dans une seule classe, les personnalisations liées entre elles (balises, filtres, etc. d'une même fonctionnalité).
- **Réutilisation et partage :** vous empaquetez facilement vos extensions pour les réutiliser dans d'autres projets ou les partager avec la communauté (via Composer, par exemple).
- **Pleine puissance :** les balises personnalisées et les passes de compilation *ne peuvent être enregistrées que* via des Extensions.


Enregistrement d'une Extension
------------------------------

Une Extension s'enregistre auprès de Latte avec `addExtension()` (ou via le [fichier de configuration |application:configuration#Templates Latte]) :

```php
$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);
```

Si vous enregistrez plusieurs extensions et qu'elles définissent des balises, filtres ou fonctions de même nom, c'est la dernière ajoutée qui l'emporte. Cela implique aussi que vos extensions peuvent redéfinir les balises, filtres et fonctions natifs.

Chaque fois que vous modifiez une classe et que le rafraîchissement automatique n'est pas désactivé, Latte recompile automatiquement vos templates.


Création d'une Extension
------------------------

Pour créer votre propre extension, vous devez écrire une classe qui hérite de [api:Latte\Extension]. Pour vous faire une idée de ce à quoi ressemble une extension, jetez un œil à la [CoreExtension |https://github.com/nette/latte/blob/master/src/Latte/Essential/CoreExtension.php] intégrée.

Voyons les méthodes que vous pouvez implémenter :


beforeCompile(Latte\Engine $engine): void .[method]
---------------------------------------------------

Appelée avant la compilation du template. La méthode peut servir par exemple à des initialisations liées à la compilation.


getTags(): array .[method]
--------------------------

Appelée lors de la compilation du template. Retourne un tableau associatif *nom de balise => callable*, où les callables sont les fonctions d'analyse des balises. [En savoir plus|custom-tags].

```php
public function getTags(): array
{
	return [
		'foo' => FooNode::create(...),
		'bar' => BarNode::create(...),
		'n:baz' => NBazNode::create(...),
		// ...
	];
}
```

La balise `n:baz` représente un pur [n:attribut |syntax#n:attributs], c'est-à-dire une balise qui ne peut s'écrire que sous forme d'attribut.

Pour les balises `foo` et `bar`, Latte reconnaît automatiquement s'il s'agit de balises paires ; si c'est le cas, elles peuvent aussi s'écrire sous forme de n:attributs, y compris les variantes préfixées `n:inner-foo` et `n:tag-foo`.

L'ordre d'exécution de ces n:attributs est déterminé par leur ordre dans le tableau retourné par `getTags()`. Ainsi, `n:foo` s'exécute toujours avant `n:bar`, même si les attributs sont écrits dans l'ordre inverse dans la balise HTML, comme `<div n:bar="..." n:foo="...">`.

Si vous avez besoin de fixer l'ordre des n:attributs entre plusieurs extensions, utilisez la méthode utilitaire `order()`, où le paramètre `before` et/ou `after` indique quelles balises passent avant ou après la balise.

```php
public function getTags(): array
{
	return [
		'foo' => self::order(FooNode::create(...), before: 'bar'),
		'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
	];
}
```


getPasses(): array .[method]
----------------------------

Appelée lors de la compilation du template. Retourne un tableau associatif *nom de passe => callable*, où les callables sont les fonctions représentant les [passes de compilation|compiler-passes] qui parcourent et modifient l'AST.

Là encore, la méthode utilitaire `order()` peut servir. La valeur des paramètres `before` ou `after` peut être `*`, au sens de avant/après tout le reste.

```php
public function getPasses(): array
{
	return [
		'optimize' => Passes::optimizePass(...),
		'sandbox' => self::order($this->sandboxPass(...), before: '*'),
		// ...
	];
}
```


beforeRender(Latte\Runtime\Template $template): void .[method]
--------------------------------------------------------------

Appelée avant chaque rendu de template. La méthode peut servir par exemple à initialiser les variables utilisées pendant le rendu.


afterRender(Latte\Runtime\Template $template): void .[method]{data-version:3.1.6}
---------------------------------------------------------------------------------
Appelée après chaque rendu de template. Elle s'exécute même si le rendu se termine prématurément via `{exitIf}` ou est interrompu par une exception, ce qui en fait le bon endroit pour le nettoyage ou la mesure.


getFilters(): array .[method]
-----------------------------

Appelée lorsque l'extension est enregistrée par la méthode `addExtension()`. Retourne les filtres sous forme de tableau associatif *nom de filtre => callable*. [En savoir plus|custom-filters].

```php
public function getFilters(): array
{
	return [
		'batch' => $this->batchFilter(...),
		'trim' => $this->trimFilter(...),
		// ...
	];
}
```


getFunctions(): array .[method]
-------------------------------

Appelée lorsque l'extension est enregistrée par la méthode `addExtension()`. Retourne les fonctions sous forme de tableau associatif *nom de fonction => callable*. [En savoir plus|custom-functions].

```php
public function getFunctions(): array
{
	return [
		'clamp' => $this->clampFunction(...),
		'divisibleBy' => $this->divisibleByFunction(...),
		// ...
	];
}
```


getProviders(): array .[method]
-------------------------------

Appelée lorsque l'extension est enregistrée par la méthode `addExtension()`. Retourne un tableau de providers, généralement des objets que les balises utilisent à l'exécution. On y accède via `$this->global->...`. [En savoir plus |custom-tags#Présentation des providers].

```php
public function getProviders(): array
{
	return [
		'myFoo' => $this->foo,
		'myBar' => $this->bar,
		// ...
	];
}
```


getCacheKey(Latte\Engine $engine): mixed .[method]
--------------------------------------------------

Appelée avant le rendu du template. La valeur de retour devient une partie de la clé dont le hachage figure dans le nom du fichier de template compilé. Pour des valeurs de retour différentes, Latte génère donc des fichiers de cache différents.

Étendre Latte

Latte est conçu pour être extensible. Si son jeu standard de balises, de filtres et de fonctions couvre déjà beaucoup de cas, vous avez souvent besoin d'ajouter votre propre logique ou vos propres utilitaires. Cette page donne un aperçu des façons d'étendre Latte pour coller parfaitement aux besoins de votre projet, du simple utilitaire à la nouvelle syntaxe complexe.

Façons d'étendre Latte

Voici un aperçu rapide des principaux moyens de personnaliser et d'étendre Latte :

  • Filtres personnalisés : pour formater ou transformer des données directement dans la sortie du template (par ex. {$var|myFilter}). Idéal pour le formatage de dates, la manipulation de texte ou l'application d'un échappement particulier. Vous pouvez aussi vous en servir pour modifier de plus gros blocs de contenu HTML, en enveloppant le contenu dans un {block} anonyme auquel vous appliquez un filtre personnalisé.
  • Fonctions personnalisées : pour ajouter une logique réutilisable appelable dans les expressions du template (par ex. {myFunction($arg1, $arg2)}). Utile pour les calculs, l'accès aux utilitaires de l'application ou la génération de petits fragments de contenu.
  • Balises personnalisées : pour créer de toutes nouvelles constructions de langage ({mytag}...{/mytag} ou n:mytag). Les balises offrent le plus de puissance : elles permettent de définir des structures propres, de contrôler l'analyse du template et d'implémenter une logique de rendu complexe.
  • Passes de compilation : fonctions qui modifient l'arbre syntaxique abstrait (AST) du template après l'analyse, mais avant la génération du code PHP. Elles servent aux optimisations avancées, aux contrôles de sécurité (comme le Sandbox) ou aux modifications automatiques du code.
  • Loaders personnalisés : pour changer la manière dont Latte trouve et charge les fichiers de template (chargement depuis une base de données, un stockage chiffré, etc.).

Choisir la bonne méthode d'extension est essentiel. Avant de créer une balise complexe, demandez-vous si un simple filtre ou une simple fonction ne suffirait pas. Prenons un exemple : implémenter un générateur Lorem ipsum qui prend en argument le nombre de mots à générer.

  • Comme balise ? {lipsum 40} – possible, mais les balises conviennent mieux aux structures de contrôle ou à la génération de balisage complexe. Elles ne peuvent pas être utilisées directement dans les expressions.
  • Comme filtre ? {=40|lipsum} – techniquement, cela fonctionne, mais les filtres sont faits pour transformer une entrée. Ici, 40 est un argument, pas la valeur transformée. C'est sémantiquement bancal.
  • Comme fonction ? {lipsum(40)} – c'est la solution la plus naturelle ! Les fonctions acceptent des arguments et retournent des valeurs, ce qui les rend parfaites au sein de n'importe quelle expression : {var $text = lipsum(40)}.

Recommandation générale : utilisez les fonctions pour le calcul et la génération, les filtres pour la transformation et les balises pour les nouvelles structures de langage ou le balisage complexe. Utilisez les passes pour manipuler l'AST et les loaders pour obtenir les templates.

Enregistrement direct

Pour les utilitaires propres à un projet ou les ajouts rapides, Latte permet d'enregistrer directement filtres et fonctions sur l'objet Latte\Engine.

Utilisez addFilter() pour enregistrer un filtre. Le premier argument de votre fonction de filtre sera la valeur placée avant la barre verticale |, les arguments suivants étant ceux passés après le deux-points :.

$latte = new Latte\Engine;

// Définition du filtre (callable : fonction, méthode statique, etc.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);

// Enregistrement
$latte->addFilter('truncate', $myTruncate);

// Utilisation dans le template : {$text|truncate} ou {$text|truncate:100}

Utilisez addFunction() pour enregistrer une fonction utilisable dans les expressions du template.

$latte = new Latte\Engine;

// Définition de la fonction
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;

// Enregistrement
$latte->addFunction('isWeekend', $isWeekend);

// Utilisation dans le template : {if isWeekend($myDate)}Weekend!{/if}

Pour plus de détails, voyez Création de filtres personnalisés et Fonctions.

La méthode robuste : l'extension Latte

L'enregistrement direct est simple, mais la façon standard et recommandée de regrouper et de distribuer des personnalisations de Latte passe par les classes Extension. Une Extension sert de point de configuration central pour enregistrer plusieurs balises, filtres, fonctions, passes de compilation et bien d'autres choses.

Pourquoi utiliser les Extensions ?

  • Organisation : elles gardent au même endroit, dans une seule classe, les personnalisations liées entre elles (balises, filtres, etc. d'une même fonctionnalité).
  • Réutilisation et partage : vous empaquetez facilement vos extensions pour les réutiliser dans d'autres projets ou les partager avec la communauté (via Composer, par exemple).
  • Pleine puissance : les balises personnalisées et les passes de compilation ne peuvent être enregistrées que via des Extensions.

Enregistrement d'une Extension

Une Extension s'enregistre auprès de Latte avec addExtension() (ou via le fichier de configuration) :

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

Si vous enregistrez plusieurs extensions et qu'elles définissent des balises, filtres ou fonctions de même nom, c'est la dernière ajoutée qui l'emporte. Cela implique aussi que vos extensions peuvent redéfinir les balises, filtres et fonctions natifs.

Chaque fois que vous modifiez une classe et que le rafraîchissement automatique n'est pas désactivé, Latte recompile automatiquement vos templates.

Création d'une Extension

Pour créer votre propre extension, vous devez écrire une classe qui hérite de Latte\Extension. Pour vous faire une idée de ce à quoi ressemble une extension, jetez un œil à la CoreExtension intégrée.

Voyons les méthodes que vous pouvez implémenter :

beforeCompile(Latte\Engine $engine)void

Appelée avant la compilation du template. La méthode peut servir par exemple à des initialisations liées à la compilation.

getTags(): array

Appelée lors de la compilation du template. Retourne un tableau associatif nom de balise ⇒ callable, où les callables sont les fonctions d'analyse des balises. En savoir plus.

public function getTags(): array
{
	return [
		'foo' => FooNode::create(...),
		'bar' => BarNode::create(...),
		'n:baz' => NBazNode::create(...),
		// ...
	];
}

La balise n:baz représente un pur n:attribut, c'est-à-dire une balise qui ne peut s'écrire que sous forme d'attribut.

Pour les balises foo et bar, Latte reconnaît automatiquement s'il s'agit de balises paires ; si c'est le cas, elles peuvent aussi s'écrire sous forme de n:attributs, y compris les variantes préfixées n:inner-foo et n:tag-foo.

L'ordre d'exécution de ces n:attributs est déterminé par leur ordre dans le tableau retourné par getTags(). Ainsi, n:foo s'exécute toujours avant n:bar, même si les attributs sont écrits dans l'ordre inverse dans la balise HTML, comme <div n:bar="..." n:foo="...">.

Si vous avez besoin de fixer l'ordre des n:attributs entre plusieurs extensions, utilisez la méthode utilitaire order(), où le paramètre before et/ou after indique quelles balises passent avant ou après la balise.

public function getTags(): array
{
	return [
		'foo' => self::order(FooNode::create(...), before: 'bar'),
		'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
	];
}

getPasses(): array

Appelée lors de la compilation du template. Retourne un tableau associatif nom de passe ⇒ callable, où les callables sont les fonctions représentant les passes de compilation qui parcourent et modifient l'AST.

Là encore, la méthode utilitaire order() peut servir. La valeur des paramètres before ou after peut être *, au sens de avant/après tout le reste.

public function getPasses(): array
{
	return [
		'optimize' => Passes::optimizePass(...),
		'sandbox' => self::order($this->sandboxPass(...), before: '*'),
		// ...
	];
}

beforeRender(Latte\Runtime\Template $template)void

Appelée avant chaque rendu de template. La méthode peut servir par exemple à initialiser les variables utilisées pendant le rendu.

afterRender(Latte\Runtime\Template $template)void

Appelée après chaque rendu de template. Elle s'exécute même si le rendu se termine prématurément via {exitIf} ou est interrompu par une exception, ce qui en fait le bon endroit pour le nettoyage ou la mesure.

getFilters(): array

Appelée lorsque l'extension est enregistrée par la méthode addExtension(). Retourne les filtres sous forme de tableau associatif nom de filtre ⇒ callable. En savoir plus.

public function getFilters(): array
{
	return [
		'batch' => $this->batchFilter(...),
		'trim' => $this->trimFilter(...),
		// ...
	];
}

getFunctions(): array

Appelée lorsque l'extension est enregistrée par la méthode addExtension(). Retourne les fonctions sous forme de tableau associatif nom de fonction ⇒ callable. En savoir plus.

public function getFunctions(): array
{
	return [
		'clamp' => $this->clampFunction(...),
		'divisibleBy' => $this->divisibleByFunction(...),
		// ...
	];
}

getProviders(): array

Appelée lorsque l'extension est enregistrée par la méthode addExtension(). Retourne un tableau de providers, généralement des objets que les balises utilisent à l'exécution. On y accède via $this->global->.... En savoir plus.

public function getProviders(): array
{
	return [
		'myFoo' => $this->foo,
		'myBar' => $this->bar,
		// ...
	];
}

getCacheKey(Latte\Engine $engine)mixed

Appelée avant le rendu du template. La valeur de retour devient une partie de la clé dont le hachage figure dans le nom du fichier de template compilé. Pour des valeurs de retour différentes, Latte génère donc des fichiers de cache différents.