Symfony лучшие практики. Должны ли запросы храниться в репозиториях или службах?

У меня есть вопрос о лучших практиках Symfony 2. Извините, если он немного расплывчатый и субъективный. Думаю, я могу подытожить свой вопрос следующим образом:

"Являются ли хранилища всегда правильными для запросов?".

Сейчас я помещаю большинство своих доктринных запросов в репозитории сущностей. Большинство моих действий с контроллером выполняют типичные вещи, такие как запрос для сущности или коллекции сущностей, генерируют исключение или перенаправление в зависимости от результата этого, в противном случае обновляют одно или несколько объектов. Большинство действий сложнее, чем это можно сделать с помощью стандартных запросов → find, → findBy и т.д. Большинство из них требуют объединения. Когда запрос включает несколько объектов, иногда я не уверен, в каком репозитории он должен идти. Я предполагаю, что есть корневой объект запроса, но... иногда данные из объединенных объектов более важны и релевантны, поэтому он чувствует себя не так поместить его в корневой репозиторий сущностей.

Это работает нормально, но я, как правило, заканчиваю тем же самым, но немного разными запросами в своих репозиториях. Придумывание имен и отслеживание того, что каждый из них делает, может стать запутанным и утомительным. Большинство этих запросов используются только одним или двумя (часто редко используемыми) действиями контроллера в одном контроллере. Я чувствую, что я загромождал свои репозитории со слишком специализированными, редко используемыми вещами.

Кажется, что все, кроме самых простых действий, должны быть инкапсулированы в объект или службу. Итак, я начал выполнять множество своих запросов непосредственно в службе, а не в репозитории. Легко смотреть на действия все в одном месте. Это хорошая практика?

Ответ 1

Ваши запросы должны храниться в вашей сущности репозиториях, а не в ваших контроллерах, чтобы они могли повторно использовать их легко.

То, что хранилища на самом деле. Предоставление повторно используемого места для запросов к базе данных.

Однако есть некоторые ситуации, в которых можно сохранить все ваши запросы в репозитории... особенно когда дело доходит до фильтрации, где может потребоваться много запросов.

Бенджамин Эберлей (создатель Доктрины) рассматривает 5 общедоступных методов в классе, чтобы они были в порядке, и 10 были достаточно большими. Недавно он опубликовал интересную статью под названием "" Об укрощении классов репозитория в доктрине" об этом в своем блоге.

Я частично делаю это как фильтруемое решение для репозитория с помощью KnpLabs в DoctrineBehaviors.

Трейты делают тестирование сложнее, но вы можете иметь более чистый и простой в обслуживании репозиторий ..., где вы должны хранить свои запросы.

Ответ 2

Вы можете сделать что-то между ними.

Определите службу:

blog.post_manager:
    class: Acme\BlogBundle\Entity\Manager\PostManager
    arguments:
        em: "@doctrine.orm.entity_manager"
        class: Acme\BlogBundle\Entity\Post

Затем создайте класс Manager:

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;

class PostManager
{
    protected $em;

    protected $repo;

    protected $class;

    public function __construct(EntityManager $em, $class) {
        $this->em = $em;
        $this->class = $class;
        $this->repo = $em->getRepository($class);
    }

    public function get($id)
    {
        return $this->repo->findById($id);
    }
}

Таким образом, вы можете оставить запросы, в которых они находятся, в репозиториях, позволяя повторно использовать код через службу менеджера, который можно использовать как это в любом контроллере:

$this->container->get('blog.post_manager')->get(1);

Поскольку служба позаботится о том, чтобы ввести класс и менеджер сущностей в класс Manager, это также упрощает работу контроллера и лучше абстрагирует его от модели.