Templates Twig en PHP

L’installation de Twig se fait grâce à l’outil composer

composer

Si composer n’est pas présent dans votre environnement, il faut procéder à son installation. Composer servira à beaucoup de tâches courantes dans un projet PHP. On va d’abord créer un répertoire bin à la racine de notre HOME, placez-y l’exécutable composer.phar et renommez le en composer (ou faites un lien symbolique).

cd
mkdir bin
cd bin
curl -s https://getcomposer.org/installer | php
mv composer.phar composer

Si vous êtes derrière un proxy, vérifiez la définition de vos variables d’environnement http_proxy et https_proxy dans votre .bashrc Ajoutez la ligne suivante à votre .bashrc pour adapter votre PATH :

export PATH=$PATH:~/bin

de manière à ce que tous les programmes installés dans le répertoire bin de votre HOME soient accessibles de n’importe où.

Installation

Installons Twig:

composer require twig/twig

ou simplement :

composer require twig

Ceci créera dans le répertoire courant un dossier vendor contenant les librairies demandées et les dépendances.

On définit d’abord un template de base, BaseTemplate.html:

<!DOCTYPE html>
<html lang="fr">
<head>
    {% block head %}
    <meta charset="utf-8">
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %}</title>
    {% endblock %}
</head>
<body>
<section id="content">
{% block content %}{% endblock %}
</section>
<footer id="footer">
    {% block footer %}
    &copy; Copyright 2023 <a href="http://monsite.com">
    Mon super Site</a>.
    {% endblock %}
</footer>
</body>
</html>

Puis un template plus spécialisé qui en hérite, menu.html :

{% extends "BaseTemplate.html" %}
{% block title %}Menu de la semaine{% endblock %}
{% block head %}
{{ parent() }}
<style>
    .important { color: #336699; }
</style>
{% endblock %}
{% block content %}
    <h1>Menu</h1>
    <p class="important">
        Voici votre menu de la semaine:
        <dl>
            <dt>Lundi</dt>
            <dd>{{Lundi}}</dd>
            <dt>Mardi</dt>
            <dd>{{Mardi}}</dd>
            <dt>Mercredi</dt>
            <dd>{{Mercredi}}</dd>
            <dt>Jeudi</dt>
            <dd>{{Jeudi}}</dd>
        </dl>
    </p>
{% endblock %}

Enfin, on utilise ce template dans un fichier menu.php en chargeant d’abord l”autoloader:

<?php
// menu.php
// inclure  l'autoloader
include 'vendor/autoload.php';

try {
    // le dossier ou on trouve les templates
    $loader = new Twig\Loader\FilesystemLoader('templates');

    // initialiser l'environement Twig
    $twig = new Twig\Environment($loader);

    // load template
    $template = $twig->load('Menu.html');

    // set template variables
    // render template
    echo $template->render(array(
        'lundi' => 'Steak Frites',
        'mardi' => 'Raviolis',
        'mercredi' => 'Pot au Feu',
        'jeudi' => 'Couscous',
        'vendredi' => 'Poisson',
    ));

} catch (Exception $e) {
    die ('ERROR: ' . $e->getMessage());
}

Affichage des personnes du Carnet

Affichons à présent les personnes du Carnet à l’aide d’un template Twig. On réutilise le fichier modele.php vu précédemment:

<?php
// modele.php

class Carnet {
    private static $connexion;
    function __construct(){
        $dsn="mysql:dbname=".BASE.";host=".SERVER;
        try{
                self::$connexion=new PDO($dsn,USER,PASSWD);
            }
        catch(PDOException $e){
            printf("Échec de la connexion : %s\n", $e->getMessage());
            $this->connexion = NULL;
        }
    }
    /** Récupére la liste des contacts sous forme d'un tableau */
    function get_all_friends(){
        $sql="SELECT * from CARNET";
        $data=self::$connexion->query($sql);
        return $data;
    }
    /** Ajoute un contact à la table CARNET */
    function add_friend($data){
        $sql = "INSERT INTO CARNET(NOM,PRENOM,NAISSANCE,VILLE) values (?,?,?,?)";
        $stmt = self::$connexion->prepare($sql);
        return $stmt->execute(array($data['nom'],
            $data['prenom'], $data['naissance'],$data['ville']));
    }
    /** Récupére un contact à partir de son ID */
    function get_friend_by_id($id)
    {
        $sql="SELECT * from CARNET where ID=:id";
        $stmt=self::$connexion->prepare($sql);
        $stmt->bindParam(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetch(PDO::FETCH_OBJ);
    }
<?php
// fichier carnet.php

include 'vendor/autoload.php';

try {
    // le dossier ou on trouve les templates
    $loader = new Twig\Loader\FilesystemLoader('templates');

    // initialiser l'environement Twig
    $twig = new Twig\Environment($loader);

    // load template
    $template = $twig->load('carnet.html');

    // on va instancier le modele
    // et préparer les variables
    // qu'on va passer au template
    require_once("modele.php");
    $contacts = new Contacts();
    $amis = $contacts->get_all_friends();
    $titre = "Liste des contacts";

    // on passe ces données au template
    // grace à la méthode render
    echo $template->render(array(
        'titre' => $titre,
        'amis' => $amis,
    ));

} catch (Exception $e) {
    die ('ERROR: ' . $e->getMessage());
}

et un template carnet.html :

{% extends "BaseTemplate.html" %}
{% block title %}Personnes du Carnet {% endblock %}
{% block head %}
{{ parent() }}
<style type="text/css">
    .important { color: #336699; }
</style>
{% endblock %}

{% block content %}

<p align="center" class="Style1">{{titre}}</p>
<table border="2" align="center" cellspacing="0" cellpadding="2" >
<tr bgcolor="#CA9999">
    <td width="50"><strong>numero</strong></td>
    <td width="50"><strong>Nom</strong></td>
    <td width="50"><strong>Prenom</strong></td>
    <td width="30"><strong>Age</strong></td>
    <td width="50"><strong>Ville</strong></td>
</tr>
{% set i=0 %}
{% for ami in amis %}
{% set i=i+1 %}
{% if i is odd %}
<tr bgcolor="#F0F0F0">
{% else %}
    <tr bgcolor="#A6A6A6">
{% endif %}
    <td>{{ami.ID}}</td>
    <td>{{ami.NOM}}</td>
    <td>{{ami.PRENOM}}</td>
    <td>{{ami.NAISSANCE}}</td>
    <td>{{ami.VILLE}}</td>
</tr>
{% endfor %}
</table>

{% endblock %}

Ce template est bien maladroit (car on peut faire plus simple, voir ci-dessous) mais il démontre l’expressivité du langage de template Twig avec des boucles, des conditionnelles, des déclarations et calculs avec des variables, etc.

Nous pouvons bien sûr en proposer un plus simple avec le CSS adéquat.

Affichage des Personnes avec un template plus simple

(carnet2.html)

{% extends "BaseTemplate.html" %}
{% block title %}Personnes du Carnet{% endblock %}
{% block head %}
{{ parent() }}
<link rel="stylesheet" href="static/css/tabstyle.css" />
{% endblock %}

{% block content %}

<h2>{{titre}}</h2>
<table id="jolie" class="centre" >
<tr>
    <td>numero</td>
    <td>Nom</td>
    <td>Prenom</td>
    <td>Age</td>
    <td>Ville</td>
</tr>
{% for ami in amis %}
    <tr>
    <td>{{ami.ID}}</td>
    <td>{{ami.NOM}}</td>
    <td>{{ami.PRENOM}}</td>
    <td>{{ami.NAISSANCE}}</td>
    <td>{{ami.VILLE}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

avec le style CSS qui va bien sur les tableaux …

Nous pouvons ainsi compléter le développement MVC effectué précédemment en utilisant des templates Twig. Voir sur github/roza/php-basic-mvc pour un code plus complet. Mais le système de routage employé est encore très rudimentaire.

Nous pouvons ensuite utliser des outils de microframeworks Web comme Phalcon ou Slim ou directement ceux du Framework de référence : Symfony pour aller plus loin.