Les vues dans Symfony2 avec Twig

Dans ce chapitre, nous verrons comment Symfony2 intègre un nouveau système de template très puissant pour gérer ses vues.




Introduction à Twig


Twig est un moteur de template PHP dans la même lignée que Smarty et directement intégré dans Symfony2.

Très puissant, Twig permettra de gérer de l'héritage entre templates et layout, séparer les couches de présentation et couches métiers...
Idéal si vous travaillez en équipe avec des intégrateurs, qui n'auront qu'à modifier les templates dans le répertoire views/ de votre bundle.

Moteur de templates PHP Twig


Le moteur dispose d'un langage avec 3 types de balises:

{{ maVar }}: Les doubles accolades permettent d'imprimer une valeur, le résultat d'une fonction...

{% for page in arrPages %}: Les accolades pourcentage permettent d'exécuter une fonction, définir un bloc...

{# Les commentaires #}: Et la dernière syntaxe pour les commentaires.

Une petite intro sur Twig avait déjà été faite sur la Ferme du Web, n'hésitez pas à y faire un tour.

Je vous conseille aussi de mettre la documentation officielle de twig dans vos bookmarks, elle servira à coup sûr.


Création du layout Twig pour notre projet Symfony2


Nous allons commencer par modifier le layout de base de notre projet.

Ouvrez le fichier app/Resources/views/base.html.twig:

Code html:
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>{% block title %}Watch My Desk{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
        <link rel="shortcut icon" href="{{ asset('favicon.ico') }}" />
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
    </body>
</html>


Par défaut, on retrouve la structure HTML de base et un certain nombre de blocks.
Les blocks sont des zones que l'ont va définir (souvent dans le layout) et qui pourront être surchargées par les templates liés aux actions.

Dans notre exemple, nous retrouvons un block:
  • title: Pour changer le contenu de la balise <title>
  • stylesheets: Pour inclure les différentes feuilles de styles CSS dynamiquement
  • body: Pour inclure le contenu principal de la page web
  • javascripts: Pour inclure les fichiers JS du projet (Défini en fin de page pour améliorer les webperfs.)


A présent, dans le template Default/index.html.twig de notre bundle, nous allons pouvoir surcharger ce layout.
Dans un premier temps, il faut spécifier que nous allons utiliser le layout base.html.twig dans notre template:
Code html:
{% extends '::base.html.twig' %}


Il est aussi envisageable de mettre le layout dans le répertoire views/ de notre bundle, puis d'appeler le layout dans les templates de la manière suivante:
Code html:
{% extends 'WmdWatchMyDeskBundle::layout.html.twig' %}


Il ne nous reste plus qu'à surcharger les blocks du layout pour faire apparaître notre page d'accueil:

Code html:
{% extends '::base.html.twig' %}

{% block title %}
    Watch my desk: Bienvenue !
{% endblock %}

{% block body %}
    Hello les fermiers !
{% endblock %}


Voici ce que vous devriez obtenir:


Si rien ne s'affiche, vérifiez bien que vous n'ayez pas oublié d'inclure le layout. Ou le block body...



Et cette fois, nous avons bien la barre de profiler !

La gestion des blocks est très puissante, on peut faire du réel héritage.
Admettons que nous souhaitions garder le contenu du block title et ajouter après la valeur par défaut du block un titre supplémentaire. Ceci est réalisable grâce à twig:

Code php:
{% block title %}
    {{ parent() }}
    - Bienvenue !
{% endblock %}


Et si vous rafraîchissez la page, vous devriez avoir en title: Watch My Desk - Bienvenue !
Vous voyez l'utilité ? Dans l'inclusion des javascripts et CSS! Pour ajouter des JS / CSS en plus que ceux par défaut, dans le même block.

Nous modifierons plus tard notre layout avec l'intégration du design du site.



Créer des liens dans les templates avec path()


Symfony intègre une fonction path() dans Twig qui permet de générer les bonnes URLs en fonction des routes définies dans nos actions.

Il suffit de passer en paramètre le nom de la route et le tour est joué:

Code html:
{% block body %}
    Hello les fermiers !
    <a href="{{ path('homepage') }}">Accueil</a>
{% endblock %}


Créez à présent un nouveau contrôleur Controller/DeskController.php avec l'action showAction qui permettra de voir le détail d'un bureau:

Code php:
<?php

namespace Wmd\WatchMyDeskBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;


class DeskController extends Controller
{
    /**
     * @Route("/show/{deskId}", name="desk_show")
     * @Template()
     */
    public function showAction($deskId)
    {
        return array('id' => $deskId);
    }
}


La route de l'action comporte un paramètre deskId qui sera l'identifiant du bureau. Et cette route est nommée desk_show.

Créez le template lié à l'action dans votre bundle: Resources/views/Desk/show.html.twig:

Code html:
{% extends '::base.html.twig' %}

{% block title %}
    {{ parent() }}
    - Détail du bureau {{ id }}
{% endblock %}

{% block body %}
    <h1>Détail du bureau n°{{ id }}</h1>
    <p>
        Description du bureau ...
    </p>
    <a href="{{ path("homepage") }}">Retour à l'accueil</a>
{% endblock %}


Puis ajoutez un lien dans votre template index.html.twig vers le bureau d'id 5 par exemple:
Code html:
{% block body %}
    Hello les fermiers !
    <a href="{{ path('homepage') }}">Accueil</a> - <a href="{{ path('desk_show', {"deskId": 5}) }}">Bureau n°5</a>
{% endblock %}


Comme vous pouvez le voir, on passe ici un paramètre à notre route, l'ID du bureau, directement dans path().

Vous pouvez tester de naviguer entre vos 2 pages.

Affichage de la page bureau 5


Encore une fois, pour en savoir plus sur les templates Twig, rendez-vous dans la doc officielle.


Les assets dans Symfony2


Pour inclure des fichiers "assets" (CSS, JS, Images...), une fonction asset() est intégrée dans twig.

Cette dernière permet de générer les bonnes URLs de nos fichiers ressources.

Nous verrons plus tard qu'il sera possible grâce à Assetic d'appliquer des fonctions bien pratiques:
  • Compression automatique des JS / CSS
  • utilisation de CDN pour les images
  • Assemblage des JS et CSS en un seul fichier...


Créez un fichier style.css dans le répertoire dédié aux CSS: src/Wmd/WatchMyDeskBundle/Resources/public/css/

Ajoutez y quelques instructions CSS pour voir si le fichier est bien inclut:
Code css:
body {
  color: #FF0000;
}


Puis dans notre layout base.html.twig, modifiez le block stylesheets pour inclure le fichier:
Code html:
{% block stylesheets %}
        <link rel="stylesheet" href="{{ asset('bundles/wmdwatchmydesk/css/style.css') }}" type="text/css" media="all" />
{% endblock %}


Je vous entends déjà vous questionner, mais pourquoi cette adresse "bundles/wmdwatchmydesk/css/style.css" ??

Vous l'aurez remarqué, nous avons ajouté le fichier CSS dans le répertoire public de notre Bundle WatchMyDeskBundle. Le répertoire de ce dernier n'est pas accessible par le web étant donné que notre vhost apache pointe sur le répertoire web...
En effet ! Chaque bundle dispose de ses propres assets et pour les rendre accessibles par le web, il faut lancer une commande qui va publier les ressources dans le répertoire web/.

Ouvrez votre console bash et exécutez la commande suivante:
php app/console assets:install web/ --symlink


Si vous êtes sur Windows, il se peut que symlink ne fonctionne pas, vous devrez alors publier les assets dès qu'il y'a une modification ou un ajout d'images/CSS/JS... Ou alors créez directement un répertoire img / css / js à la racine de web/



Si tout se passe bien, vous devriez voir quels sont les bundles qui ont publié leur assets et à quel endroit:
Code:
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Wmd\WatchMyDeskBundle into web/bundles/wmdwatchmydesk
Installing assets for Symfony\Bundle\WebProfilerBundle into web/bundles/webprofiler
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution


Tous nos fichiers assets présents dans Resources/public/ sont liés avec un lien symbolique (grâce à l'option --symlink de la commande) dans le répertoire web/bundles/wmdwatchmydesk.

A présent, nous pouvons rafraîchir notre page d'accueil et voir si le texte a changé de couleur. Si c'est le cas, notre CSS est bien chargée !

Il faudra faire de même pour les fichiers JS et images.

Maintenant que nous avons les notions de base sur les contrôleur, routing et templating, passons à la partie modèle avec les entités.






Rechercher sur la Ferme du web