petekaner
petekaner

Reputation: 8921

How to change related entities using event listeners with doctrine

Using Symfony and Doctrine, I have a User entity and a Address entity. Every user can have 0 or more addresses and one of them is his default address.

So when I change the default address from one to another I should set that one to default and the others to not default (a boolean field).

I tried to do so with event listeners so when the Address entity is updated I launched the post updated event setting all the other addresses to non default, something like this:

class AddresssListener
{
    public function postUpdate(LifecycleEventArgs $event)
    {
        $entity = $event->getEntity();
        if ($entity instanceof Address) {
            $this->changeDefaultAddress($entity, $event);
        }
    }

    private function changeDefaultAddress($address, $event)
    {
        if ($address->getIsDefault() == true) {
            foreach ($address->getUser()->getBillingDatas() as $another_address) {
                if ($address != $another_address) {
                    $another_address->setIsDefault(false);
                    $em = $event->getEntityManager();
                    $em->persist($another_address);
                }
            }
        }
    }
}

The code is executed correctly and no error is displayed, but the changes on the non default addresses are not saved.

Upvotes: 4

Views: 1840

Answers (1)

Wilt
Wilt

Reputation: 44422

If a User can only have one default Address you should also somehow make sure your database model only supports one address to be the default one.

I would suggest to make the Address which is the current default address to a relation of User (an additional One-To-One association between Address ($defaultAddress) and User next to your One-To-Many relation with addresses). Then you can simply do like this:

$user->setDefaultAddress($address);
$em->persist($user);
$em->flush();

This can be done with one database operation vs two in your example (PostPersist is called after the flush of the first operation)

And now it is easy to get the current default address:

$address = $user->getDefaultAddress();

Upvotes: 1

Related Questions