How to validate HABTM data…

Update: Since writing of this article the ‘rule’ => ‘multiple’ has been implemented in cake core.
It is much more convenient to use for HABTM validation.
You may consider this post deprecated and only to be used for historical purposes or if you are working with an older code-base.

So we’ve got our Post and Tag models (Post hasAndBelongsToMany Tag).

We are about to save a new Post, but there is a need to ensure that a user selects at least one Tag…

Let’s see how we can accomplish such validation…

First, let’s build the form for saving our Post and some Tags.

echo $form->create('Post', array('action'=>'add'));
echo $form->input('title');
echo $form->input('post');
echo $form->input('Tag', array('multiple'=>'checkbox'));
echo $form->end('Add post');

Pretty generic stuff… In our controller we’ll get a list of tags and it will be automagically assigned to our ‘Tag’ input and turned into a bunch of checkboxes representing each Tag.
After submitting the form the Tag data will be sent back as an array of id’s.

Now, let’s add a validation rule to our Tag model:

class Tag extends AppModel {

  var $name = 'Tag';

  var $hasAndBelongsToMany = 'Post';

        var $validate = array('Tag'=>array('rule'=>'checkTags'));

  function checkTags() {
     if(!empty($this->data['Tag']['Tag'])) {
         return true;
     }

     return false;
  }
}

As you see, we are using a custom method checkTags() to ensure that at least one Tag has been selected. It might appear that we could use ‘notEmpty’ rule, but unfotunatelly it doesn’t work with arrays of data so we have to use our own validation method.

Last, but not least, we create an add() action in our Posts Controller:

function add() {

      if(!empty($this->data)) {
          $this->Post->Tag->set($this->data);
          if($this->Post->Tag->validates()) {
              $this->Post->save($this->data);
          }
      }

      $this->set('tags', $this->Post->Tag->find('list', array('fields'=>array('id', 'tag'))));
  }

Just to clarify…
First, we validate the Tag model, by using the data from the form to ensure that at least one Tag was selected. If so, we save the Post and the relevant Tags.
Also, as you see, we use find(‘list’) to build our list of Tags for the view by relying on some good CakePHP magic.

%d bloggers like this: