Revisiting saveAll() and HABTM

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('')));

    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('')));

    echo $form->end('Add Aricle with Tags and Comment');


Pretty simple form. I am reading 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:

function add() {
    if(!empty($this->data)) {

Just for fun here’s the resulting SQL:

[sourcecode language=”sql”]
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 `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)

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.

Related Posts