in Профессиональное

Symfony2: выборка случайной записи при помощи Doctrine2 Repository

Я уже рассматривал в одной из прошлых статей случайные выборки (см.). Сейчас мы самым простым способом интегрируем получение случайной записи в Symfony2 проект при помощи Doctrine2 Repository.

Мои entities определены по привычке в YAML формате, поэтому я буду описывать именно его. Итак, укажем нашей сущности использовать кастомный Repository:

# src/Vendor/MyBundle/Resources/config/doctrine/metadata/orm/Vendor.MyBundle.Entity.User.dcm.yml
Vendor\MyBundle\Entity\User:
    type: entity
    table: user
    ...
    repositoryClass: Vendor\MyBundle\Repository\UserRepository
    ...

После этого можно создать класс UserRepository.php в директории src/Vendor/MyBundle/Repository или же выполнить команду doctrine:generate:repositories:

>php app\console doctrine:generate:repositories VendorMyBundle
Generating entity repositories for "VendorMyBundle"
  > OK generating Vendor\MyBundle\Repository\UserRepository
  > SKIP no custom repository for Vendor\MyBundle\Entity\UserData

У нас есть класс репозитория. Добавим в него метод выбора случайного юзера:

  public function getRandomUser()
  {
    // mapper для результата
    $rsm = new ResultSetMapping;
    $rsm->addEntityResult('Vendor\MyBundle\Entity\User', 'u');
    $rsm->addFieldResult('u', 'id', 'id');
    // тут я использую NativeQuery - перевести этот запрос в DQL для меня сейчас слабо )
    // также примем допущение что user не содержит "дыр" в ID
    $query = $this->getEntityManager()->createNativeQuery(
      'SELECT id FROM user JOIN ( SELECT CEIL(RAND() * (SELECT MAX(id) FROM user)) AS id ) AS r2 USING (id)',
      $rsm
    );
    // ищем случайный ID
    $user = $query->getSingleResult();
    // на выходе получаем полноценный Vendor\MyBundle\Entity\User (хотя как вариант можно написать маппер на все необходимые поля)
    return $this->find($user->getId());
  }

В контроллере пользуемся репозиторием так:

  public function someAction()
  {
    $em = $this->get('doctrine.orm.entity_manager');
    $userRepo = $em->getRepository('VendorMyBundle:User');
    $randomUser = $userRepo->getRandomUser();
  }

P.S. данный код возможно далек от идеала, тем не менее на пробную работу с репозиторием и native sql мной было потрачено некоторое время, результатами своих изысканий я с вами и делюсь )

Write a Comment

Comment

*

15 Comments

    • Да, автоматом. Пока не нашел плюсов в аннотациях – кроме того что они более всего документированы.

        • Я имел в виду именно сущности ) Валидация по-моему альтернативного способа и не предполагает. Во всяком случае это не документировано

          • Плюсы аннотаций:
            1) можно скрыть в IDE – Ъ
            2) сущность и описание ее маппинга в одном месте.

            зы: а есть ли какая-то регистрация на сайте? Надоело капчу вводить, да и посты хочу править если что.

  1. По сабжу: а что если это дело вынести в сервисный слой, и метод будет возвращать не HydratedResult а объект QueryBuilder’а, где я смогу заджоинить нужные мне колонки к юзеру, или вообще получить какие-то другие данные на основе этого подзапроса?

    • Ну по факту entity manager это тоже вроде бы служба, так что не вижу препятствий – хотя конечно надо попробовать. А вот необходимость такого решения лично для меня под вопросом – посуди сам, я получаю репозиторий так же как службу, просто на выходе метода не результаты выборки а QueryBuilder.

      Насчет регистрации посмотрю – у меня мультисайт не хочу блоги плодить )) хотя если хочешь тоже покарябать статьи – для тебя – сделаю )

  2. > php app\console doctrine:generate:repositories …

    Выводит ошибку

    [InvalidArgumentException]
    Command “doctrine:generate:repositories” is not defined.

    Did you mean one of these?
    doctrine:generate:entities
    doctrine:generate:entity
    doctrine:generate:form

    • Уважаемый, это статья более чем полуторагодичной давности. Для версии Симфони 2.0.х, версию Doctrine не помню. Для начала рекомендую изучить следующие команды:

      c:\openserver\__src\repo>php app/console list doctrine
      Symfony version 2.1.7-DEV – app/dev/debug

      Available commands for the “doctrine” namespace:
      doctrine:cache:clear-metadata
      doctrine:cache:clear-query
      doctrine:cache:clear-result
      doctrine:database:create
      doctrine:database:drop
      doctrine:ensure-production-settings
      doctrine:fixtures:load
      doctrine:generate:crud
      doctrine:generate:entities
      doctrine:generate:entity
      doctrine:generate:form
      doctrine:mapping:convert
      doctrine:mapping:import
      doctrine:mapping:info
      doctrine:migrations:diff
      doctrine:migrations:execute
      doctrine:migrations:generate
      doctrine:migrations:migrate
      doctrine:migrations:status
      doctrine:migrations:version
      doctrine:query:dql
      doctrine:query:sql
      doctrine:schema:create
      doctrine:schema:drop
      doctrine:schema:update
      doctrine:schema:validate

      Если же говорить о репозиториях, то они насколько я знаю, создаются при выполнении команды doctrine:generate:entities (если кастомный репозиторий прописан в сущности)