Plan du site  
pixel
pixel

Articles - Étudiants SUPINFO

Les templates avec Twig

Par Jocelyn JARRIN Publié le 09/05/2017 à 22:10:14 Noter cet article:
(0 votes)
Avis favorable du comité de lecture

Bonjour et bienvenu sur ce nouvel article qui sera consacré comme vous l'aurez déjà compris aux templates Twig.

Introduction

Commençons par une petite explication de ce qu'est un template.

Aussi appelées "vues", les templates servent la partie V de la structure MVC, MVVM, MVW... C'est-à-dire que ces templates sont dédiés à l'affichage. Ils permettent donc de séparer la partie affichage de la partie code (HTML et PHP). Et les graphistes (ou designers) sont heureux que cette séparation existe. Nous ne sommes plus obligés de leur affliger un code PHP auquel ils ne comprennent strictement rien. Bien entendu, les développeurs en sont heureux aussi car ils ont, de fait, des fichiers beaucoup plus légers et simples à maintenir. Les métiers de graphiste et de dévelppeur sont bien distincts et chacun peut se spécialiser.

Présentation de Twig

Grâce aux templates nous allons pouvoir nous concentrer seulement sur l'affichage en front (ce que le visiteur, ou "client", pourra voir) et ainsi nous plonger dans le métier de designer. Certaines fonctionnalités vont rapidement être à notre portée grâce au code dynamique comme par exemple afficher un menu différent pour un utilisateur connecté et pour un autre non connecté ou faire une boucle pour afficher les éléments d'un tableau. Pour cela, Twig a créé un langage bien à lui mais qui est assez intuitif et concis. Sachez qu'il existe des certifications pour Twig et je vous invite grandement à les passer. Beaucoup d'entreprises utilisent cette technologie très simple d'utilisation. Ainsi lorsque l'on veut afficher une variable, nous le faisons de la manière suivante :

{{ variable }}
		

En lieu et place de notre fameux code PHP :

<?php echo $variable; ?>
		

Grâce au moteur de template qu'est Twig nous allons aussi pouvoir avoir accès à l'héritage de template. Non pas qu'en PHP la chose ne soit pas faisable, mais disons qu'avec Twig et puisque tout est déjà intégré nous n'aurons pas le moindre effort à fournir pour l'utiliser. À nous les navbars qui s'affichent sur toutes nos pages de notre site !

Autre point sympathique que nous amène Twig : les variables à afficher sont déjà sécurisées. Ainsi nous pouvons nous soulager des fonctions PHP : htmlentities () ou encore addslashes ().

Je ne vous ai parlé ici que de la partie Front-end d'un site web. À vrai dire, nous pouvons couvrir plusieurs autres sujets : celui du style dans les mails. Et oui, Twig le gère aussi, puisque c'est un outil de templating.* Nous pourrions aussi traiter le sujet du templating dans les Flux RSS grâce à Twig. Une des bonnes pratiques du monde des développeurs dit que les templates doivent être utilisés autant que possible, et ce pour toutes les bonnes raisons que nous avons vu.

Ok, maintenant que je vois à quoi ça sert, comment comment on s'en sert ?

Comme déjà dit, Twig est assez simple à utiliser et la doc est très bien faite.

Exemple

Voici un petit exemple très simple avant d'approfondir un peu les possibilités de ce moteur de templates :

<?php
// Depuis un contrôleur

return $this->render('index.html.twig', array(
  'var1' => $var1,
  'var2' => $var2
));
?>
			

Nous appelons donc render en lui passant le nom du template et les variables que nous allons utiliser dans ce template.

Côté affichage, nous allons avoir un code ressemblant à celui-là :

{{ var1 }}
				

Comme vous le voyez, pour afficher une variable nous avons cette manière là. Pour demander à Twig de faire quelque chose nous avons encore une fois une syntaxe assez simple. Pour l'exemple d'un if nous pouvons lui signer en écrivant de la manière suivante :

{% if ... %}
{% else %}
{% endif %}
					

Pour écrire un commentaire (possiblement sur plusieurs lignes) nous avons juste à faire :

{# ... #}
					

Présentation de la variable

Afficher l'index d'un tableau :

Identifiant : {{ user['id'] }}
		

Afficher l'attribut d'un objet :

Identifiant : {{ user.id }}
		

On peut aussi appliquer un ou plusieurs filtres à la variable à afficher. Nous allons ici appliquer le filtre « upper » pour mettre tout en majuscules :

Pseudo en majuscules : {{ pseudo|upper }}
		

On peut afficher une variable en combinant les filtres. « striptags » permet de supprimer les balises HTML. « title » permet de mettre la première lettre de chaque mot en majuscule. L'ordre d'application des filtres peut importer, ici striptags est appliqué, puis title :

Message : {{ news.texte|striptags|title }}
		

On peut aussi utiliser un filtre avec des arguments. Attention, il faut que la variable date soit un objet de type Datetime ici :

Date : {{ date|date('d/m/Y') }}
		

Pour concaténer des infos :

Identité : {{ nom ~ " " ~ prenom }}
		

Ce que fait {{ var1.id }}

En fait, la syntaxe {{ var1.id }} va effectuer beaucoup plus que le simple $var1->getId(); Et voici ce que cela fait :

  • Elle vérifie si objet est un tableau, et si "attribut" est un index valide. Si c'est le cas, elle affiche objet['attribut'].

  • Sinon, et si "objet" est un objet, elle vérifie si "attribut" est un attribut valide (public donc). Si c'est le cas, elle affiche objet->attribut.

  • Sinon, et si "objet" est un objet, elle vérifie si attribut() est une méthode valide (toujours publique, on n'oublie pas). Si c'est le cas, elle affiche objet->attribut().

  • Sinon, et si "objet" est un objet, elle vérifie si isAttribut() est une méthode valide. Si c'est le cas, elle affiche objet->isAttribut().

  • Sinon, elle n'affiche rien et retourne null.

Passons à autre chose de très utile, les filtres. Voici les plus utilisés

UPPER : Pour mettre toutes les lettres en majuscule.

{{ var|upper }}
		

STRIPTAGS : Suppression des balises XML.

{{ var|striptags }}
		

DATE : Formate la date selon le format donné en argument. La variable en entrée doit être une instance de Datetime.

{{ date|date('d/m/Y') }}
Date d'aujourd'hui : {{ "now"|date('d/m/Y') }}
		

FORMAT : Ajoute une variable dans une texte.

{{ "Il y a %s pommes et %s poires"|format(153, nb_poires) }}
		

LENGHT : Retourne le nombre de lignes d'un tableau ou la longueur d'un string.

Longueur de la variable : {{ texte|length }}
Nombre d'éléments du tableau : {{ tableau|length }}
		

Côté sécurité, ça donne quoi ?

Dans chacun des exemples montrés ici, les variables utilisées ont déjà été protégées par Twig. En effet, Twig applique par défaut un filtre sur toutes les variables qui sont affichées, afin de les protéger de balises HTML malencontreuses. Du coup si une variable contient le caractère « < » il sera échapé (on peut dire aussi qu'il ne sera pas pris en compte). Par exemple :

{{ var1 }}
		

Cela permet d'avoir un nom qui resemble a :

« nom[CaractèreEnHTML]pseudo » 
		

Ce mécanisme est donc très pratique. Et donc à savoir : inutile de protéger vos variables en amont, Twig s'occupe de tout en fin de chaîne. Et dans le cas où vous voulez afficher volontairement une variable qui contient du HTML, et que vous ne voulez pas que Twig l'échappe, il vous faut utiliser le filtre "raw" de la manière suivante :

{{ ma_variable_html|raw }}
		

Avec ce filtre, Twig désactivera localement la protection HTML, et affichera la variable en brut, quel que soit ce qu'elle contient.

Il existe aussi des variables globales

{{ app.request }}
		

La requête « request » qu'on a vu au chapitre précédent sur les contrôleurs.

{{ app.session }}
		

Le service « session » qu'on a vu également au chapitre précédent.

{{ app.environment  }}
		

L'environnement courant : « dev », « prod », et ceux que vous avez définis.

{{ app.debug }}
		

True si le mode debug est activé, False sinon.

{{ app.user  }}
		

L'utilisateur courant, que nous verrons également plus loin dans ce cours.

Bien entendu, on peut enregistrer nos propres variables globales, pour qu'elles soient accessibles depuis toutes nos vues, au lieu de les injecter à chaque fois depuis le contrôleur. Pour cela, il faut que l'action se déroule en deux temps, afin de ne pas setter une valeur dans le fichier de conf. Nous allons donc séparer la conf de l'attribution de la valeur : app/config/config.yml et app/config/parameters.yml. Configuration (ici, injection dans toutes les vues) qui utilise le paramètre :

# app/config/config.yml

twig:
    globals:
        webmaster: %app_webmaster%
			

Valeur du paramètre :

# app/config/parameters.yml

parameters:
    # …
    app_webmaster: moi-même
			

On a ainsi séparé la valeur du paramètre, stockée dans un fichier simple, et l'utilisation de ce paramètre, perdue dans le fichier de configuration.

Les structures de contrôle

Pour éviter de devoir balancer une quantité démentielle de variables à la vue ET de devoir créer beaucoup de vues, il existe des structures de contrôle. Ces structures sont assez similaires à celles que nous pouvons retrouver dans les langages de code. Pour bien se rendre compte de la différence d'écriture entre la vue template et la vue "normale" en PHP, je vais vous montrer à chaque fois les deux codes possibles.

IF

En Twig nous aurons cette forme là :

{% if membre.age < 12 %}
  Il faut avoir au moins 12 ans pour ce film.
{% elseif membre.age < 18 %}
  OK bon film.
{% else %}
  Un peu vieux pour voir ce film non ?
{% endif %}
			

En PHP nous aurons ceci :

<?php
	if($membre->getAge() < 12)
	{
		?>
	  		Il faut avoir au moins 12 ans pour ce film.
		<?php
	}
	elseif($membre->getAge() < 18)
	{
?>
OK bon film.
<?php
	}
	else
	{
		?>
  			Un peux vieux pour voir ce film non ?
		<?php
	}
?>
			
FOR

Voici la version Twig :

<ul>
  {% for membre in liste_membres %}
    <li>{{ membre.pseudo }}</li>
  {% else %}
    <li>Pas d'utilisateur trouvé.</li>
  {% endfor %}
</ul>
				

Et voici la version avec les clés valeurs du tableau :

<ul>
  {% for valeur, option in liste_options %}
    <li>value= {{ valeur }} {{ option }}</li>
  {% endfor %}
</ul>
					

L'équivalent en PHP sans les clés valeurs

<ul>
	<?php
		if(count($liste_membres) > 0)
		{
		  foreach($liste_membres as $membre)
		  {
		    echo '<li>' . $membre->getPseudo() . '</li>';
		  }
		}
		else
		{
			?>
			<li>Pas d'utilisateur trouvé.</li>
			<?php
		}
	?>
</ul>
					

En PHP avec les clés valeurs

<ul>
	<?php
		if(count($liste_membres) > 0)
		{
		  foreach($liste_options as $valeur, $option)
		  {
		    echo '<li> valeur :' . $valeur . ' option : ' . $option . '</li>';
		  }
		}
		else
		{
			?>
			<li>Pas d'utilisateur trouvé.</li>
			<?php
		}
	?>
</ul>
					
SET

En Twig

{% set foo = 'bar' %}
						

En version PHP

<?php $foo = 'bar'; ?>
						
Des infos supplémentaires sur le FOR

Le for définit une variable {{ loop }} au sein de la boucle, qui contient les attributs suivants :

{{ loop.index }}
							

Le numéro de l'itération courante (en commençant par 1).

{{ loop.index0 }}
							

Le numéro de l'itération courante (en commençant par 0).

{{ loop.revindex0 }}
							

Le nombre d'itérations restantes avant la fin de la boucle (en finissant par 0).

{{ loop.first }}
							

true si c'est la première itération, false sinon.

{{ loop.last }}
							

true si c'est la dernière itération, false sinon.

{{ loop.length }}
							

Le nombre total d'itérations dans la boucle.

Deux tests qui servent toujours

Voici le premier : paire ou impaire ? Even / Odd ?

{% for valeur in tableau %}
  <span class="{% if loop.index is even %}pair{% else %}impair{% endif %}">
    {{ valeur }}
  </span>
{% endfor %}
		

Et en PHP ça nous donne

<?php
	$i = 0;
	foreach($tableau as $valeur)
	{
	  echo '<span class="';
	  echo $i % 2 ? 'impair' : 'pair';
	  echo '">'.$valeur.'</span>';
	  $i++;
	}
?>
		

Et le deuxième, le Defined (c'est de loin celui dont je me sers le plus)

{% if var is defined %} … {% endif %}
		

Version PHP

<?php
if(isset($var))
	{
		...
	}
?>
		

Parlons maintenant d'include et d'héritage

Dans beaucoup de langages nous avons la possibilité d'inclure du code afin d'éviter sa répétition. Répéter du code c'est mal ! Je dis cela sur le ton de la plaisanterie, mais cette dernière mise à part force est de constater que répéter du code est l'équivalent de creuser un peu à chaque fois la tombe de notre projet. Notre projet peu à tout moment devenir un projet conséquent avec le temps et si les bonnes pratiques ne sont pas mises en oeuvre dès le départ il sera extrêmement difficile de faire demi-tour. Si on doit changer une valeur à un endroit dans notre code qui est recopié partout, nous allons devoir le changer autant de fois qu'il y a de copié/collé. Avouez que c'est plutôt dommage quand on sait qu'on peut facileement centraliser notre code en un fichier puis inclure ce fichier chaque fois que bon nous semble.

L'include

Voici la commande permettant un include en Twig :

{{ include("OCPlatformBundle:Advert:form.html.twig") }}
			
L'héritage

L'héritage en Twig est la même idée que pour du développement, il n'y a rien de bien nouveau : nous avons établi une charte graphique pour notre site web (ou mail) et nous voulons l'utiliser partout dans notre application.

À la façon du développement dans lequel nous avons une classe qui sera étendue par sa/ses filles, avec Twig nous allons avoir un template dans lequel il y aura des "blocks" à replire et il sera étendu et rempli par son/ses fils pour former une page complète. La différence réside dans le fait que là où l'include en PHP ne permet que la modification à l'endroit où il est écrit, le fils d'un template Twig peut remplir plusieurs "blocks" (plusieurs trous).

Le template père s'appelle en général le "layout". On peut en avoir une version assez minimaliste comme par exemple :

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>{% block title %}Notre site{% endblock %}</title>
  </head>

  <body>
    {% block body %}
    {% endblock %}
  </body>
</html>
						

Voici un exemple de template fils nommé accueil qui comblerait le block body :

{% extends "layout.html.twig" %}

{% block title %}{{ parent() }} - Accueil{% endblock %}

{% block body %}
  Voici le body de notre page.
{% endblock %}
						

Dans le fils nous pouvons voir le mot "extends" dont nous avons expliqué la fonctionnalité de remplacement de la fonction "include". Nous pouvons aussi voir le "block title" et le "block body" dans le template père que nous retrouvons dans le fils. Comme expliqué, les blocks dans le fils servent à remplir le template père, le block title fils prend alors la place du block title dans le template père. Nous pouvons donc en déduire (si ce n'est pas le cas, je vous l'affirme) que le nom d'un block se définit par {% block son_nom %} et il est délimité par ce même block et {% endblock %}. Dans le fils nous retrouvons cette même notation avec un {% block son_nom %} et {% endblock %}.

En ce qui concerne les templates pères et les descendants, nous avons une bonne pratique en vigueur à ce propos : il ne doit pas y avoir plus de trois niveaux d'extends. Je m'explique :

  • 1 : le layout, charte graphique de notre site.

  • 2 : le layout bundle (référence aux bundles de Synfony 2). On peut se représenter le bundle comme étant une partie de notre site, exemple si nous avons une partie de notre site (plusieurs pages donc) réservées à la visite virtuelle en 3D de maisons et bien ces pages pourront porter le nom "notre_site - Visite virtuelle".

  • 3 : le template du contenu principal de notre page.

Conclusion

Pour clôturer cet article nous allons faire un petit récap de ce que nous venons de voir :

  • Nous avons compris ce qu'est un template et pourquoi c'est extrêmement utile

  • Nous avons vu pourquoi Twig est sympa à utiliser au travers de différentes commandes de bases de cet outil

  • Nous l'avons comparé à des commandes en PHP et nous avons vu qu'il est très facile de se servir de Twig

  • Nous avons compris l'intérêt d'utiliser des variables

  • Les structures de contrôle n'ont plus de secret pour nous

  • L'include et l'héritage sont désormais des sujets compris

* Pour un tuto complet sur les mails en PHP je vous invite à regarder un autre de mes articles : " Comment envoyer un mail en PHP ".

A propos de SUPINFO | Contacts & adresses | Enseigner à SUPINFO | Presse | Conditions d'utilisation & Copyright | Respect de la vie privée | Investir
Logo de la société Cisco, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société IBM, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sun-Oracle, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Apple, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sybase, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Novell, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Intel, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Accenture, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société SAP, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Prometric, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Toeic, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo du IT Academy Program par Microsoft, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management

SUPINFO International University
Ecole d'Informatique - IT School
École Supérieure d'Informatique de Paris, leader en France
La Grande Ecole de l'informatique, du numérique et du management
Fondée en 1965, reconnue par l'État. Titre Bac+5 certifié au niveau I.
SUPINFO International University is globally operated by EDUCINVEST Belgium - Avenue Louise, 534 - 1050 Brussels