Doctrine2 event listener: postPersist o non postPersist?

Oggi mi sono imbattuto in un problema apparentemente semplice che mi ha dato un po’ di filo da torcere: il postPersist.
Il problema è abbastanza comune: devo aggiornare alcuni oggetti di una collezione quando uno di questi viene modificato o inserito con particolari caratteristiche. Sto sviluppando un applicazione con Sf2 e ho configurato il config.yml per gestire l’evento postPersist e postUpdate di Doctrine2 come servizio.

services:
    listener.entity.myEntity
:
        class
: Ideato\MyBundle\Listener\Entity\MyEntityListener
        tags
:
            - { name
: doctrine.event_listener, event: postPersist }
            - { name
: doctrine.event_listener, event: postUpdate }

Quindi creo la classe per il listener

<?php
namespace Ideato\MyBundle\Listener\Entity;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Ideato\MyBundle\Entity\MyEntity;

class MyEntityListener
{
    public function postUpdate(LifecycleEventArgs $args)
    {
        $this->postPersist($args);
    }

    public function postPersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        if ($entity instanceof MyEntity) {
            $em = $args->getEntityManager();
            // query che interpellano il repository dell'entità e alcune relazioni
        }
    }
}

Oibò banale! Fatto in millllioni di altri posti; lancio i test: ROSSI!
Azzzzzpiterina cosa c’è di diverso? Risposta: le relazioni!
Ebbene si, nonostante il cascading sul persit e l’update, l’evento postPersist/Update viene invocato immediatamente dopo il persist o l’update dell’entità ma prima del persist delle relazioni. Se questo in relazioni oneToOne, oneToMany o manyToOne non provochi problemi di sorta, per le manyToMany sì, sopratutto nel caso in cui la condizione che serve è proprio sulla relazione. Infatti nelle relazioni oneTo* possiamo spostare il listener “sull’altra” entità che viene persistita. Per quanto riguarda le manyToMany, non c’è una entità alla quale si possa agganciare il listener.
Soluzione: agganciarsi al postFlush. Questo è invocato quando tutto è andato a buon fine e solo se c’è stato qualcosa da memorizzare (è cambiata qualche proprietà da persistere), altrimenti non viene invocato. Una limitazione che nel mio caso rafforza la correttezza dell’invocazione.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInEmail this to someone
Written by kea

Leave a Reply

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *