Search code examples
doctrine-ormpersist

Doctrine2, update some datas before persist


I'm developing my php software using Doctrine2. It is quite simple to use it but I have a little problem and I would know what is the best practice in that situation. Maybe you could help me ! You'll have all my gratitude :-D

Situation :

I have 2 entities (User and Contacts)

  • A User can contain some Contacts
  • The entity (table) Contacts have a field labelled mainContact which define if it is the main contact of the user or not.
  • Ony one contact could be the main contact (mainContact=1)

Problematic :

I woud like that when I persist a contact :

  • If this contact has mainContact=1, all other contacts associated to the user sould be updated to mainContact=0
  • If this contact has mainContact=0, I need to check all other contacts. If I don't find any other contact with mainContact=1 for this user, I automaticly update the current contact with setMainContact(true).

Possible solutions :

I have some idea how to process this logic but I would like to know the best practice in order to do a good code because this application will be an open source application.

Not clean ideas :

  • Create a method in the Contact Repository that will update all the others contacts assigned to the user and return the value to attribute to the current contact.

With this solution, I must launch the repository method always before to persist a contact all around the application. If I forgot to launch it, the database integrity should be compromised.

  • Use the Prepersist mecanism from the entity to get the entitymanager and update all others user's contacts.

This method is not recommanded, the entity should never access directly the entity manager.

Can anyone tell me what is the best practice to do so ? Thank you very much !

PS : Sorry for my poor english !


Solution

  • The best thing you can do here (from a pure OOP perspective, without even the persistence logic) is to implement this logic in your entity's setters. After all, the logic isn't heavy considered that a User won't have many contacts, nor the operation will happen very often.

    <?php
    
    class User
    {
        protected $contacts;
    
        // constructor, other fields, other methods
    
        public function addContact(Contact $contact)
        {
            if ($this->contacts->contains($contact)) {
                return;
            }
    
            if ($contact->isMainContact()) {
                foreach ($this->contacts as $existingContact) {
                    $existingContact->setMainContact(false);
                }
    
                $this->contacts->add($contact);
                $contact->setUser($this); // set the owning side of the relation too!
                return;
            }
    
            $mainContact = true;
    
            foreach ($this->contacts as $existingContact) {
                if ($existingContact->isMainContact()) {
                    $mainContact = false;
                    break; // no need for further checks
                }
            }
    
            $contact->setMainContact($mainContact);
            $this->contacts->add($contact);
            $contact->setUser($this); // set the owning side of the relation too!
        }
    }
    

    On the other side, think about adding a field to your user instead:

    <?php
    
    class User
    {
        // keep reference here instead of the contact (cleaner)
        protected $mainContact;
    }