Разделение опасений - где промыть () в структуре MVC (контроллер VS ServiceLayer)

StackOverflow https://stackoverflow.com/questions/4276094

Вопрос

У меня есть приложение, в котором я использую PHP с Zend Framework и Doctrine2 в качестве ORM. Мой вопрос связан с тем, насколько предпочтительно контроллер должен знать о базовой модели и настойчивом слое. В идеале я бы сказал, что это «ничего» сам - контроллер ничего не должен знать о том, как / когда сущности сохраняются. Однако я чувствую, что это не всегда лучшее решение (?).

Я пытался следовать руководству «разделение озабоченности». Я сделал это, создав сервисный слой, который выполняет операции CRUD на моделях. См. В следующем примере:

public function testbuildAction()
{        
    // create section
    $sectionService = new \MyAPP\Model\Service\Acl\SectionService();        
    $sectionA       = $sectionService->createSection('SectionA-NAME');

    // create privilege with the above section
    $privilegeService   = new \MyAPP\Model\Service\Acl\PrivilegeService();
    $privilegeA = $privilegeService->createPrivilege(
                            $sectionA, 
                            \MyAPPFrameWork\Model\Acl\Privilege::PERMISSION_EDIT
                        );

    // create a role with the privilege above. A role must have at least one priv.
    $roleService = new \MyAPP\Model\Service\Acl\RoleService();
    $role        = $roleService->createRole('Role-NAME', $privilegeA); 

    // this loads a managed User object (managed by EntityManager)
    $user = $this->_helper->IdentityLoader(); 
    $user->addRole($role); // add the role to this user
    $userService = new \MyAPP\Model\Service\Core\UserService();        
    $userService->updateUser($user); // persist the updates.
}

Как вы можете видеть, контроллер ничего не знает о настойчивости, но чтобы получить этот результат, мне нужно выполнить как упорство (), так и в Shipped () внутри каждого вызова на CreatexXX () или updatexxxx () методах сервисного слоя. Я бы предпочел сделать что-то вроде этого:

public function testbuildAction()
{        
    // create section
    $sectionService = new \MyAPP\Model\Service\Acl\SectionService();        
    $sectionA       = $sectionService->createSection('SectionA-NAME');

    // create privilege with the above section
    $privilegeService   = new \MyAPP\Model\Service\Acl\PrivilegeService();
    $privilegeA = $privilegeService->createPrivilege(
                            $sectionA, 
                            \MyAPPFrameWork\Model\Acl\Privilege::PERMISSION_EDIT
                        );

    // create a role with the privilege above. A role must have at least one priv.
    $roleService = new \MyAPP\Model\Service\Acl\RoleService();
    $role        = $roleService->createRole('Role-NAME', $privilegeA); 

    // this loads a managed User object (managed by EntityManager)
    $user = $this->_helper->IdentityLoader(); 
    $user->addRole($role); // add the role to this user

    // persist it all (all service-classes access the same entitymanager).
    $roleService->flush(); // everything is persisted
}

Но это вызывает отклонение доктрины2, так как он сохраняет объекты в базу данных в неправильном порядке - привилегии сохраняются перед разделами (не знаю, если я могу проинструктировать доктрину выполнять это в упорядоченном порядке ??). Привилегии не имеют неправильного удостоверения личности для разделов, которые еще не сохраняются.

Во всяком случае, большая проблема здесь - это ли я попытаться отложить промывку, пока все объекты не будут созданы, и отношения были установлены. Глава, имеющая одну транзакцию, которая все делает запись в базу данных, которая, следовательно, должна быть вызвана контроллером (поскольку это единственное, что зная, когда создается объект и соотношение), тем самым «загрязняя» контроллер со знанием Устойчивый слой?

Это было полезно?

Решение

Antony предполагает что-то вроде крючка в __dessuctuct () entitymanager. Однако с тех пор, как вы не знаете, изменены ли предприятия, вы не хотите звонить в Flash каждый раз, даже если у вас есть только сценарий только для чтения.

Поэтому сервисный слой не должен обмануть, но контроллер, вы можете легко использовать Doctrine EventManager, чтобы каждый сервисный слой отправлял событие «ТребованиеFLUSH»:

$em->getEventManager()->dispatchEvent("requireFlush", new OnFlushEventArgs($em));

Вы, вероятно, должны написать какую-то функцию удобства для этого.

Затем вы пишете свой собственный слушатель событий:

class DelayFlushListener
{
    private $requiresFlush = true;
    private $delayFlush = true;

    public function __construct($delayFlush = true) {
       $this->delayFlush = $delayFlush;
    }

    public function requireFlush(EventArgs $args) {
        $this->em = $args->getEntityManager();
        if ($this->delayFlush) {
            $this->requiresFlush = true;
        } else {
            $this->em->flush();
        }
    }

    public function flush() {
         if ($this->requiresFlush) {
             $this->em->flush();
         }
    }
}

Теперь зарегистрируйте этот слушатель в своем загрузке:

 $listener = new DelayFlushListener();
 $em->getEventManager()->addEventListener(array("requireFlush"), $listener);

А внутри вашего контроллера вы можете заставить задержку Flush, если необходимо в обратном вызове PostDispatch в каждом запросе).

 $listener->flush();

Другие советы

Я готовлюсь признаю, что знаю абсолютно ничего о Zend, PHP или доктрине2 ...

Но это звучит так, будто вам нужна реализация Блок работы шаблон. Я работаю с MVC, используя ASP.NET и C # и иметь то, что делает это.

Сказав, что мои контроллеры просто вызовут сервисный слой, и это зависит от сервисного слоя для управления, когда транзакция предана хранилище настойчивости (база данных в моем случае)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top