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.

Créer une requête SQL native dans Symfony2 avec Doctrine2

Il peut être intéressant voir obligatoire dans certains cas complexes d’avoir recours aux requêtes SQL native directement dans Symfony2, tout en passant par l’ORM et en récupérant des objets à la suite de cette requête.

Voici un exemple d’utilisation dans un Repository Symfony2:

use Doctrine\ORM\Query\ResultSetMapping;
$rsm = new ResultSetMapping();
$rsm->addEntityResult('Novaway\Bundle\CmsBundle\Entity\Project', 'p');
$rsm->addFieldResult('p', 'id', 'id');
$rsm->addFieldResult('p', 'title', 'title');

$sql = 'SELECT p.id, p.title FROM project p JOIN project_related pr ON p.id = pr.related_project_id WHERE pr.project_id = ?';

$query = $this->_em->createNativeQuery($sql, $rsm);
$query->setParameter(1, $idProject);

$projects = $query->getResult();

Récupérer l’ID d’un objet dans un Form\Type Symfony2 pour le QueryBuilder Doctrine

Il peut vous arriver d’avoir besoin de connaître l’ID de l’objet édité dans un formulaire, et ce directement dans la classe xxxType.php (La classe de votre formulaire).

Voilà comment récupérer dans un premier temps l’ID de l’objet dans la méthode buildForm (dans notre exemple il s’agit d’un objet Tag):

public function buildForm(FormBuilder $builder, array $options)
{
$idTag= $builder->getData()->getId();

Une fois récupéré, il est possible de le passer dans le Query Builder Doctrine de la manière suivante:

$builder->add('parent', 'entity', array(
'class' => 'Novaway\\CmsBundle\\Entity\\Tag',
'query_builder' => function(EntityRepository $er) use ($idTag)
{
$qb = $er->createQueryBuilder('t')
->where('t.parent IS NULL');

if (!is_null($idTag)) {
$qb->where('t.id != :id')
->setParameter('id', $idTag);
}

return $qb->orderBy('t.title', 'ASC');
},
'required' => false,
'empty_value' => '= Parent ='
));

Voilà une astuce bien pratique pour afficher du contenu plus avancé dans les widgets entity par exemple.

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

Utiliser des variables de session dans un template Twig

Si l’on souhaite appeler des variables de session à l’intérieur d’un template twig, on peut utiliser la variable globale app.session.

Exemple d’un objet Info déclaré dans un contrôleur :

$info = new Info();
$this->container->get('request')->getSession()->set('info', $info);

Pour l’appeler sa propriété titleMeta, depuis un template twig :

{{ app.session.get('info').titleMeta }}