Twig : Comment créer facilement et simplement votre propre filter

Les filters Twig sont très utiles lors des développements d’interfaces. Vous ne pouvez pas le nier, vous les utilisez tous les jours et je suis sûr que vous aimez ça :)

Twig vient avec tout un tas de filters plus utiles les uns que les autres, je vous invite à consulter cette liste complète des filters par défaut.

Vous pouvez également installer des filters en plus de ceux par défauts comme par exemple les quelques filters que Fabien Potencier a regroupé dans un repository Github appelé « Twig-extensions » et que nous vous recommandons. Installez facilement grâce à Composer et vous pourrez par exemple utiliser les filters debug (équivalent d’un var_dump() depuis une vue Twig), des filters relatifs à la manipulation de chaines de caractères comme avec le filter truncate ou encore des filters vous donnant la possibilité d’internationaliser vos vues.

Les filters par défaut et ceux de Fabien Potencier répondent aux besoins de la majorité des développements mais qu’en est-il si vous vous rendez compte qu’aucun des filters que vous connaissez ne réponde à un besoin particulier que vous exprimez ? Rien de plus simple, créez-le ! C’est ce que nous allons voir ici.

Pour commencer, vous devez créer un dossier Twig dans lequel vous créerez un autre dossier Extension à la racine de votre Bundle. Lorsque c’est chose faite, créez dans ce dernier dossier un fichier portant le nom de votre extension Twig comme par exemple MyfilterExtension.php. Voici ensuite ce que vous devrez au moins avoir dans ce fichier :

namespace Acme\Bundle\AcmeBundle\Twig\Extension;

class MyfilterExtension extends \Twig_Extension
{
    public function getFilters()
    {
        return array(
            'myfilter' => new \Twig_Filter_Method($this, 'doSomething')
        );
    }

    public function doSomething($value)
    {
        return 'transformated-' . $value;
    }

    public function getName()
    {
        return 'myfilter_extension';
    }

}

Ce que fait ce filter est très simple, à chaque fois que vous utiliserez dans votre vue Twig le mot clef myfilter, il ajoutera la chaine ‘transformated-’ devant la valeur de la chaine sur laquelle vous être en train d’appliquer votre filter, par exemple :

{{ 'value' }}

Affichera la chaîne de caractère value en tant que telle dans votre vue.

{{ 'value' | myfilter }}

Affichera la chaîne de caractère transformated-value dans votre vue.
Je vous laisse imaginer toutes les possibilités que vous pouvez développer avec ça ! :)

Une fois votre classe terminée, vous n’avez plus qu’à la déclarer dans votre services.xml afin d’injecter votre classe et de pouvoir l’utiliser.

...
<services>
    ...
    <service id="acme.twig.myfilter_extension" class="Acme\Bundle\AcmeBundle\Twig\Extension\MyfilterExtension"> 
        <tag name="twig.extension" />
    </service>
    ...
</services>
...

Un point intéressant consiste à donner la possibilité à votre filter d’accepter des paramètres depuis la vue Twig, en plus de la valeur (ou l’objet) sur lequel vous voulez effectuer un traitement. On pourrait imaginer par exemple un appel à notre filter suivant :

{{ 'value' | myfilter('rockin') }}

Et avoir une méthode doSomething() acceptant cette fois-ci un deuxième paramètre.

public function doSomething($value, $parameter)
{
    return 'transformated-' . $value . '-' . $parameter;
}

ce qui nous retournerais, en gardant notre exemple précédent, la chaîne transformated-value-rockin.

Bien sûr, ce n’est ici qu’une application simple, d’autres utilisations plus poussées des filters peuvent être faites comme par exemple passer un manager en paramètre à votre classe lors de l’injection pour pouvoir effectuer du traitement lié à des entités ou autre.

Utiliser Uploadify avec les sessions Symfony2

Pour uploader des images avec Uploadify tout en conservant la même session Symfony2 dans un environnement sécurisé, il est necessaire de passer le paramètre de session pour récupérer la même session lors de l’appel Flash.

Passer son identifiant de session à Uploadify

Dans notre template Twig, nous allons passer notre identifiant de session (app.session.id) au script javascript d’Uploadify pour pouvoir le récupérer par la suite dans sf2.

{% extends "::base.html.twig" %}
{% block css %}
    {{ parent() }}
    <link href="{{ asset('bundles/novawaycms/js/uploadify/uploadify.css') }}" rel="stylesheet" type="text/css" />
{% endblock %}

{% block body %}
<form><input id="file_upload" type="file" name="file_upload" /></form>
{% endblock %}

{% block js %}
    {{ parent() }}
<script type="text/javascript" src="{{ asset('bundles/novawaycms/js/uploadify/swfobject.js') }}"></script>
<script type="text/javascript" src="{{ asset('bundles/novawaycms/js/uploadify/jquery.uploadify.v2.1.4.min.js') }}"></script>

<script type="text/javascript">

$(document).ready(function() {
    $('#file_upload').uploadify({
        'uploader'  : '{{ asset('bundles/novawaycms/js/uploadify/uploadify.swf') }}',
        'script'    : '{{ path("processUpload") }}',
        'scriptData': {'sid':'{{app.session.id}}'},
        'cancelImg' : '{{ asset('bundles/novawaycms/js/uploadify/cancel.png') }}',
        'auto'      : true,
        'buttonText'  : 'Parcourir ...',
        'multi'          : true,
        'fileExt'     : '*.jpg;*.gif;*.png',
        'fileDesc'    : 'Fichiers Images Web (.JPG, .GIF, .PNG)',
        'onComplete'  : function(event, ID, fileObj, response, data) {

        }
    });
});
{% endblock %}

On ajoute le paramètre sid qui contient notre identifiant de session Symfony2 à la requête qui sera éxécutée par la librairie.

Récupérer l’identifiant de session dans Symfony2

Puis, on crée notre listener de session UploadifySessionListener que nous ajouterons dans un dossier EventListener de notre bundle.

<?php

/*
 * Override Session listener for uploadify
 */

namespace Novaway\Bundle\CmsBundle\EventListener;

use Symfony\Component\DependencyInjection\ContainerInterface;

use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;

/**
 * Sets the session on the request.
 *
 * This will also start the session if it was already started during a previous
 * request.
 *
 */
class UploadifySessionListener
{
    private $container;
    private $autoStart;

    public function __construct(ContainerInterface $container, $autoStart = false)
    {
        $this->container = $container;
        $this->autoStart = $autoStart;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
            return;
        }

        if (!$this->container->has('session')) {
            return;
        }

        $request = $event->getRequest();
        if ($request->hasSession()) {
            return;
        }

        $request->setSession($session = $this->container->get('session'));

        if ($request->getMethod() == 'POST' &&
            $this->container->get('request')->request->has('Filename') &&
            $this->container->get('request')->request->has('sid')) {

            session_id($this->container->get('request')->request->get('sid'));

            //fix problème de récuperation du token
            $this->container->get('request')->cookies->set(session_name(), $session->getId());
        }

        if ($this->autoStart || $request->hasPreviousSession()) {
            $session->start();
        }
    }
}

Il ne reste plus qu’à dire à notre application d’utiliser notre listener de session à la place de celui par défaut.

Pour cela, nous allons surcharger celui-ci grâce à l’injection de dépendance dans notre fichier de configuration (app/config/config.yml) :

    parameters:
        session_listener.class: Novaway\Bundle\CmsBundle\EventListener\UploadifySessionListener

Uploadify est désormais utilisable en mode connecté.

Note: pour illustrer ce billet, nous passons directement l’id de session brute. Dans un environnement de production, il serait préférable de le crypter/décrypter pour éviter des injections de session.

Twig: Donner une couleur de fond à vos cellules de tableau pair et impair

Lorsque nous générons des tableaux, il est plus facile de lire les données d’une ligne en changeant de couleurs entre la position pair et impaire. Voici comment le faire dans vos templates twig:

{% for record in records %}
<tr class="{% if loop.index is divisibleby(2) %}odd{% else %}even{% endif %}">
...
</tr>
{% endfor %}

Il vous reste maintenant à déclarer les 2 styles (odd, even) dans votre feuille css.

Twig: accès aux éléments, variables et constantes dans Symfony2

Voici une liste non exhaustive des éléments accessibles dans vos modèles twig

  • app.security
    • .token
      • .key
      • .user
      • .roles
      • .authenticated
      • .attributes
    • .alwaysAuthenticate
  • app.user (entity User)
  • app.request
    • .attributes
    • .query
    • .server
    • .files
    • .cookies
    • .headers
    • .content
    • .languages
    • .charsets
    • .acceptableContentTypes
    • .pathInfo
    • .requestUri
    • .baseUrl
    • .basePath
    • .method
    • .format
  • app.session
    • .locale
    • .defaultLocale
    • .saved
  • app.environment
  • app.debug