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

<?php
    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:

function add() {
    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.

%d bloggers like this: