During my months of winter hibernation, or maybe due to some oversight in prior review of the test cases… I’ve missed a very important and a great feature, which is that saveAll() can also work with HABTM data.
Let’s see a quick example based on the provided test cases.
We have the following models:
Tag HABTM Article
Article HABTM Tag
Article hasMany Comment
… and both Article and Comment belongsTo User
First, we’ll build a form (view add.ctp), so we can store an Article with some Tags as well as relevant Comment, all belonging to some User. All in one go with the lovely saveAll()
echo $form->create();
echo $form->input('Article.title');
echo $form->input('Article.body');
echo $form->hidden('Article.user_id', array('value' => $session->read('User.id')));
echo $form->input('Tag', array('options'=>array(15,20,30), 'multiple'=>'checkbox'));
echo $form->input('Comment.comment');
echo $form->hidden('Comment.user_id', array('value' => $session->read('User.id')));
echo $form->end('Add Aricle with Tags and Comment');
?>
Pretty simple form. I am reading User.id from some variable that was previously stored in the session (you could actually modify the data array in the controller before saving, rather than passing it as a hidden field). Also, I just created a “fake” array of Tag id’s, in ‘options’=>array(15,20,30)… in real life the values would likely come from $this->Article->Tag->find(‘list’);
Once the form is done, the controller action to save all of this data in one shot, couldn’t be simpler:
if(!empty($this->data)) {
$this->Article->saveAll($this->data);
}
}
Just for fun here’s the resulting SQL:
[sourcecode language=”sql”]
START TRANSACTION
INSERT INTO `articles` (`body`, `user_id`, `updated`, `created`) VALUES (‘This is a great article with tags and comments’, 5, ‘2009-03-30 11:54:54’, ‘2009-03-30 11:54:54′)
SELECT LAST_INSERT_ID() AS insertID
SELECT `ArticlesTag`.`tag_id` FROM `articles_tags` AS `ArticlesTag` WHERE `ArticlesTag`.`article_id` = 6
INSERT INTO `articles_tags` (`article_id`,`tag_id`) VALUES (6,’0′), (6,’1′), (6,’2’)
INSERT INTO `comments` (`comment`, `user_id`) VALUES (‘NO comment’, 6)
SELECT LAST_INSERT_ID() AS insertID
COMMIT
[/cc]
Pretty powerful stuff, with just a couple of lines of code.
P.S. My previous post, which mentioned the problems with saveAll() and HABTM had been corrected.