Green Acorn
Green Acorn

Reputation: 912

Best way to update entity one to many relationship in Symfony 2 / Doctrine 2

What is the best way to update an entities one to many relationship in doctine? For example: I have an entity called booking with a mapped one to many Guest entities.

When a booking is edited, the number of guests can change by either adding or removing guests. At the moment, I count the number of guests submitted, and if they are different to the current number of guests, i delete the booking guests and re add the new ones!

To me this doesn't seem right and would like to know how other people approach this.

Code example:

    if (count($collection)) {
        $numberGuests = count($this->getEntity()->getGuests());
        foreach ($collection as $guest) {
            if ($numberGuests != count($guests)) {
                // delete guest if the number has changed
                $this->getGuestManager()->delete($guest);
            } else {
                // update entity
                $guest->setArrayData(Tools::getData($i, $guests));
            }
        }
    }

Upvotes: 1

Views: 9975

Answers (1)

Cesc
Cesc

Reputation: 688

I don't think there is a best way, but the way you have now is not correct. Why if the user modifies the guests but the number is still the same (he deletes one guest from the list but adds a new one)?

Anyway, I don't think it's a bad approach to "Reset" the relationship everytime somebody edits (maybe not the most efficient though) you will just need to set, from the owning side (guest), the booking. (In a many to one relationship, the "many" side has to be the owning side)

I would do that in controler:

    if ($editForm->isValid()) {

        //find all guests entities that has this booking related
        $oldguests=$em->getRepository('YourBundle:Guest')->findby(array("booking"=>$entity));
        //well you will need to custom a little bit better this "findby"

        foreach($oldguest as $guest){
             //remove the booking for that guest. So that guest won't have any booking linked  
             $guest->removeBooking();
             $em->persist($guest);  
        }
        //now we make the link with guest and booking 
        //$form->submit($request) should have set the current entity with the current guests the user selected
        foreach($entity->getGuests() as $currentguest){
             $currentguest->setBooking($entity);
             $em->persist($guest);
        }

        $em->persist($entity);
        $em->flush();

    }

And in the Guests entity I would add the function removeUser

 //guest.php
 public function removeBooking(){
       $this->booking=NULL;
 } 

Maybe is more elegant if you create a function in the GuestRepository.php that does what the controller is doing, and in the controller you just call that function.

You really need to take care of the owning side of the relationship. If you allow the edition through the owning side, that is, updating guests with the booking, the default code app/console gives you wouldn't need any kind of customization at all: both entities would be properly updated.

To keep it simple we can say that: let the user update the owning side of the relationship => everything is automatic. Let the user update the inverse side of the relationship => manual customization required. (this is the same for many to many relationships).

Hope this helps.

Upvotes: 1

Related Questions