Héritage et réutilisabilité des modèles
Les mécanismes de réutilisation et d'héritage des modèles sont là pour booster votre productivité car chaque modèle ne contient que son contenu unique et les éléments et structures répétés sont réutilisés. Nous présentons trois concepts : l'héritage des modèles, la réutilisation horizontale et l'héritage des unités.
Le concept d'héritage des modèles Latte est similaire à l'héritage des classes PHP. Vous définissez un modèle parent à partir duquel les autres modèles enfants peuvent s'étendre et remplacer certaines parties du modèle parent. Ce concept fonctionne parfaitement lorsque les éléments partagent une structure commune. Cela vous semble compliqué ? Ne vous inquiétez pas, ce n'est pas le cas.
Héritage de la mise en page {layout}
Examinons l'héritage des modèles de mise en page en commençant par un exemple. Il s'agit d'un modèle parent que nous
appellerons par exemple layout.latte
et qui définit un squelette de document HTML.
La balise {block}
définit trois blocs que les modèles enfants peuvent remplir. La balise block indique au moteur
de modèle qu'un modèle enfant peut remplacer ces parties du modèle en définissant son propre bloc du même nom.
Un modèle enfant peut ressembler à ceci :
La balise {layout}
est la clé ici. Elle indique au moteur de modèle que ce modèle „étend“ un autre
modèle. Lorsque Latte rend ce modèle, il localise d'abord le parent – dans ce cas, layout.latte
.
À ce stade, le moteur de modèle remarque les trois balises de bloc dans layout.latte
et remplace ces blocs par
le contenu du modèle enfant. Notez que, comme le modèle enfant n'a pas défini le bloc footer, le contenu du modèle
parent est utilisé à la place. Le contenu d'une balise {block}
dans un modèle parent est toujours utilisé comme
solution de repli.
Le résultat peut ressembler à ceci :
Dans un modèle enfant, les blocs ne peuvent être situés qu'au niveau supérieur ou à l'intérieur d'un autre bloc, par exemple :
De plus, un bloc sera toujours créé dans le modèle, que la condition environnante {if}
soit évaluée comme
étant vraie ou fausse. Contrairement à ce que vous pourriez penser, ce modèle définit bien un bloc.
Si vous souhaitez que la sortie à l'intérieur du bloc soit affichée de manière conditionnelle, utilisez plutôt ce qui suit :
Les données situées à l'extérieur d'un bloc dans un modèle enfant sont exécutées avant que le modèle de présentation
ne soit rendu. Vous pouvez donc l'utiliser pour définir des variables telles que {var $foo = bar}
et propager les
données à l'ensemble de la chaîne d'héritage :
Héritage multi-niveaux
Vous pouvez utiliser autant de niveaux d'héritage que nécessaire. Une façon courante d'utiliser l'héritage de mise en page est l'approche à trois niveaux suivante :
- Créez un modèle
layout.latte
qui contient l'aspect et la convivialité principaux de votre site. - Créez un modèle
layout-SECTIONNAME.latte
pour chaque section de votre site. Par exemple,layout-news.latte
,layout-blog.latte
etc. Ces modèles étendent touslayout.latte
et incluent des styles/conceptions spécifiques à chaque section. - Créez des modèles individuels pour chaque type de page, par exemple un article d'actualité ou une entrée de blog. Ces modèles étendent le modèle de section approprié.
Héritage dynamique de la mise en page
Vous pouvez utiliser une variable ou toute expression PHP comme nom du modèle parent, de sorte que l'héritage peut se comporter de manière dynamique :
Vous pouvez également utiliser l'API Latte pour choisir automatiquement le modèle de mise en page.
Conseils
Voici quelques conseils pour travailler avec l'héritage de mise en page :
- Si vous utilisez
{layout}
dans un modèle, il doit s'agir de la première balise de modèle de ce modèle. - La mise en page peut être recherchée automatiquement (comme dans les
présentateurs). Dans ce cas, si le modèle ne doit
pas avoir de mise en page, il l'indiquera avec la balise
{layout none}
. - La balise
{layout}
a un alias{extends}
. - Le nom de fichier du modèle étendu dépend du chargeur de modèle.
- Vous pouvez avoir autant de blocs que vous le souhaitez. Rappelez-vous que les modèles enfants n'ont pas à définir tous les blocs parents, vous pouvez donc remplir des valeurs par défaut raisonnables dans un certain nombre de blocs, puis ne définir que ceux dont vous avez besoin plus tard.
Blocs {block}
Voir aussi anonyme {block}
Un bloc permet de modifier la façon dont une certaine partie d'un modèle est rendue, mais il n'interfère en aucune façon avec la logique qui l'entoure. Prenons l'exemple suivant pour illustrer comment un bloc fonctionne et, surtout, comment il ne fonctionne pas :
Si vous rendez ce modèle, le résultat sera exactement le même avec ou sans les balises de bloc. Les blocs ont accès aux variables des scopes externes. Il s'agit simplement d'un moyen de les rendre surmontables par un modèle enfant :
Maintenant, lors du rendu du modèle enfant, la boucle va utiliser le bloc défini dans le modèle enfant
child.Latte
au lieu de celui défini dans le modèle de base parent.Latte
; le modèle exécuté est
alors équivalent au modèle suivant :
Cependant, si nous créons une nouvelle variable à l'intérieur d'un bloc nommé ou si nous remplaçons une valeur d'une variable existante, le changement sera visible uniquement à l'intérieur du bloc :
Le contenu du bloc peut être modifié par des filtres. L'exemple suivant supprime tout le HTML et met le titre en majuscule :
La balise peut aussi être écrite comme n:attribute:
Blocs locaux
Chaque bloc remplace le contenu du bloc parent du même nom. Sauf pour les blocs locaux. Ils sont un peu comme les méthodes privées d'une classe. Vous pouvez créer un modèle sans craindre que – en raison de la coïncidence des noms des blocs – ils soient écrasés par le second modèle.
Blocs d'impression {include}
Voir aussi {include file}
Pour imprimer un bloc à un endroit précis, utilisez la balise {include blockname}
:
Vous pouvez également afficher le bloc à partir d'un autre modèle :
Les blocs imprimés n'ont pas accès aux variables du contexte actif, sauf si le bloc est défini dans le même fichier où il est inclus. Cependant, ils ont accès aux variables globales.
Vous pouvez transmettre des variables au bloc de la manière suivante :
Vous pouvez utiliser une variable ou toute expression en PHP comme nom de bloc. Dans ce cas, ajoutez le mot-clé
block
devant la variable, afin que l'on sache à la compilation qu'il s'agit d'un bloc, et non d'un modèle d'insertion, dont le nom pourrait également se trouver dans la variable :
Le bloc peut également être imprimé à l'intérieur de lui-même, ce qui est utile, par exemple, lors du rendu d'une structure arborescente :
Au lieu de {include menu, ...}
, nous pouvons également écrire {include this, ...}
où
this
signifie le bloc actuel.
Le contenu imprimé peut être modifié par des filtres. L'exemple suivant supprime tout le HTML et met le titre en majuscule :
Bloc parent
Si vous devez imprimer le contenu du bloc à partir du modèle parent, l'instruction {include parent}
fera
l'affaire. Elle est utile si vous souhaitez compléter le contenu d'un bloc parent au lieu de le remplacer complètement.
Définitions {define}
En plus des blocs, il existe également des „définitions“ dans Latte. Elles sont comparables aux fonctions dans les langages de programmation ordinaires. Elles sont utiles pour réutiliser des fragments de modèles afin de ne pas se répéter.
Latte essaie de garder les choses simples, donc les définitions sont les mêmes que les blocs, et tout ce qui est dit à propos des blocs s'applique également aux définitions. Elles diffèrent des blocs en ce sens que
- elles sont entourées de balises
{define}
- elles ne sont rendues que lorsqu'elles sont insérées par l'intermédiaire d'une balise
{include}
- elles peuvent être paramétrées comme des fonctions en PHP
Imaginez que vous disposiez d'un modèle d'aide contenant un ensemble de définitions sur la manière de dessiner des formulaires HTML.
Les arguments d'une définition sont toujours facultatifs et ont une valeur par défaut : null
, sauf si une valeur
par défaut est spécifiée (ici, 'text'
est la valeur par défaut de $type
). Les types de paramètres
peuvent également être déclarés : {define input, string $name, ...}
.
Le modèle contenant les définitions est chargé à l'aide de la commande {import}
. Les définitions elles-mêmes sont rendues de la même manière que les blocs:
Les définitions n'ont pas accès aux variables du contexte actif, mais elles ont accès aux variables globales.
Noms de blocs dynamiques
Latte permet une grande flexibilité dans la définition des blocs car le nom du bloc peut être n'importe quelle expression
PHP. Cet exemple définit trois blocs nommés hi-Peter
, hi-John
et hi-Mary
:
Par exemple, nous ne pouvons redéfinir qu'un seul bloc dans un modèle enfant :
Ainsi, la sortie ressemblera à ceci :
Checking Block Existence {ifset}
Voir aussi {ifset $var}
Utilisez le test {ifset blockname}
pour vérifier si un bloc (ou plusieurs blocs) existe dans le contexte
actuel :
Vous pouvez utiliser une variable ou toute expression en PHP comme nom de bloc. Dans ce cas, ajoutez le mot-clé
block
devant la variable pour indiquer clairement que ce n'est pas la variable qui est vérifiée :
L'existence de blocs est également renvoyée par la fonction hasBlock()
:
Conseils
Voici quelques conseils pour travailler avec des blocs :
- Le dernier bloc de premier niveau n'a pas besoin d'avoir de balise de fermeture (le bloc se termine à la fin du document). Cela simplifie l'écriture des modèles enfants, qui n'ont qu'un seul bloc primaire.
- Pour plus de lisibilité, vous pouvez éventuellement donner un nom à votre balise
{/block}
, par exemple{/block footer}
. Toutefois, ce nom doit correspondre au nom du bloc. Dans les modèles de grande taille, cette technique vous aide à voir quelles balises de bloc sont fermées. - Vous ne pouvez pas définir directement plusieurs balises de bloc portant le même nom dans un même modèle. Mais vous pouvez y parvenir en utilisant des noms de blocs dynamiques.
- Vous pouvez utiliser n:attributes pour définir des blocs tels
que
<h1 n:block=title>Welcome to my awesome homepage</h1>
- Les blocs peuvent également être utilisés sans nom uniquement pour appliquer les filtres à la sortie :
{block|strip} hello {/block}
Réutilisation horizontale {import}
La réutilisation horizontale est le troisième mécanisme de réutilisation et d'héritage dans Latte. Il permet de charger
des blocs à partir d'autres modèles. Il est similaire à la création d'un fichier avec des fonctions d'aide en PHP, puis à son
chargement à l'aide de require
.
Bien que l'héritage de modèles soit l'une des fonctionnalités les plus puissantes de Latte, il est limité à l'héritage simple – un modèle ne peut étendre qu'un seul autre modèle. La réutilisation horizontale est un moyen d'obtenir un héritage multiple.
Prenons un ensemble de définitions de blocs :
À l'aide de la commande {import}
, importez tous les blocs et définitions définis
dans blocks.latte
dans un autre modèle :
Si vous importez les blocs dans le modèle parent (c'est-à-dire si vous utilisez {import}
dans
layout.latte
), les blocs seront également disponibles dans tous les modèles enfants, ce qui est très pratique.
Le modèle destiné à être importé (par exemple blocks.latte
) ne doit pas étendre un autre modèle, c'est-à-dire utiliser {layout}
. Toutefois, il peut
importer d'autres modèles.
La balise {import}
doit être la première balise de modèle après {layout}
. Le nom du modèle peut
être une expression PHP quelconque :
Vous pouvez utiliser autant d'instructions {import}
que vous le souhaitez dans un modèle donné. Si deux modèles
importés définissent le même bloc, le premier l'emporte. Toutefois, la plus haute priorité est accordée au modèle principal,
qui peut écraser tout bloc importé.
Le contenu des blocs écrasés peut être préservé en insérant le bloc de la même manière qu'un bloc parent:
Dans cet exemple, {include parent}
appellera correctement le bloc sidebar
à partir du modèle
blocks.latte
.
Héritage des unités {embed}
L'héritage des unités reprend l'idée de l'héritage des mises en page au niveau des fragments de contenu. Alors que l'héritage de la mise en page fonctionne avec des „squelettes de documents“, qui prennent vie grâce à des modèles enfants, l'héritage des unités vous permet de créer des squelettes pour de plus petites unités de contenu et de les réutiliser où vous le souhaitez.
Dans l'héritage d'unités, la balise {embed}
est la clé. Elle combine le comportement de {include}
et {layout}
. Elle vous permet d'inclure le contenu d'un autre modèle ou bloc et de transmettre éventuellement des
variables, comme le fait {include}
. Elle vous permet également de remplacer tout bloc défini à l'intérieur du
modèle inclus, comme le fait {layout}
.
Par exemple, nous allons utiliser l'élément accordéon pliable. Jetons un coup d'œil au squelette de l'élément dans le
modèle collapsible.latte
:
Les balises {block}
définissent deux blocs que les modèles enfants peuvent remplir. Oui, comme dans le cas du
modèle parent dans le modèle d'héritage de mise en page. Vous voyez aussi la variable $modifierClass
.
Utilisons notre élément dans le modèle. C'est là que {embed}
entre en jeu. Il s'agit d'un kit super puissant
qui nous permet de tout faire : inclure le contenu du modèle de l'élément, y ajouter des variables et y ajouter des blocs avec
du HTML personnalisé :
Le résultat pourrait ressembler à ça :
Les blocs à l'intérieur des balises d'intégration forment une couche distincte indépendante des autres blocs. Par
conséquent, ils peuvent avoir le même nom que le bloc à l'extérieur de la balise embed et ne sont en aucun cas affectés. En
utilisant la balise include à l'intérieur des balises {embed}
, vous pouvez
insérer des blocs créés ici, des blocs du modèle incorporé (qui ne sont pas locaux),
ainsi que des blocs du modèle principal qui sont locaux. Vous pouvez également importer
des blocs à partir d'autres fichiers :
Les modèles intégrés n'ont pas accès aux variables du contexte actif, mais ils ont accès aux variables globales.
Avec {embed}
vous pouvez insérer non seulement des modèles mais aussi d'autres blocs, ainsi l'exemple
précédent pourrait être écrit comme ceci :
Si nous passons une expression à {embed}
et qu'il n'est pas clair s'il s'agit d'un bloc ou d'un nom de fichier,
ajoutez le mot-clé block
ou file
:
Cas d'utilisation
Il existe différents types d'héritage et de réutilisation du code dans Latte. Résumons les principaux concepts pour plus de clarté :
{include template}
Use Case: Utilisation de header.latte
& footer.latte
dans layout.latte
.
header.latte
footer.latte
layout.latte
{layout}
Cas d'utilisation : Extension de layout.latte
à l'intérieur de homepage.latte
&
about.latte
.
layout.latte
homepage.latte
about.latte
{import}
Cas d'utilisation : sidebar.latte
dans single.product.latte
&
single.service.latte
.
sidebar.latte
single.product.latte
single.service.latte
{define}
Cas d'utilisation : Une fonction qui récupère des variables et produit des balises.
form.latte
profile.service.latte
{embed}
Cas d'utilisation : Incorporation de pagination.latte
dans product.table.latte
&
service.table.latte
.
pagination.latte
product.table.latte
service.table.latte