[Symfony] Enregistrer une fonction DQL customisé

J’ai voulut utiliser la fonction SQL LEFT via Doctrine. A ma grande surprise j’ai eu l’erreur suivante :

[Syntax Error] line 0, col 238: Error: Expected known function, got 'LEFT'

oO Mais, pourquoi il m’insulte alors que mon SGBD connait bien la fonction LEFT ?

Pourquoi cette erreur ?

 

Si vous utiliser Doctrine, vous utiliser le DQL (Doctrine Query Langage). Ce langage est une surcouche qui est ensuite traduit en fonction de votre SGBD. Par défaut, toutes les fonctions de votre SGBD ne sont pas forcément intégré à Doctrine.

 

Pourquoi vouloir ajouter de nouvelles fonctions au DQL ?

 

  • Pour prendre en charge une fonction qui existe dans votre SGBD (Système de Gestion de Base de Données), mais pas dans le DQL.
  • Pour ajouter un fonction DQL qui sera convertie en une serie d’instruction SQL (nous verrons un exemple à la fin de l’article)

Création de la classe qui permet de gérer la fonction

 

Cette classe doit hériter de ‘Doctrine\ORM\Query\AST\Functions\FunctionNode’ et donc implémenter les méthodes abstraites ‘parse’ et ‘getSql’. La première méthode permet parser le SQL afin de détecter votre fonction et la seconde de générer le SQL équivalent. Dans mon cas, je souhaite détecter la fonction ‘LEFT’ et le remettre dans le SQL.

:! Pour rappel la fonction ‘LEFT’ permet de récupérer les x caractère de gauche d’une chêne de caractère. La chaine étant passé en premier paramètre et x en second. Avec LEFT(‘1234567′, 2) , on récupère ’12’.

<?php 
namespace Ageo\UtilitiesBundle\DQL; 
use Doctrine\ORM\Query\AST\Functions\FunctionNode; 
use Doctrine\ORM\Query\Lexer; 
/** 
* "LEFT" "(" ArithmeticPrimary ", ArithmeticPrimary)" 
*/ 
class LeftFunction extends FunctionNode { 
       public $stringExpression = null; 
       public $numberExpression = null; 

      public function parse(\Doctrine\ORM\Query\Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); // (2)
		$parser->match(Lexer::T_OPEN_PARENTHESIS); // (3)
		$this->stringExpression = $parser->ArithmeticPrimary(); // (4)
		$parser->match(Lexer::T_COMMA); // (5)
		$this->numberExpression = $parser->ArithmeticPrimary(); // (6)
		$parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3)
	}
	
	public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
	{
		return 'LEFT(' .
			$this->stringExpression->dispatch($sqlWalker) . ', ' .
			$this->numberExpression->dispatch($sqlWalker) .
			')'; // (7)
	}
}

Une fois la fonction crée, il faut la déclarer auprès de doctrine :

</pre>
<pre>doctrine:
    orm:
        dql:
            string_functions:
                 RIGHT: Ageo\UtilitiesBundle\DQL\RightFunction
                 LEFT: Ageo\UtilitiesBundle\DQL\LeftFunction</pre>

Voilà la fonction LEFT va désormais être traité par le processus et dans notre cas être réécrite.

 

Ajout d’une fonction complémentaire non gérer par le SGBD

 

L’autre possibilités est de créer une fonction non géré par votre SGBD. Je pense par exemple à une fonction MIDDLE qui utiliserait les fonction LEFT et RIGHT en SQL.

 

Ajouter un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *