Modèles
Nette utilise le système de modèles Latte. Latte est utilisé parce que c'est le système de modèles le plus sûr pour PHP, et en même temps le système le plus intuitif. Vous n'avez pas besoin d'apprendre grand chose de nouveau, il vous suffit de connaître PHP et quelques balises Latte.
Il est courant que la page soit complétée à partir du modèle de mise en page + le modèle d'action. Voici à quoi peut
ressembler un modèle de mise en page, remarquez les blocs {block}
et la balise {include}
:
<!DOCTYPE html>
<html>
<head>
<title>{block title}My App{/block}</title>
</head>
<body>
<header>...</header>
{include content}
<footer>...</footer>
</body>
</html>
Et ceci pourrait être le modèle d'action :
{block title}Homepage{/block}
{block content}
<h1>Homepage</h1>
...
{/block}
Il définit le bloc content
, qui est inséré à la place de {include content}
dans la mise en page,
et redéfinit également le bloc title
, qui écrase {block title}
dans la mise en page. Essayez
d'imaginer le résultat.
Recherche de modèles
Dans les présentateurs, vous n'avez pas besoin de spécifier quel modèle doit être rendu ; le cadre détermine automatiquement le chemin, ce qui facilite le codage.
Si vous utilisez une structure de répertoires dans laquelle chaque présentateur a son propre répertoire, placez simplement
le modèle dans ce répertoire sous le nom de l'action (c'est-à-dire de la vue). Par exemple, pour l'action default
,
utilisez le modèle default.latte
:
app/ └── UI/ └── Home/ ├── HomePresenter.php └── default.latte
Si vous utilisez une structure dans laquelle les présentateurs sont regroupés dans un répertoire et les modèles dans un
dossier templates
, enregistrez-les dans un fichier <Presenter>.<view>.latte
soit dans un
fichier <Presenter>/<view>.latte
:
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── Home.default.latte ← 1st variant └── Home/ └── default.latte ← 2nd variant
Le répertoire templates
peut également être placé un niveau plus haut, au même niveau que le répertoire des
classes de présentateurs.
Si le modèle n'est pas trouvé, le présentateur répond par l'erreur 404 – page non trouvée.
Vous pouvez changer la vue en utilisant $this->setView('anotherView')
. Il est également possible de spécifier
directement le fichier de modèle avec $this->template->setFile('/path/to/template.latte')
.
Les fichiers dans lesquels les modèles sont recherchés peuvent être modifiés en remplaçant la méthode formatTemplateFiles(), qui renvoie un tableau de noms de fichiers possibles.
Recherche de modèles de mise en page
Nette recherche également automatiquement le fichier de mise en page.
Si vous utilisez une structure de répertoires dans laquelle chaque présentateur a son propre répertoire, placez le modèle soit dans le dossier du présentateur, s'il lui est propre, soit à un niveau supérieur s'il est commun à plusieurs présentateurs :
app/ └── UI/ ├── @layout.latte ← common layout └── Home/ ├── @layout.latte ← only for Home presenter ├── HomePresenter.php └── default.latte
Si vous utilisez une structure dans laquelle les présentateurs sont regroupés dans un répertoire et les modèles dans un
dossier templates
, la mise en page sera attendue aux endroits suivants :
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── @layout.latte ← common layout ├── Home.@layout.latte ← only for Home, 1st variant └── Home/ └── @layout.latte ← only for Home, 2nd variant
Si le présentateur se trouve dans un module, il cherchera également plus haut dans l'arborescence du répertoire en fonction de l'imbrication du module.
Le nom de la présentation peut être modifié à l'aide de $this->setLayout('layoutAdmin')
et sera alors
attendu dans le fichier @layoutAdmin.latte
. Vous pouvez également spécifier directement le fichier de modèle de
présentation en utilisant $this->setLayout('/path/to/template.latte')
.
L'utilisation de $this->setLayout(false)
ou de la balise {layout none}
à l'intérieur du modèle
désactive la recherche de modèle.
Les fichiers dans lesquels les modèles de présentation sont recherchés peuvent être modifiés en remplaçant la méthode formatLayoutTemplateFiles(), qui renvoie un tableau de noms de fichiers possibles.
Variables dans le modèle
Les variables sont transmises au modèle en les écrivant à $this->template
. Elles sont ensuite disponibles
dans le modèle en tant que variables locales :
$this->template->article = $this->articles->getById($id);
De cette façon, nous pouvons facilement passer n'importe quelle variable aux modèles. Cependant, lors du développement d'applications robustes, il est souvent plus utile de se limiter. Par exemple, en définissant explicitement une liste de variables que le modèle attend et leurs types. Cela permettra à PHP de vérifier le type, à l'IDE d'autocompléter correctement et à l'analyse statique de détecter les erreurs.
Et comment définir une telle énumération ? Tout simplement sous la forme d'une classe et de ses propriétés. Nous la
nommons de façon similaire à 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 autres variables
}
L'objet $this->template
dans le présentateur sera maintenant une instance de la classe
ArticleTemplate
. Ainsi, PHP vérifie les types déclarés lorsqu'ils sont écrits. Et à partir de PHP 8.2, il
préviendra également en cas d'écriture dans une variable inexistante. Dans les versions précédentes, la même chose peut
être réalisée en utilisant le trait Nette\SmartObject.
L'annotation @property-read
est pour les IDE et l'analyse statique, elle fera fonctionner la complétion
automatique, voir PhpStorm et la complétion de
code pour $this->template.
Vous pouvez aussi vous offrir le luxe de chuchoter dans les templates, il suffit d'installer le plugin Latte dans PhpStorm et de spécifier le nom de la classe au début du template, voir l'article Latte : how to type system:
{templateType App\UI\Article\ArticleTemplate}
...
C'est également de cette façon que les modèles fonctionnent dans les composants, il suffit de suivre la convention de
nommage et de créer une classe de modèle FifteenTemplate
pour le composant, par exemple
FifteenControl
.
Si vous devez créer un $template
en tant qu'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 présentateurs et les composants transmettent automatiquement plusieurs variables utiles aux modèles :
$basePath
est un chemin URL absolu vers le répertoire racine (par exemple/CD-collection
)$baseUrl
est une URL absolue vers le répertoire racine (par exemplehttp://localhost/CD-collection
)$user
est un objet représentant l'utilisateur$presenter
est le présentateur actuel$control
est le composant ou le présentateur actuel$flashes
liste des messages envoyés par la méthodeflashMessage()
Si vous utilisez une classe de modèle personnalisée, ces variables sont transmises si vous créez une propriété pour elles.
Création de liens
Dans le modèle, nous créons des liens vers d'autres présentateurs et actions comme suit :
<a n:href="Product:show">detail</a>
L'attribut n:href
est très pratique pour les balises HTML <a>
. Si nous voulons imprimer le
lien ailleurs, par exemple dans le texte, nous utilisons {link}
:
URL is: {link Home:default}
Pour plus d'informations, voir Création de liens.
Filtres, balises, etc. personnalisés
Le système de modélisation Latte peut être étendu avec des filtres, des fonctions, des balises, etc. personnalisés. Ceci
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 configurer directement l'objet Latte\Engine
$latte = $this->template->getLatte();
$latte->addFilterLoader(/* ... */);
}
Latte version 3 propose un moyen plus avancé en créant une extension pour chaque projet web. Voici un exemple approximatif d'une telle classe :
namespace App\UI\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 en utilisant la configuration:
latte:
extensions:
- App\UI\Accessory\LatteExtension
Traduction de
Si vous programmez une application multilingue, vous aurez probablement besoin d'éditer une partie du texte du modèle dans
différentes langues. Pour ce faire, le Nette Framework définit une interface de traduction Nette\Localization\Translator, qui possède
une seule méthode translate()
. Celle-ci accepte le message $message
, qui est généralement une chaîne
de caractères, et tout autre paramètre. La tâche consiste à renvoyer la chaîne traduite. Il n'y a pas d'implémentation par
défaut dans Nette, vous pouvez choisir en fonction de vos besoins parmi plusieurs solutions prêtes à l'emploi que vous
trouverez sur Componette. Leur documentation vous indique comment
configurer le traducteur.
Les modèles peuvent être configurés avec un traducteur, que l'on nous aura passé, en utilisant la méthode setTranslator()
:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator);
}
Alternativement, le traducteur peut être défini à l'aide de la configuration:
latte:
extensions:
- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
Le traducteur peut alors être utilisé, par exemple, comme un filtre |translate
, avec des paramètres
supplémentaires transmis à la méthode translate()
(voir foo, bar
) :
<a href="basket">{='Basket'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>
Ou comme une balise de soulignement :
<a href="basket">{_'Basket'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>
Pour la traduction des sections de modèles, il existe une balise appariée {translate}
(depuis Latte 2.11, la
balise {_}
était utilisée auparavant) :
<a href="order">{translate}Order{/translate}</a>
<a href="order">{translate foo, bar}Order{/translate}</a>
Translator est appelé par défaut au moment de l'exécution, lors du rendu du modèle. Latte version 3, cependant, peut traduire tout le texte statique 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 modèle 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 :
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator, $lang);
}
Par texte statique, nous entendons, par exemple, {_'hello'}
ou {translate}hello{/translate}
. Le texte
non statique, tel que {_$foo}
, continuera à être compilé à la volée.