06 Twig
Maintenant que nous savons router nos fonctions PHP vers un pattern d'url (routing + Controller), il convient de s'intéresser au V de MVC à savoir les vues !
Des vues ?
Les vues (parfois nommés templates) permettent de séparer la présentation (le code HTML) de notre logique métier (le controller). Flight intégre un mécanisme de gestion des vues mais celui-ci est plutôt limité. Nous allons donc utiliser le moteur de templates du secteur PHP à savoir Twig.
Twig
Twig est un moteur de templates pour le langage de programmation PHP, utilisé par défaut par le framework Symfony. Celui-ci est une traduction de jinja, moteur de templates écrit en python ❤️.
Fonctionnalités
- Contrôle de flux complexe
- Échappement automatique
- Héritage des templates
- Filtres de variables
- Internationalisation (via gettext)
- Macros
- Langage extensible
Syntaxe
Pour afficher le contenu d'une variable
{{ ma_variable }}
Pour afficher un élément d'un tableau ou d'un objet
{{ book.title }}
Pour itérer sur un tableau
{% for book in books %}
{{ book.title }}
{% endfor %}
Et si on mélange tout ça avec du HTML ?
<ul>
{% for book in books %}
<li>
<strong>{{ book.title }}</strong>
</li>
{% endfor %}
</ul>
Filtres
Les filtres fournissent des traitements sur une expression, si on les place après elle séparés par des pipes.
capitalize
: met une majuscule à la première lettre d'une chaine de caractères.upper
: met la chaine en lettres capitales.first
: affiche la première ligne d'un tableau.length
: renvoie la taille de la variable.
Variables spéciales
loop
: contient les informations de la boucle dans laquelle elle se trouve. Par exemple loop.index donne le nombre d'itérations déjà survenue._route
: partie de URL située après le domaine
Donc, pour obtenir la route d'une page :
{{ path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) }}
Installation
Un composer require
sur le package twig/twig
?
Mise en oeuvre
Initialisation
Pour commencer créer un répertoire views/
à la racine du projet.
Puis nous devons indiquer à Flight que nous allons utiliser Twig et le charger en extension mais tout d'abord nous devons charger Twig et le configurer.
Dans votre fichier index.php
:
<?php
$loader = new \Twig\Loader\FilesystemLoader(dirname(__FILE__) . '/views');
$twigConfig = array(
// 'cache' => './cache/twig/',
// 'cache' => false,
'debug' => true,
);
Une fois que nous avons charger et configurer Twig, il convient d'indiquer à Flight de l'inscrire en tant qu'extension
index.php
:
<?php
Flight::register('view', '\Twig\Environment', array($loader, $twigConfig), function ($twig) {
$twig->addExtension(new \Twig\Extension\DebugExtension()); // Add the debug extension
});
Désormais Flight sera en mesure d'utiliser Twig.
Notre première vue
Et maintenant nous allons utiliser Twig conjointement avec Flight pour générer notre page à partir d'une vue.
<?php
Flight::route('/first_view/', function(){
Flight::view()->display('first_view.twig');
});
- Que se passe t'il en se rendant sur notre page first_view ?
- Créer le fichier
views/first_view.twig
pour corriger l'erreur. - Un fichier vide c'est bien, et si nous ajoutions un peu de HTML ?
Félicitation vous venez de créer votre première vue et de la rendre via Twig.
Afficher des choses plus utiles ...
Afficher du HTML via Twig c'est bien, afficher le conteu de variables, tableaux, ... c'est encore mieux. Nous allons découvrir comment passé des données à notre vue.
En reprenant notre vue:
<?php
Flight::route('/first_view/', function(){
Flight::view()->display('first_view.twig');
});
Nous allons la modifier, pour lui passer quelques données:
<?php
Flight::route('/first_view/', function(){
$data = [
'contenu' => 'Hello World!',
'name' => 'Ben Kenobi',
];
Flight::view()->display('first_view.twig', $data);
});
Nous passons à notre fichier twig le tableau data
qui contient deux éléments. Si nous rechargons notre page nous ne voyons pas nos données apparaître. Il faut donc modifier notre fichier .twig pour afficher les données:
Ajoutez le code suivant à votre vue:
{{ contenu }}
{{ name }}
- Que constatez vous ?
- Avez vous compris le passage de données à notre vue ?
Héritage de template
La partie la plus puissante de Twig est l’héritage des templates. L'héritage de templates vous permet de créer un «squelette» de base contenant tous les éléments communs de votre site et définissant les blocs que les modèles enfants peuvent remplacer.
Cela semble compliqué mais reste très basique. Il est plus facile de comprendre cela en commençant par un exemple.
Template de base
Ce template, que nous appellerons base.twig
, définit un simple squelette de document HTML que vous pouvez utiliser pour une page simple à deux colonnes. C’est le travail des templates «enfants» de remplir les blocs vides de contenu:
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<main>{% block content %}{% endblock %}</main>
<footer>
{% block footer %}
© Copyright 2008 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</footer>
</body>
</html>
Dans cet exemple, les balises {% block %}
définissent quatre blocs que les modèles enfants peuvent remplir.
La balise de bloc indique simplement au moteur de gabarit qu'un modèle enfant peut remplacer les espaces réservés qu'il contient.
Template enfant
Un modèle enfant pourrait ressembler à ceci:
{% extends "base.twig" %}
{% block title %}Index{% endblock %}
{% block head %}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome to my awesome homepage.
</p>
{% endblock %}
La balise {% extend %}
est la clé ici. Il indique au moteur de modèle que ce modèle «étend» un autre modèle. Lorsque le système de gabarit évalue ce gabarit, il localise d'abord le parent. La balise extend devrait être la première balise du modèle.
Global et filtre
Global
Parfois nous avons besoins de passer la même valeur à plusieurs voir toutes nos vues, Twig intégre un mécanisme très intéressant appellé global.
<?php
Flight::register('view', '\Twig\Environment', array($loader, $twigConfig), function ($twig) {
$twig->addExtension(new \Twig\Extension\DebugExtension()); // Add the debug extension
$twig->addGlobal('ma_valeur', "Hello There!");
});
Ainsi la variable ma_valeur
sera passé à chaque vue, il est possible de rendre cela plus intéressant en passant des variables plus complexes, voir le résultat d'appel de fonction.
Filtres
Twig intégre de nombreux filtres par défaut, il est possible de créer nos propres filtres au besoin:
<?php
Flight::register('view', 'Twig_Environment', array($loader, $twigConfig), function ($twig) {
// Twig loading treatment
$twig->addFilter(new \Twig\TwigFilter('trad', function($string){
return $string;
}));
});
Il s'agit d'un filtre très intéressant qui retourne la valeur inchangée.. Le but est ici juste de vous présenter la syntaxe pour créer vos propres filtres.
Shortcut
Faire appel à Twig pour rendre nos templates c'est chouette, toutefois faire appel à cette ligne de code :
<?php
Flight::view()->display('first_view.twig');
Reste assez complexe. Et si nous utilisions un raccourci pour faire appel à cette fonction ?
Après l'enregistrement de Twig ajouter le code suivant:
<?php
Flight::map('render', function($template, $data=array()){
Flight::view()->display($template, $data);
});
Ce code permet de dire que lorsque que nous ferons appel à la méthode render
de Flight, nous utiliserons Twig.
Ainsi ceci:
<?php
Flight::route('/first_view/', function(){
Flight::view()->display('first_view.twig');
});
Devient cela:
<?php
Flight::route('/first_view/', function(){
Flight::render('first_view.twig');
});
Mise en application
En utilisant l'approche TDD, les Tests unitaires et d'intégrations
- Créer une fonctions permettant de récupérer les livres lister à l'adresse suivante https://medusa.delahayeyourself.info/api/books/,
- Créer une route ainsi qu'une vue (template Twig) pour afficher le nombre de livres ainsi que les différents livres.
Pour aller plus loin
Vous avez encore à découvrir du monde des moteurs de template, comme par exemple Les structures de contrôles, ou encore l'escaping