16
votes

Documentation says:

Changes to fields of the passed entities are not recognized by the flush operation anymore, use the computed change-set passed to the event to modify primitive field values.

But it also says:

getEntityChangeSet() to get a copy of the changeset array. Changes to this returned array do not affect updating.

Does this mean I can not change fields of an entity in preUpdate event listener? If not, how would I go about accomplishing this update?

3
please provide link to that documentation - GusDeCooL

3 Answers

37
votes

Apparently you need to recompute the changeset yourself for the changes to take effect:

$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
$meta = $em->getClassMetadata(get_class($entity));
$uow->recomputeSingleEntityChangeSet($meta, $entity);
5
votes

Alternatively you can use PreUpdateEventArgs class (http://www.doctrine-project.org/api/orm/2.2/class-Doctrine.ORM.Event.PreUpdateEventArgs.html). Forexample:

public function preUpdate(PreUpdateEventArgs $args)
{
    $entity = $args->getEntity();

    if ($entity instanceof Product)
    {
        $args->setNewValue(
            "discount",
             123
        );
    }
}
0
votes

This answer is mostly targeted at this comment.

It's safe to change properties of the updated entity in preUpdate, but not of any of it's related entities.

https://www.doctrine-project.org/projects/doctrine-orm/en/2.11/reference/events.html#preupdate

Changes to associations of the updated entity are never allowed in this event, since Doctrine cannot guarantee to correctly handle referential integrity at this point of the flush operation.

You can however do that in onFlush.

public function onFlush(OnFlushEventArgs $args): void
{
    foreach ($this->em->getUnitOfWork()->getScheduledEntityUpdates() as $entity) {
        if (!$entity instanceof Foo) {
            continue;
        }

        $bar = $foo->getBar();
        $bar->setBaz('Baz');

        // Tell the unit of work manually that the entity has changed
        $args->getEntityManager()->getUnitOfWork()->recomputeSingleEntityChangeSet(
            $this->em->getClassMetadata(get_class($bar)),
            $bar
        );

    }
}