VaN
VaN

Reputation: 2210

postPersist event not updating database

I have 2 entities, Invoice and Advance. Advances are related to Invoices, with ManyToOne relation. And when adding or editing and advance, I want the Invoice total to be edited accordingly. I have a listener set for Advances postPersist which looks like this :

class PostPersistListener
{
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function postPersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
        $em = $args->getEntityManager();

        // Advance Listener
        if ($entity instanceof Advance) {

            // Modification du total de la facture mère
            $invoice = $entity->getInvoice();

            echo '<pre>';
            \Doctrine\Common\Util\Debug::dump($invoice);
            echo '</pre>';

            $newTotal = $invoice->getTotalMaster() - $entity->getTotalMaster();
            $invoice->setTotalMaster($newTotal);

            echo '<pre>';
            \Doctrine\Common\Util\Debug::dump($invoice);
            echo '</pre>';

            $em->flush();

        }

    }
}

The event is well triggered. The first dump() displays something like this :

object(stdClass)#1379 (49) {
  ["__CLASS__"]=>
  string(32) "Evo\BackendBundle\Entity\Invoice"
  ["id"]=>
  int(1)
  ["totalMaster"]=>
  float(250)
}

And the second dump() this :

object(stdClass)#1379 (49) {
  ["__CLASS__"]=>
  string(32) "Evo\BackendBundle\Entity\Invoice"
  ["id"]=>
  int(1)
  ["totalMaster"]=>
  float(240)
}

So the "totalMaster" property is modified. But the $em->flush() doesn't seem to update the field in the database. Am i missing something ?

Upvotes: 1

Views: 3260

Answers (2)

Cerad
Cerad

Reputation: 48865

To start with, as it's name implies, PostPersist only get's triggered after the initial persist operation i.e. only for new objects. Editing an existing object will not trigger the event.

From: http://docs.doctrine-project.org/en/latest/reference/events.html#lifecycle-events

postPersist - The postPersist event occurs for an entity after the entity has been made persistent. 
It will be invoked after the database **insert** operations. 
Generated primary key values are available in the postPersist event.

There are also strict limits to what you can do with these events. Basically the flush operation is already underway so anything that updates an entity is problematical at best. Specifically:

From: http://docs.doctrine-project.org/en/latest/reference/events.html#postupdate-postremove-postpersist

The three post events are called inside EntityManager#flush(). 
Changes in here are not relevant to the persistence in the database, 
but you can use these events to alter non-persistable items, like non-mapped fields, logging or 
even associated classes that are directly mapped by Doctrine.

It's barely possible you might get this to work using prePersist and preUpdate but those have their own issues.

@kix has the correct approach. Updating an invoice total is a domain function and should be handled using a domain event.

P.S. You don't need to call persist on existing objects retrieved through Doctrine.

Upvotes: 3

kix
kix

Reputation: 3319

You've missed the $em->persist($invoice) line.

Also, I'd suggest implementing this logic with Symfony's built-in events, not with prePersist listeners. The simple reason behind this is that your code is dealing with business logic and not persistence logic. You should dispatch an AdvanceModified event with the event_dispatcher service (it should be available to your controller) and then process it in a listener.

Upvotes: 0

Related Questions