Micha
Micha

Reputation: 563

symfony event listener preUpdate does get called if one-to-many association changes

I have an entity that has a OneToMany relationship with another entity.

Meaning entity

/**
 * One Meaning has Many Tags.
 *
 * @ORM\OneToMany(targetEntity="Tag", mappedBy="meaning")
 */
private $tags;

Tag entity

/**
 * Many Tags have One Meaning.
 *
 * @ORM\ManyToOne(targetEntity="Meaning", inversedBy="tags")
 * @ORM\JoinColumn(name="meaning_id", referencedColumnName="id")
 */
private $meaning;

I registered an event listener to the preUpdate and prePersist doctrine events.

services.yml

tag.event_listener.meaning_tag_persister:
    class: TagBundle\EventListener\MeaningTagsPersister
    tags:
        - { name: doctrine.event_listener, event: preUpdate, method: preUpdate }
        - { name: doctrine.event_listener, event: prePersist, method: prePersist }

Within this Event Listener all I do is set the meaning in the tag entity.

MeaningTagsPersister.php

/**
 * Call before an entity gets updated
 *
 * @param PreUpdateEventArgs $args
 */
public function preUpdate(PreUpdateEventArgs $args)
{
    /** @var Entry $object */
    $object = $args->getObject();

    if (!$object instanceof Meaning) {
        return;
    }

    /** @var Tag $tag */
    foreach($object->getTags() as $tag) {
        $tag->setMeaning($object);
    }
}

The prePersist method looks exactly the same. Whenever I create a new Meaning entity, the event listener gets called with the appropriate method. When I update the Meaning entity the event listener works as well, but only if I update one of its "normal" properties like name. If I change any of the tags it is not recognized by doctrine as a changed entity (which is correct as the Meaning entity itself hasn't changed).

Yet, I still have to update the meaning within each Tag when the Meaning entity gets updated. I also have to remove the meaning from any Tag that is no longer associated with that Meaning.

Is an event listener the right way to accomplish this? If yes, how do I get the Meaning entity to trigger the preUpdate event if only the tags have changed? If not, what would be the appropriate way to update all associated Tag entities through the Meaning entity?

Upvotes: 2

Views: 3374

Answers (2)

mastacash
mastacash

Reputation: 46

The problem here is that PreUpdate does not handle changes on Associations as stated in the documentation:

...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.

Doctrine#PreUpdate

To verify, execute the same code in your Controller and it will persist the changes.

Upvotes: 3

Łukasz D. Tulikowski
Łukasz D. Tulikowski

Reputation: 1495

You are using doctrine Lifecycle Events you should add

/** @Entity @HasLifecycleCallbacks */

to your Meaning and Tag entities.

Refer: Doctrine Lifecycle Callbacks

Upvotes: 0

Related Questions