Templates

Nette utilise le système de templates Latte. D'une part parce que c'est le système de templates le plus sécurisé pour PHP, et d'autre part parce que c'est aussi le système le plus intuitif. Vous n'avez pas besoin d'apprendre beaucoup de nouveautés, la connaissance de PHP et de quelques balises suffit.

Il est courant qu'une page soit composée d'un template de layout + du template de l'action donnée. Voici à quoi peut ressembler un template de layout, remarquez les blocs {block} et la balise {include} :

<!DOCTYPE html>
<html>
<head>
	<title>{block title}Mon App{/block}</title>
</head>
<body>
	<header>...</header>
	{include content}
	<footer>...</footer>
</body>
</html>

Et voici ce que sera le template de l'action :

{block title}Page d'accueil{/block}

{block content}
<h1>Page d'accueil</h1>
...
{/block}

Il définit le bloc content, qui sera inséré à la place de {include content} dans le layout, et redéfinit également le bloc title, qui écrasera {block title} dans le layout. Essayez d'imaginer le résultat.

Recherche de templates

Vous n'avez pas besoin de spécifier dans les presenters quel template doit être rendu, le framework déduit le chemin lui-même et vous évite d'écrire.

Si vous utilisez une structure de répertoires où chaque presenter a son propre répertoire, placez simplement le template dans ce répertoire sous le nom de l'action (ou de la vue), c'est-à-dire pour l'action default, utilisez le template default.latte :

app/
└── Presentation/
    └── Home/
        ├── HomePresenter.php
        └── default.latte

Si vous utilisez une structure où les presenters sont regroupés dans un seul répertoire et les templates dans un dossier templates, enregistrez-le soit dans le fichier <Presenter>.<view>.latte soit <Presenter>/<view>.latte :

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── Home.default.latte  ← 1ère variante
        └── Home/
            └── default.latte   ← 2ème variante

Le répertoire templates peut également être placé un niveau plus haut, c'est-à-dire au même niveau que le répertoire contenant les classes des presenters.

Si le template n'est pas trouvé, le presenter répondra par une erreur 404 – page non trouvée.

Vous pouvez changer la vue en utilisant $this->setView('autreVue'). Il est également possible de spécifier directement le fichier de template en utilisant $this->template->setFile('/chemin/vers/template.latte').

Les fichiers où les templates sont recherchés peuvent être modifiés en surchargeant la méthode formatTemplateFiles(), qui retourne un tableau de noms de fichiers possibles.

Recherche du template de layout

Nette recherche également automatiquement le fichier de layout.

Si vous utilisez une structure de répertoires où chaque presenter a son propre répertoire, placez le layout soit dans le dossier du presenter s'il lui est spécifique, soit un niveau plus haut s'il est commun à plusieurs presenters :

app/
└── Presentation/
    ├── @layout.latte           ← layout commun
    └── Home/
        ├── @layout.latte       ← uniquement pour le presenter Home
        ├── HomePresenter.php
        └── default.latte

Si vous utilisez une structure où les presenters sont regroupés dans un seul répertoire et les templates dans un dossier templates, le layout sera attendu à ces endroits :

app/
└── Presenters/
    ├── HomePresenter.php
    └── templates/
        ├── @layout.latte       ← layout commun
        ├── Home.@layout.latte  ← uniquement pour Home, 1ère variante
        └── Home/
            └── @layout.latte   ← uniquement pour Home, 2ème variante

Si le presenter se trouve dans un module, la recherche s'effectuera également aux niveaux de répertoires supérieurs, en fonction de l'imbrication du module.

Le nom du layout peut être modifié à l'aide de $this->setLayout('layoutAdmin') et il sera alors attendu dans le fichier @layoutAdmin.latte. Il est également possible de spécifier directement le fichier de template de layout à l'aide de $this->setLayout('/chemin/vers/template.latte').

En utilisant $this->setLayout(false) ou la balise {layout none} à l'intérieur du template, la recherche de layout est désactivée.

Les fichiers où les templates de layout sont recherchés peuvent être modifiés en surchargeant la méthode formatLayoutTemplateFiles(), qui retourne un tableau de noms de fichiers possibles.

Variables dans le template

Nous passons des variables au template en les écrivant dans $this->template et elles sont ensuite disponibles dans le template comme variables locales :

$this->template->article = $this->articles->getById($id);

Nous pouvons ainsi passer facilement n'importe quelle variable aux templates. Cependant, lors du développement d'applications robustes, il est plus utile de se limiter. Par exemple, en définissant explicitement la liste des variables que le template attend et leurs types. Grâce à cela, PHP pourra vérifier les types, l'IDE pourra suggérer correctement et l'analyse statique pourra détecter les erreurs.

Et comment définir une telle liste ? Simplement sous la forme d'une classe et de ses propriétés. Nous la nommerons de manière similaire au presenter, mais avec Template à la fin :

/**
 * @property-read ArticleTemplate $template
 */
class ArticlePresenter extends Nette\Application\UI\Presenter
{
}

class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
	public Model\Article $article;
	public Nette\Security\User $user;

	// et d'autres variables
}

L'objet $this->template dans le presenter sera désormais une instance de la classe ArticleTemplate. Ainsi, PHP vérifiera les types déclarés lors de l'écriture. Et à partir de PHP 8.2, il avertira également en cas d'écriture dans une variable inexistante ; dans les versions précédentes, le même résultat peut être obtenu en utilisant le trait Nette\SmartObject.

L'annotation @property-read est destinée à l'IDE et à l'analyse statique, grâce à elle, l'autocomplétion fonctionnera, voir PhpStorm et l'autocomplétion pour $this⁠-⁠>⁠template.

Vous pouvez également profiter du luxe de l'autocomplétion dans les templates, il suffit d'installer le plugin pour Latte dans PhpStorm et d'indiquer le nom de la classe au début du template, plus d'informations dans l'article Latte : comment gérer le système de types :

{templateType App\Presentation\Article\ArticleTemplate}
...

C'est ainsi que fonctionnent également les templates dans les composants, il suffit de respecter la convention de nommage et pour un composant par ex. FifteenControl créer une classe de template FifteenTemplate.

Si vous avez besoin de créer $template comme instance d'une autre classe, utilisez la méthode createTemplate() :

public function renderDefault(): void
{
	$template = $this->createTemplate(SpecialTemplate::class);
	$template->foo = 123;
	// ...
	$this->sendTemplate($template);
}

Variables par défaut

Les presenters et les composants transmettent automatiquement plusieurs variables utiles aux templates :

  • $basePath est le chemin URL absolu vers le répertoire racine (par ex. /eshop)
  • $baseUrl est l'URL absolue vers le répertoire racine (par ex. http://localhost/eshop)
  • $user est l'objet représentant l'utilisateur
  • $presenter est le presenter actuel
  • $control est le composant ou presenter actuel
  • $flashes tableau des messages envoyés par la fonction flashMessage()

Si vous utilisez votre propre classe de template, ces variables seront transmises si vous créez une propriété pour elles.

Création de liens

Dans le template, les liens vers d'autres presenters & actions sont créés de cette manière :

<a n:href="Product:show">détail du produit</a>

L'attribut n:href est très pratique pour les balises HTML <a>. Si nous voulons afficher le lien ailleurs, par exemple dans du texte, nous utilisons {link} :

L'adresse est : {link Home:default}

Plus d'informations peuvent être trouvées dans le chapitre Création de liens URL.

Filtres personnalisés, balises, etc.

Le système de templates Latte peut être étendu avec des filtres, fonctions, balises personnalisés, etc. Cela peut être fait directement dans la méthode render<View> ou beforeRender() :

public function beforeRender(): void
{
	// ajout d'un filtre
	$this->template->addFilter('foo', /* ... */);

	// ou nous configurons directement l'objet Latte\Engine
	$latte = $this->template->getLatte();
	$latte->addFilterLoader(/* ... */);
}

Latte version 3 offre une méthode plus avancée, à savoir la création d'une extension pour chaque projet web. Exemple succinct d'une telle classe :

namespace App\Presentation\Accessory;

final class LatteExtension extends Latte\Extension
{
	public function __construct(
		private App\Model\Facade $facade,
		private Nette\Security\User $user,
		// ...
	) {
	}

	public function getFilters(): array
	{
		return [
			'timeAgoInWords' => $this->filterTimeAgoInWords(...),
			'money' => $this->filterMoney(...),
			// ...
		];
	}

	public function getFunctions(): array
	{
		return [
			'canEditArticle' =>
				fn($article) => $this->facade->canEditArticle($article, $this->user->getId()),
			// ...
		];
	}

	// ...
}

Nous l'enregistrons à l'aide de la configuration :

latte:
	extensions:
		- App\Presentation\Accessory\LatteExtension

Traduction

Si vous programmez une application multilingue, vous aurez probablement besoin d'afficher certains textes dans le template dans différentes langues. Nette Framework définit à cet effet une interface pour la traduction Nette\Localization\Translator, qui a une seule méthode translate(). Elle accepte un message $message, qui est généralement une chaîne, et tout autre paramètre. La tâche est de retourner la chaîne traduite. Il n'y a pas d'implémentation par défaut dans Nette, vous pouvez choisir parmi plusieurs solutions prêtes à l'emploi selon vos besoins, que vous trouverez sur Componette. Dans leur documentation, vous apprendrez comment configurer le traducteur.

Il est possible de définir un traducteur pour les templates, que nous recevrons via injection, avec la méthode setTranslator() :

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator);
}

Le traducteur peut alternativement être défini via la configuration :

latte:
	extensions:
		- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)

Ensuite, le traducteur peut être utilisé par exemple comme filtre |translate, y compris avec des paramètres supplémentaires qui sont passés à la méthode translate() (voir foo, bar) :

<a href="basket">{='Panier'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>

Ou comme balise soulignée :

<a href="basket">{_'Panier'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>

Pour traduire une section du template, il existe une balise paire {translate} (depuis Latte 2.11, auparavant la balise {_} était utilisée) :

<a href="order">{translate}Commande{/translate}</a>
<a href="order">{translate foo, bar}Commande{/translate}</a>

Le traducteur est appelé par défaut à l'exécution lors du rendu du template. Cependant, Latte version 3 peut traduire tous les textes statiques déjà pendant 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, plusieurs versions compilées du template sont créées dans le répertoire cache, une pour chaque langue. Pour cela, il suffit d'indiquer la langue comme deuxième paramètre :

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator, $lang);
}

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

version: 4.0