2
votes

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?

2
Did you have @ORM\HasLifecycleCallbacks() on both entities? - Łukasz D. Tulikowski
@ŁukaszD.Tulikowski actually I have that on neither one of the entities. I was under the impression that using event listeners would make this line unnecessary. - Micha

2 Answers

2
votes

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.

0
votes

You are using doctrine Lifecycle Events you should add

/** @Entity @HasLifecycleCallbacks */

to your Meaning and Tag entities.

Refer: Doctrine Lifecycle Callbacks