Symfony 2: Doctrine 2 выбор случайных записей из MySQL

symfony-2-doctrine-2

Приветствую всех посетителей моего блога. В процессе разработки очередного проекта на Symfony 2 столкнулся с необходимостью получить случайные записи из MySQL. Как все наверное знают в общем случае эта тема не нова и все решения которые существуют для получения случайных записей из MySQL уже давно известны, но как не странно я не нашел ни одного работающего рецепта как реализовать один из способов с Doctrine 2, как выяснилось в процессе проб и ошибок в Doctrine 2 нельзя этого сделать без напильника. В рамках данного поста я хочу предложить вам в качестве решения данной проблемы простой способ выбора случайных записей из MySQL с помощью Symfony 2, Doctrine 2 Query Builder и MySQL функции RAND().

Добавление функции RAND

Как бы это не было странным, но Doctrine 2 ничего не знает о встроенной функции RAND() в MySQL. Давайте исправим эту досадную оплошность и создадим класс для описания данной функции в DQL:

<?php

namespace Acme\DemoBundle\DQL;

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

class RandFunction extends FunctionNode
{
    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(SqlWalker $sqlWalker)
    {
        return 'RAND()';
    }
}

Следующим шагом нам надо подключить наше описание к списку функций Doctrine 2, для этого давайте откроем конфигурацию нашего приложения Symfony 2 которая хранится как правило в файле app/config/config.yml и добавим для секции doctrine примерно следующее описание для подключение нашей функции:

doctrine:
    orm:
        dql:
            numeric_functions:
                Rand: Acme\DemoBundle\DQL\RandFunction

Создание репозитория и метода получения случайных записей

В рамках данной статьи я не буду описывать, что такое репозитории и для чего они нужны, лучше меня вам про это сможет рассказать официальная документация Symfony 2 или Doctrine 2. Поэтому я просто приведу листинг класса репозитория с реализацией метода выбора случайных записей ниже:

<?php

namespace Acme\DemoBundle\Entity\Repository;

use Doctrine\ORM\EntityRepository;

class SomeRepository extends EntityRepository
{
    /**
     * Get random entities
     *
     * @param int $count Entities count, default is 10
     *
     * @return array
     */
    public function getRandomEntities($count = 10)
    {
        return  $this->createQueryBuilder('q')
            ->addSelect('RAND() as HIDDEN rand')
            ->addOrderBy('rand')
            ->setMaxResults($count)
            ->getQuery()
            ->getResult();
    }
}

Как вы видите метод достаточно прост. Вы возможно можете задать вопрос почему я не использую вызов функции RAND() в ORDER BY? Так вот DQL не поддерживает в ORDER BY использование функций, поэтому генерация случайного значения была перенесена в SELECT запроса с указанием алиаса rand, в дальнейшем в ORDER BY используется имя алиаса.

Настоятельно вам советую обратить внимание на то, что данный метод работает вполне нормально, но он не очень производительный. Для моих целей производительность была не важна, в связи с чем я использую именно этот способ получения случайных записей из MySQL т.к. на мой субъективный взгляд он самый простой. Прошу вас учитывать это в своих приложениях и не использовать данный подход на больших массивах данных. В случае, если у вас ситуация схожая с моей, то пользуйтесь с удовольствием и до новых встреч в будущих постах.

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

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