Dec102006

Something to consider when saving HABTM records in CakePHP

Just the other day I was in the process of saving an HABTM (Have And Belongs To Many) field with CakePHP, specifically for saving the relations between a model Project and another model Category. I first had to do a small extension to the helper since Category was also a n-depth level tree, so I’ve used findAllThreaded on the Category model to get the tree and build a nice tree of checkboxes. All good there.

I was then building the screen that would let the user check these checkboxes and save the relations. Now, since the project was already saved and all I had to do in that screen was present the user with the checkboxes, I figured I didn’t need to set any project details when saving, other than the ID of the project that I was relating to. Big mistake.

So in my edit categories screen (as documented on several CakePHP pages) I had to build the checkboxes with their name in the form of data[Category][Category][]. This is to allow CakePHP to take care of generating the SQL statements when inserting multiple HABTM records. So I tried doing this:

$this->Project->id = 4;
$this->Project->save($this->data);

Where data was just something like:

Array (
	'Category' => array (
		'Category' => array (
			4,
			10,
			12
		)
	)
)

So an array of Category IDs. To my surprise while debugging the issued SQL commands I discovered that nothing was being saved. So I did what any smart coder would do ;) and I went to the code inside CakePHP’s source code that take cares of the saving. The following lines drove my attention inside function save():

if (isset($weHaveMulti) && isset($v[$n]) && $count > 0 && count($this->hasAndBelongsToMany) > 0) {
	$joined[] = $v;
}

If you do a little debugging you’ll see that CakePHP is expecting to have some data to save for model Project before saving the HABTM relation. Why? Take a look at this part of the expression:

$count > 0

This is a variable that gets initialized to 0. If you go below you’ll see that the foreach that processes each data element increments this variable by the end. So It expects to find something relating to the model we’re saving on the data array BEFORE the array of IDs. In other words, the data array should look more like:

Array (
	'Project' => array (
		'id' => 4
	),
	'Category' => array (
		'Category' => array (
			4,
			10,
			12
		)
	)
)

Something that let’s Project come before Category. So I did exactly that: in the form that builds the array of checkboxes I’ve included a hidden form element that sets the project name. And voila, HABTM records started appearing.

It may save you hours of debugging :)

BAKE ON!

Related posts:

  1. Modelizing HABTM join tables in CakePHP 1.2: with and auto-with models
  2. CakePHP tip of the day: pay attention to conventions
  3. CakePHP 1.2 tip of the day: be mindful of Model::set


Leave a Comment

2 Comments to "Something to consider when saving HABTM records in CakePHP"

  1. Dec282006 at 1:30 pm

    scoby [Visitor] wrote:

    thanks for going through that step by step. I was having a few difficulties with HABTM And that avoided another ‘gotcha’ that would have wasted more of my time.

    thanks Mariano :)

  2. May312011 at 11:55 am

    Rui wrote:

    You saved my life! thank you!

 
Powered by Wordpress and MySQL. Clauz's design for by Cricava