2

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

Я попытался выполнить «директиву по разделению интересов». Я сделал это, создав сервисный уровень, который выполняет операции 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. 
} 

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

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 
} 

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

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

ответ

0

Antony предлагает что-то вроде закреплять в __destruct () EntityManager. Однако, поскольку вы не знаете, изменились ли сущности, вы не хотите каждый раз вызывать флеш, даже если у вас есть только сценарий, доступный только для чтения.

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

$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); 

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

$listener->flush(); 
0

Я охотно признаю, что я абсолютно ничего не знаю о Zend, PHP или Doctrine2 ...

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

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

+0

Doctrine2 реализует шаблон работы, но как можно сказать, что этот образец срабатывает? Вы говорите, что ваш уровень сервиса контролирует это, но знает ли он, когда контроллер завершил добавление/удаление/обновление объектов? Единственный способ, который я вижу, - сделать явный entityManager-> flush() в контроллере, чтобы это произошло? – Aleksander 2010-11-25 10:59:38

Смежные вопросы