Saving HABTM with cake

Jul 27, 2006
cakePHP's model associations really help save time, but one part of the association interface could use some polishing. When dealing with Has And Belongs To Many (HABTM) associations, cakePHP can do some "funny" things. But thanks to a topic in cakePHP's google group, I was able to get my HABTM schema situated. However, the solution isn't obvious so I felt others could benefit from a nudge in the right direction. Here's what I did:

To stay DRY, all of the code will go in the AppModel. Open up app/app_model.php and create the following method: function correctHABTMdata($return = false) {
    $data = array();

    $data[$this->name] = $this->data[$this->name];

    foreach($this->data as $key => $value) {
        if($key != $this->name) {
            if($key == key($value) && is_array($value)) {
                if(!is_array($this->data[$key][$key])) {
                    $data[$key][$key][0] = $this->data[$key][$key];
                }

                if(count($data[$key][$key]) == 1 && trim($data[$key][$key][0]) == "") {
                    if(count($data[$key]) == 1) {
                        unset($data[$key]);
                    } else {
                        unset($data[$key][$key]);
                    }
                }
            } else {
                $data[$key] = $value;
            }
        }
    }

    if($return) {
        return $data;
    } else {
        $this->data = $data;
        return true;
    }
}
This will solve all "3 secrets of HABTM associations". Now we just need to make this method as easy as possible to use, so we'll call it in our AppModel's beforeSave() callback: function beforeSave() {
    if($this->hasAndBelongsToMany != array()) {
        $this->correctHABTMdata();
    }
        
    return true;
}
This will automatically call the correctHABTMdata() method if a HABTM association is defined in your model. Now when you call $this->Model->save(); in your controllers you don't need to worry if the array is correctly formatted. And don't forget, if you override AppModel's beforeSave() callback in your models then be sure to call the parent beforeSave().

I haven't thoroughly tested this approach, but it has worked pretty well for me. I have some test data that shows each "secret" is correctly addressed.

Happy HABTMing
0 comments

More Posts

Other Places

Recent Photos

image image image image image image