@koji6ac9h

Где разместить логику в Symfony 3 приложении (+ Doctrine 2)?

Всем привет, может кто посоветует где правильней/лучше разместить логику когда есть несколько сущностей (Doctrine entity) которые имплеменируют общий интерфейс?
Ситуация такая, есть интерфейс Request:

<?php

namespace AppBundle\Entity;

interface Request
    public function approve();
    public function reject();
}


и несколько сущьностей: Invite и JoinRequest в первом компания приглашает человека в компанию, во втором наоборот.

Пример Invite:
<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/** @ORM\Entity */
class Invite implements Request
{

    /**
     * @ORM\Column(type="integer") @ORM\Id @ORM\GeneratedValue
     * @var int
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Company")
     * @ORM\JoinColumn(nullable=false)
     * @var Company
     */
    private $company;

    /**
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(nullable=false)
     * @var User
     */
    private $user;

    public function approve()
    {
        // Some logic here. Add user to company, send mail, add flash message etc...
    }

    public function reject()
    {
        // Same
    }

    // Getters/Setters.
}


также будут и другие типы сущностей (запрос на обмен контактами и т.д.)
Насколько я понял размещать какую либо бизнес логику в самих Doctrine Entity считаеться плохой практикой да и передавать зависимости в Entity (mailer, twig templating, flash messages) выглядит не очень красиво, в контроллере тоже, так что единственное что мне приходит в голову это выделить под все эти Request Entity отдельный сервис, или даже свой под каждый, но не убивает ли это весь смысл полиморфизма?
  • Вопрос задан
  • 945 просмотров
Пригласить эксперта
Ответы на вопрос 2
voronkovich
@voronkovich
Я бы выбрал 2-й вариант - под каждую сущность свой сервис реализующий логику. Не могли бы вы уточнить, что вы имеете ввиду во фразе "убивает смысл полиморфизма"? Полиморфизм не должен быть самоцелью. Предпочитая декорирование наследованию, вы ведь не убиваете смысл наследования?
Ответ написан
myrkoxx
@myrkoxx
developer
Как вариант (если работать с анемичной моделью):

Контроллер:

class InviteController
{
    public function acceptCompanyInviteAction(Invite $invite)
    {
          /** просто как пример */
         $this->get('invite.manager')->acceptCompanyInvite($invite);

         return new Response('acccepted');
    }


Менеджер инвайта:

class InviteManager
{
    /** @var InviteRepository $repository */
    private $repository;

    /** @var EntityManagerInterface $entityManager */
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
        $this->repository = $entityManager->getRepository('AppBundle:Invite'); 
    }
   
    public function acceptCompanyInvite(Invite $invite)
    {
         /** ваша логика  */
        
         $this->entityManager->persiste($invite);
         $this->entityManager->flush($invite);

         return $invite;
    }


Менеджер создается для абстрагирования от репозитория. Использовать репозиторий в контроллере както по мне не очень. У нас, как правило под каждую Entity есть свой репозиторий и менеджер. Структура каталогов в вашем случая у нас такая:

Entity
-----Repository
---------InviteRepository
-----Manager
---------InviteManger
-----Invite

Ну ето очень простой способ, не лучший но довольно акуратный.

А вообще, если есть время ознакомтесь с такими подходами: http://williamdurand.fr/2013/08/07/ddd-with-symfon... и https://jorgearco.com/ddd-with-symfony/ - вот репа последнего: https://github.com/jorge07/ddd-playground
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы