Practical use of saveAll() (part 2, notes and tips)

In part 1, I explained how to use saveAll() in order to save multiple models at the same time, if you haven’t had a chance to read that post please do so before starting on this one.

1. Saving multiple records for the same model.

Using our models from the previous example, we can build a form to save multiple Accounts at the same time (accounts/add.ctp):

echo $form->create();

echo $form->input('Account.0.name');
echo $form->input('Account.0.username');
echo $form->input('Account.0.email');
echo $form->input('Account.0.company_id', array('type'=>'hidden', 'value'=>1));

echo $form->input('Account.1.name');
echo $form->input('Account.1.username');
echo $form->input('Account.1.email');
echo $form->input('Account.1.company_id', array('type'=>'hidden', 'value'=>1));

echo $form->end('Add');

Now, in your Accounts controller’s add() action you would do something like this:

function add() {
   if(!empty($this->data)) {
        $this->Account->saveAll($this->data['Account'], array('validate'=>'first'));
   }
}

Notice, that I am passing $this->data[‘Account’] to saveAll(), rather than just $this->data. This is necessary for saveAll() to work properly when saving multiple records for a single model.

2. Any chance to save deep bindings?

No, at least currently, if you have Company->Account->Profile, you cannot save all three models in one go.

3. What if Company hasMany Account and Company hasMany Profile?

This is possible, you can save all three models at the same time. It is very similar to the way we’ve saved Company and Account models before. Just add Profile model’s fields to the form, named as Profile.0.name (for example).

4. Make sure your DB supports transactions

You’ve probably noticed that saveAll() uses transactions to ensure data integrity. I, however, made a little mistake (https://trac.cakephp.org/ticket/5178) and forgot that MySQL’s default MyISAM storage engine does not support transactions. So, make sure that you use InnoDB in MySQL to enable transaction support (if you use another DB, double check that transactions are supported).

5. Is it possible to save HABTM models with saveAll()?
Update (3/30/2009): It is now working just fine, please see this post for more details.

I have not found a way (or a supporting test case) to save multiple HABTM models at once, for example, if you wanted to create a new Post and some new Tags and save all that goodness in one shot.
It is possible with save() to create a new post and assign some Tags to it, but you need to know the ids of the Tags before the save(). (See this post on saving HABTM data for more details).

6. What if Company hasOne Account?

This is still possible, but since you can only have one Account per Company, you should name your Account model fields as usual, i.e. Account.name (no need for Account.0.name, since only one Account is allowed by the relationship).

Well, that pretty much concludes the majority of things you should know about saveAll(), hopefully now, you should be able to handle and troubleshoot a variety of cases where saving of multiple models or records is needed.

%d bloggers like this: