UNIX_TIMESTAMP, ROUND и другие DQL запросы через queryBuilder в Symfony 2

от автора

Как известно у Symfony 2 в Doctrine 2 из «коробки» нет поддержки стандартных функций Mysql, таких как UNIX_TIMESTAMP или ROUND и еще несколько других. В первую очередь статья для того чтобы понять как дополнять DQL своими функциями. Но перед написанием как следует «похабрить» и по «гитхабить», а вдруг уже кто-то написал, советую не городить велосипеды и воспользоваться уже готовыми наработками, например GitHub MysqlDoctrineFunctions
Статья больше подходит для новичков.

Итак, задание! Сделать функцию ROUND, приступим:

Первое что нам нужно это сделать описание нашего метода через FunctionNode из Doctrine\ORM\Query\AST\Functions\FunctionNode.
Создадим в нашем Bundle папку с названием DQL (можно конечно обозвать как угодно).
У меня это выглядит так: src/Acme/SimpleBundle/DQL

Создаем в этой директории файл с названием например Round.php, получается src/Acme/SimpleBundle/DQL/Round.php
Содержимое:

namespace Acme\SimpleBundle\DQL;  use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\AST\Functions\FunctionNode;  class Round extends FunctionNode {     protected $roundExp;     protected $roundPrecission;      public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)     {         return 'ROUND(' .             $sqlWalker->walkArithmeticExpression($this->roundExp) . ','.             $sqlWalker->walkArithmeticExpression($this->roundPrecission)         .')';     }      /**      * parse - allows DQL to breakdown the DQL string into a processable structure      * @param \Doctrine\ORM\Query\Parser $parser      */     public function parse(\Doctrine\ORM\Query\Parser $parser)     {         $parser->match(Lexer::T_IDENTIFIER);         $parser->match(Lexer::T_OPEN_PARENTHESIS);          $this->roundExp = $parser->ArithmeticExpression(); // Указываем первое значение функции         $parser->match(Lexer::T_COMMA); // Добавим разделитель         $this->roundPrecission = $parser->ArithmeticExpression(); // И добавим второе значение          $parser->match(Lexer::T_CLOSE_PARENTHESIS);     } } 

Нам нужно реализовать две функции, функция getSql как и ясно из названия вернет в ORM подготовленный SQL, а parse предназначена для парсинга переменных передаваемых в запрос, например round(sum,2)

Для того чтобы передавать параметры в функцию, нам необходимо определить внутренние переменные, в данном примере это:

    protected $roundExp;     protected $roundPrecission;     // Чтобы было понятно то это выглядит так  round(roundExp, roundPrecission) 

Далее нам необходимо подсказать доктрине где искать наши функции, для этого укажем в config.yml в секции doctrine: что у нас есть дополнения к стандартному DQL, у меня это выглядит так:

doctrine:     dbal:         driver:   %database_driver%         host:     %database_host%         port:     %database_port%         dbname:   %database_name%         user:     %database_user%         password: %database_password%         charset:  UTF8      orm:         auto_generate_proxy_classes: %kernel.debug%         auto_mapping: true          dql:           string_functions:             unix_timestamp: \Mart\AdminBundle\DQL\UnixTimestamp           numeric_functions:             round: \Mart\AdminBundle\DQL\Round 

Теперь при выполнении запроса вида:

$queryBuilder->andWhere("ROUND (sum) , 1) = :condition"); 

Доктрина полезет в наши функции и составит правильный запрос в Mysql.

ссылка на оригинал статьи http://habrahabr.ru/post/209870/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *