Painless HABTM Validation in CakePHP

Recently I was faced with the task of validating a model with a HABTM relationship. I tried looking around for various solutions but all of them seemed quite complicated and time consuming to implement until I came across this nifty solution. Lets say you have two models - posts and tags with a HABTM relationship. You probably already have the relationship defined in your model, if not, it goes something like this:

models/post.php:

var $hasAndBelongsToMany = array(
	'Tag' => array(
		'className' => 'Tag',
		'joinTable' => 'tags_posts',
		'foreignKey' => 'post_id',
		'associationForeignKey' => 'tag_id',
		'with' => 'TagsPost',
		'unique' => true,
		'conditions' => '',
		'fields' => '',
		'order' => '',
		'limit' => '',
		'offset' => '',
		'finderQuery' => '',
		'deleteQuery' => '',
		'insertQuery' => ''
	)
);

Now in addition to that, just go ahead and add multiple validation rule in your post model:

var $validate = array(
        'Tag' => array(
            'multiple' => array(
                'rule' => array('multiple',array('min' => 2)),
                'message' => 'Please select at least 2 tags'),
        ),
    );

And last but not least add a beforeValidate filter …

function beforeValidate() {
	foreach($this->hasAndBelongsToMany as $k=>$v) {
		if(isset($this->data[$k][$k]))
		{
			$this->data[$this->alias][$k] = $this->data[$k][$k];
		}
	}
}

All you have to do now is add the following snippet in your main model’s controller:

controllers/posts_controller.php:

<?php
class PostsController extends Controller {

    function beforeRender()
    {
        $model = Inflector::singularize($this->name);
        foreach($this->{$model}->hasAndBelongsToMany as $k=>$v) {
            if(isset($this->{$model}->validationErrors[$k]))
            {
                $this->{$model}->{$k}->validationErrors[$k] = $this->{$model}->validationErrors[$k];
            }
        }

    }
}
?>

That will check for the errors raised in the main model’s validationErrors and copies them back to the HABTM’s model so that the view can correctly capture and print that validation error.

That’s it!

If you have any questions or comments, please post them below. If you liked this post, you can share it with your followers or follow me on Twitter!