Pregunta

Tengo una aplicación donde uso PHP con marco Zend y Doctrine2 como ORM. Mi pregunta está relacionada con la cantidad del controlador preferentemente debe saber sobre el modelo y la persistencia capa subyacente. Idealmente, diría que este es 'nada' a mí mismo - el controlador no debe saber nada acerca de cómo / cuando las entidades se conservan. Sin embargo, creo que esto no siempre es la mejor solución (?).

He tratado de seguir la "separación de las preocupaciones de las directivas de diseño. He hecho esto mediante la creación de una capa de servicio que realiza las operaciones CRUD en mis modelos. Véase el siguiente ejemplo:

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.
}

Como se puede ver el controlador no sabe nada acerca de la persistencia, pero para obtener este resultado que necesito para llevar a cabo tanto persisten () y al ras () dentro de cada llamada a la createXXX () o updateXXX () de la capa de servicios . Yo prefiero que se haga algo como esto:

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
}

Sin embargo, esto hace que falle Doctrine2 como lo hace persistir los objetos de la base de datos en el orden equivocado - se conservan los privilegios antes de secciones (¡no sé si puedo dar instrucciones para realizar esta doctrina de una manera ordenada ??). Los privilegios se equivoca Identificación de las secciones, que no se conserva todavía.

De todos modos, la gran cuestión aquí es si debería intentar aplazar el lavado hasta que todos los objetos han sido creados y las relaciones se han establecido. El objetivo es tener una transacción que hace todo por escrito a la base de datos - que por lo tanto debe ser activado por el controlador (ya que es el único saber cuándo se realiza la construcción de objetos y la relación), con lo que 'contaminar' el controlador con el conocimiento de la capa de persistencia?

¿Fue útil?

Solución

Antony sugiere algo así como de enganche en __destruct () del EntityManager. Sin embargo, ya que no saber si las entidades raelly cambiaron no desea llamar a ras cada vez, incluso si sólo tiene un escenario de sólo lectura.

Por lo tanto, la capa de servicio debe no tirar pero el controlador, que fácilmente podría utilizar la Doctrina EventManager tener cada acción capa de servicio de envío de un evento "requireFlush":

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

Probablemente debería escribir algún tipo de función de conveniencia para esto.

A continuación, escribe su propio detector de eventos:

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();
         }
    }
}

Ahora se registra ese oyente en su archivo de arranque:

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

Y dentro de su controlador puede desencadenar la descarga demora si es necesario en una devolución de llamada postDispatch en cada petición).

 $listener->flush();

Otros consejos

Me fácilmente a admitir que no sé absolutamente nada acerca de Zend, PHP o Doctrine2 ...

Sin embargo, esto suena como que necesita una implementación de la unidad de trabajo patrón. Yo trabajo con MVC utilizando ASP.NET y C # y tener algo que hace eso.

Una vez dicho esto mis reguladores simplemente llaman la capa de servicio y le toca a la capa de servicios de control cuando la transacción se ha comprometido a la tienda de persistencia (la base de datos en mi caso)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top