Utiliser les fonctions de date SQL avec doctrine2 et symfony2

Merci à Florent Viel pour m’avoir refilé le tips (c’est un tueur) !

Grâce à SQL, il est possible de manipuler des dates en utilisant les fonction MONTH(), MINUTE(), etc… plus d’info sur les manipulations de dates en SQL.

Cependant, il est parfois utile de pouvoir les utiliser dans doctrine (par exemple comme dans mon cas en travaillant sur Symfony2 (v2.3 à l’heure où j’écris ce billet)). Avant de pouvoir les utiliser facilement comme dans cet exemple :

$qb = $this->createQueryBuilder('p')
            ->select('count(p) as activity, hour(p.created_at) as hour, dayofweek(p.created_at) as journey')
            ->groupBy('hour, journey');

Il est nécessaire de faire un petit prérequis qui indiquera à doctrine comment utiliser ces fonctions jusqu’à lors inconnues pour lui.

Dans un dossier DQL dans mon bundle (par exemple), créer un fichier Month.php qui renseigne comment parser un format date

<?php

namespace YourApp\YourBundle\DQL;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

/**
 * DateFunction ::= "HOUR" "(" ArithmeticPrimary ")"
 */
class Month extends FunctionNode
{
    public $dateExpression;

    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->dateExpression = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(SqlWalker $sqlWalker)
    {
        return 'MONTH(' .
            $this->dateExpression->dispatch($sqlWalker) .
        ')';
    }
}

Ensuite, dans le fichier de config config.yml de votre application, rajoutez les différentes fonctions que vous souhaitez utiliser :

doctrine:
    orm:
        entity_managers:
                dql:
                    datetime_functions:
                        date: YourApp\YourBundle\DQL\Date
                        hour: YourApp\YourBundle\DQL\Hour
                        month: YourApp\YourBundle\DQL\Month

A partir de là, vous pourrez utiliser vos fonctions de manipulation de dates comme en SQL.