symfony2 update related entity in eventListener

2019-09-06 00:03发布

We have three entities:

  1. MaterialAssigned
  2. Stock
  3. Job

MaterialAssigned holds three fields:

  1. Quantity (int)
  2. Relation with a Job Entity
  3. Relation with a Stock entity

We are try to write a preUpdate() on MaterialAssigned which takes old and new Quantity values, do some calculation and update the overall total quantity in the related Stock Entity. When we var_dump() values along our logic, everything seems to work as expected, however the related Stock entity never gets updated.

That's the relevant code from the EventListener:

public function preUpdate(PreUpdateEventArgs $eventArgs)
{
    $entity = $eventArgs->getEntity();
     if ($entity instanceof MaterialAssigned) {

        $changeArray = $eventArgs->getEntityChangeSet();
        $pre_quantity = $changeArray['quantity'][0];
        $post_quantity = $changeArray['quantity'][1];

        // Here we call the function to do the calculation, for testing we just use a fixed value
        $entity->getStock()->setTotal(9999);

        $em   = $eventArgs->getEntityManager();
        $uow  = $em->getUnitOfWork();
        $meta = $em->getClassMetadata(get_class($entity));
        $uow->recomputeSingleEntityChangeSet($meta, $entity);
    }
}

1条回答
可以哭但决不认输i
2楼-- · 2019-09-06 00:26

The issue here is that preUpdate is restricted by Doctrine to not allow any Entities to be updated from within this method. onFlush on the other hand does allow the update of Entities, and replaces the need for three separate methods (update, persist, remove).

We then found the following guide which hints at a solution: Tobias Sjösten's guide

Our code now looks like:

public function onFlush(OnFlushEventArgs $args)
{
    $this->em = $args->getEntityManager();
    $uow = $this->em->getUnitOfWork();

    // These collects an array of all the changes that are going to be flushed.
    // If you do not wish to see deleted entities just remove the line $uow->getScheduledEntityDeletions()
    $entities = array_merge(
        $uow->getScheduledEntityInsertions(),
        $uow->getScheduledEntityUpdates(),
        $uow->getScheduledEntityDeletions()
    );

    foreach ($entities as $entity) {

        if ($entity instanceof MaterialAssigned) {

            // This gets an array filled with the changes for the entire entity
            $changeArray = $uow->getEntityChangeSet($entity);

            $stock = $entity->getStock();

            // Here we call our function passing $changeArray.
            // This does some math and update the value. For simplicity we just
            // set the value manually in this example
            $stock->setTotal(9999);

            $md = $this->em->getClassMetadata('Northerncam\AppBundle\Entity\Stock');
            $uow->recomputeSingleEntityChangeSet($md, $stock);
        }
    }
}

This is the print_r() of $changeArray:

array (size=1)
    'quantity' =>
        array (size=2)
            0 => int 10
            1 => int 50
查看更多
登录 后发表回答