Czechnology
Czechnology

Reputation: 14992

Doctrine2's preUpdate missing PreUpdateEventArgs argument in Symfony2

Doctrine2 documentation on preUpdate event says

This event has a powerful feature however, it is executed with a PreUpdateEventArgs instance, which contains a reference to the computed change-set of this entity. This means you have access to all the fields that have changed for this entity with their old and new value.

Sounds useful! So what I do:

/**
 * Acme\TestBundle\Entity\Article
 *
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class Article
{
    // ...

    /**
     * @ORM\PreUpdate
     */
    public function preUpdate(\Doctrine\ORM\Event\PreUpdateEventArgs $eventArgs)
    {
        if ( /* use $eventArgs here */ )

            $this->updatedAt = new \DateTime();
    }

    // ...
}

But no luck - no arguments are passed:

Catchable Fatal Error: Argument 1 passed to
Acme\TestBundle\Entity\Article::preUpdate() must be an instance of
Doctrine\ORM\Event\PreUpdateEventArgs, none given, called in
...\vendor\doctrine\lib\Doctrine\ORM\Mapping\ClassMetadataInfo.php on line 1540 and defined in ...\src\Acme\TestBundle\Entity\Article.php line 163

I guess this must work some other way in Symfony2. How do I do it?

Upvotes: 4

Views: 9494

Answers (2)

ruslanix.com
ruslanix.com

Reputation: 349

You should remember what with PreUpdateEventArgs instance you have access to all the fields that have CHANGED for this entity with their old and new value. But in you example updatedAt will not be at that changeset. If you try to set updatedAt value, you should get error: "Field 'updatedAt' is not a valid field of the entity". So, you can change updateAt field and then use UnitOfWork:recomputeSingleEntityChangeSet. Example:

public function preUpdate(PreUpdateEventArgs $args)
{
    $entity = $args->getEntity();
    $em = $args->getEntityManager();
    $uow = $em->getUnitOfWork();

    if ($entity instanceof Product)
    {
        $entity->setDiscount(123);

        $uow->recomputeSingleEntityChangeSet(
            $em->getClassMetadata("XXXBundle:Product"),
            $entity
         );
    }
}

More code examples in my blog post (on russain:)): Update doctine entity in preUpdate event

Upvotes: 17

meze
meze

Reputation: 15087

There are two ways of handling lifecycle events.

First is simply annotate a method of your doctrine entity as @ORM\PreUpdate. This method will be called before update. The second is more complicated. It involves listener preUpdate. It's a separate class that you subscribe to listen to particular events.

Read carefully from here again and the symfony cookbook.

Upvotes: 4

Related Questions