Tags

, , , , ,

The basic idea behind this behavior is that you (well, once in a while) need to save two HABTM models at the same time or search across both models, which are involved in the HABTM relationship.

By default cake does a nice job of saving HABTM models and their relation, but you need to know the ID(s) of at least one of the models that’s involved.
Also, you cannot supply HABTM model conditions, because cake will not build a JOIN to apply the conditions to both models properly.

So, again, this behavior attempts to solve some common issues with HABTM associations.

To give an example we could have a Location Model, which hasAndBelongsToMany Address.
In the Location Model we can have some arbitrary info, such as location name, location value, location capacity, etc., etc.
In the Address Model, of course, we’ll store the relevant address.

The usage is quite simple…

In the Location Model add:

public $hasAndBelongsToMany = array(‘Address’);
public $actsAs = array(‘Habtamable’);

The behavior will do a look-up in the addresses table, to see if a given address already exists.
It will also take care of validating the models.
Once the models are saved (using this behavior or not), you have an established HABTM relationship in the database. Now, using this behavior you can do a search by supplying the conditions of both models. See the updates below for more info…

Silly me, I’ve overlooked an important issue…
As of today’s writing (9/26/2009), the behavior will validate the models one at a time, which obviously looks ugly (and super user-unfriendly) when it comes to UI.
I’m working on fixing this at the moment…
This feature is now working with the latest update (maybe a bit hackish, however).

Grab the behavior here:
http://github.com/teknoid/cakephp-habtamable-behavior

Update (10/8/2009):
You can now pass the following settings:
joinType
fieldsToSkip
habtmModel
See behavior’s README for more details

Update (10/8/2009):
Validates two HABTM models at once, based on their own validation rules.
Will only do the fake re-bind, if the HABTM model is present in the conditions.

Update (10/7/2009):
It also dawned on me that searching across HABTM models, has always been a pain. So the latest revision published on the above date, will take care of that for you.

$this->Location->find('all', array('conditions' => array('Location.is_active' => 1, 'Address.city' => 'Miami')));

The behavior will do a “fake” hasOne bind, as outlined in some other posts here, and build a JOIN to perform the search.
For now I’m only supporting INNER JOIN, but after I get done with validation the behavior will accept a few additional settings to improve the searching and joining.
(And ultimately make it work with pagination).

P.S. Any feedback is greatly appreciated.