I'm a programmer specialising in performant and scalable systems using PHP and Ruby and cooking


Published:
On Doctrine | PHP

Symfony 1.2, Doctrine 1.1 and saving relationships

When creating a form in Symfony 1.2 sometimes you may want to use Doctrine to automatically save your related data. Since the update to 1.1 there is a small problem in that this doesn't work.

For example let's take the Faqs section. Each FAQ can have MANY FAQ groups and each group can have MANY FAQs. So when we edit an FAQ we have the option (checkboxes) to choose which groups to assign the current FAQ to.

Ordinarily Doctrine would handle saving these relationships but unfortunately we have to take care of letting the model know what it needs to save ourselves. We do this by overloading the doSave method of a form in order for us to set the linkage and tell the model that the relations should be set as modified and therefore saved. Fortunately since Doctrine would normally be expected to handle this behaviour there are methods that make this easy for us.

First we need to overload the doSave method and this must match the interface in the form class, in this case PluginFaqForm.class.php:

public function doSave($con = null)  
{
}

Then we need to unlink all relations for our groups:

$this->getObject()->unlink('FaqGroups');

"FaqGroups" would of course be replaced with the name of you alias.

Why unlink? well this tells doctrine to remove all references to other records with that alias. This is so that we can correctly blanket remove the relations in case we uncheck any in the form. Because we haven't passed any other options to this method, it will assume we want to unlink all records and also that it will store these changes for future modifications before committing to the database.

So now we need to atually link our selected groups:

$this->getObject()->link('FaqGroups', $this->getValue('faq_gropus_list'));

We have added the the aias as the first parameter so that doctrine knows which relationships to setup. The second parameter is and array of ids to setup the relationships with, in this case an array of checkbox values taken directly from our form.

Now we need to actually save the changes so lets tell Doctrine to carry on with it's normal process:

parent::doSave($con);  

So this in total looks like:

public function doSave($con = null)  
{
  $this->getObject()->unlink('FaqGroups');
  $this->getObject()->link('FaqGroups', $this->getValue('faq_groups_list'));
  parent::doSave($con);
}

All you need to do is drop this into your form to overload the parent methods, then change the alias and away you go. This can be used as many times as you wish just by copying the unlink and link command lines.