Doctrine 2 → Пользовательские функции DQL
Допустим, что вы используете ORM Doctrine 2 и что вам необходимо выбрать из базы некие записи, но не просто так, а по хитрому. Выборка должна осуществляться по хешу какого-то поля, значение в котором вы не хотите никому показывать из соображений безопасности. Пример, возможно, и надуманный, но не в этом суть... Короче говоря, нужно реализовать подобный запрос:
1 2 | SELECT * FROM `spam` AS `s`
WHERE MD5(`s`.`secretfield`) = 'hash';
|
Дальнейшие действия хоть и касаются DQL и Doctrine, но будут описаны в контексте фреймворка Symfony 2. Оригинальную статью можно обнаружить в документации
Вернёмся к задаче. Недолго думая, метод, выбирающий нужные значения, пропишется в репозитории:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php
namespace Hypersoft\UltraBundle\Entity\Repository;
use Doctrine\ORM\EntityRepository;
class SpamRepository extends EntityRepository
{
/**
* @param string $hash
* @return array
*/
public function getSpamByHash($hash)
{
$qb = $this->createQueryBuilder('s');
return $qb
->where('MD5(s.secretfield) = :hash')
->setParameter('hash', $hash)
->getQuery()
->getResult();
}
}
|
Однако попытка получить результат, используя этот метод, закончится неудачно, так как будет сгенерирована ошибка, мол, что за MD5? Сообщение дословно не помню, но важно, что эта функция доктрине неизвестна.
Выход из этой ситуации, естетственно, имеется. Для начала опишем саму функцию
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php
namespace Hypersoft\UltraBundle\ORM;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\Parser;
/**
* Example: MD5(xyz)
*/
class Md5 extends FunctionNode
{
protected $argument;
/**
* @param \Doctrine\ORM\Query\SqlWalker $sqlWalker
* @return string
*/
public function getSql(SqlWalker $sqlWalker)
{
return 'MD5(' . $this->argument->dispatch($sqlWalker) . ')';
}
/**
* @param \Doctrine\ORM\Query\Parser $parser
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->argument = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
|
Следующим делом уведомим ORM о том, что требуемая функция описана, и расположена по такому-то адресу в таком-то классе.
1 2 3 4 5 6 7 8 | # app/config/config.yml
doctrine:
dbal:
# bla-bla-bla
orm:
dql:
string_functions:
md5: Hypersoft\UltraBundle\ORM\Md5
|
Вот, собственно, и всё.
Комментарии
Мне пока довелось только MD5 и RAND вводить.
Наткнулся только на этот бандл. Но тут 4и всего и то, так, по нужде.
Обидно, но если найдётся, то я обязательно сброшу. Помню ещё, что он вообще был такой глобальный, там не то к Twig были какие-то дополнения, не то ещё к чему. В общем он такой большой был.
Вот и всё что я помню, гражданин Начальник.