Utilizando funções de um banco de dados específico com o Doctrine2 e o Symfony2

Um dos ganhos de performance do Doctrine2 é devido a sua DQL conter apenas as funções que são comuns a todos os bancos de dados.

Para utilizarmos funções específicas de cada banco de dados (por exemplo, a função IFNULL do MySQL ou a função NVL do Oracle), o Doctrine nos permite adicioná-las através de extensões.

Segue aqui um exemplo para adicionar uma função YEAR, que retorna o ano de uma data fornecida, utilizando a função EXTRACT do Oracle:

Primeiro adicione um diretório que irá conter a sua função, por exemplo DoctrineExtensions\Query\Oracle.

Dentro deste diretório vamos criar a classe Year.php, que irá conter a nossa função:


<php
namespace DoctrineExtensions\Query\Oracle;

use Doctrine\ORM\Query\Lexer,
    Doctrine\ORM\Query\AST\Functions\FunctionNode;

class Year extends FunctionNode
{
    private $date;

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return sprintf(
                'EXTRACT(YEAR FROM %s)',
                $sqlWalker->walkArithmeticPrimary($this->date));
    }

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->date = $parser->ArithmeticPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

A classe Year deve estender a classe FunctionNode, que requer que sejam implementados dois métodos: getSql e parse. Informações mais detalhadas podem ser encontradas no artigo do cookbook do Doctrine "DQL user defined functions"

Registrando a função

Agora, só precisamos disponibilizar a função YEAR ao DQL do Doctrine. Para isso, é necessário registrá-la, através das configurações do Doctrine no arquivo app/config/config.yml, sob a chave dql. Logo abaixo da chave dql, você deve definir a chave do tipo da sua função, que pode ser: string_functions, numeric_functions ou datetime_functions. Em seguida, vem a chave com o nome da sua função e a localização da respectiva classe:


# Doctrine Configuration
doctrine:
  orm:
    dql:
      datetime_functions:
        year: DoctrineExtensions\Query\Oracle\Year

Dica: Antes de escrever a sua função, verifique se ela já existe no repo DoctrineExtensions, que contém uma coleção de funções, com várias contribuições.

Mais sobre