Quick fix for HABTM Validation

This article is also available in the following languages:
By kogalex
I was looking for a simple solution for HABTM validation, and struggled to find one that didn't required me to write a lot of code.
i came up with this, hopefully it will help someone.
This is my first post here, so i guess someone will rewrite my code to be much better.
basically we want to add to the app_model.php the next code

Model Class:

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


and then just add a simple "multiple" validation rule with the name of the HABTM connection

let's say we have a baked code that looks like this

Model Class:

<?php 
var $hasAndBelongsToMany = array(
        
'Project' => array(
            
'className' => 'Project',
            
'joinTable' => 'projects_users',
            
'foreignKey' => 'user_id',
            
'associationForeignKey' => 'project_id',
            
'unique' => true,
            
'conditions' => '',
            
'fields' => '',
            
'order' => '',
            
'limit' => '',
            
'offset' => '',
            
'finderQuery' => '',
            
'deleteQuery' => '',
            
'insertQuery' => ''
        
)
);
?>

all we do is add

Model Class:

<?php 
var $validate = array(
        
'Project' => array(
            
'multiple' => array(
                
'rule' => array('multiple',array('min' => 2)),
                
'message' => 'Please select at least 2 projects you attend'),
        ),
    );
?>

more info about the multiple validation rule here http://book.cakephp.org/view/786/multiple

Comments

  • Posted 03/08/11 03:09:48 PM
    This solution don't work for me
    My Opportunity Model

    var $hasAndBelongsToMany = array(
    'Mood' => array(
    'className' => 'Mood',
    'joinTable' => 'opportunities_moods',
    'foreignKey' => 'opportunity_id',
    'associationForeignKey' => 'mood_id',
    'unique' => true,
    'conditions' => '',
    'fields' => '',
    'order' => '',
    'limit' => '',
    'offset' => '',
    'finderQuery' => '',
    'deleteQuery' => '',
    'insertQuery' => ''
    )
    );

    var $validate = array(
    'name' => array(
    'notempty' => array(
    'rule' => array('notempty'),
    'message' => 'Required field',
    ),
    'Mood' => array(
    'multiple' => array(
    'rule' => array('multiple',array('min' => 2)),
    'message' => 'Please select at least 2 mood you attend'),
    ),
    ));

    function beforeValidate() {

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


    }

    }

    My View


    New Opportunity
    Form->create('Opportunity');?> Form->input("id"); ?> Form->input("name"); ?> Form->input("code"); ?> Form->input('Mood',array('type' => 'select', 'multiple' => 'checkbox')); ?> Form->end('Save'); ?>


    Any Ideas??
  • Posted 11/18/10 01:06:24 PM
    hello I use the example that you post but I can display the error message of that validation, I need help
  • Posted 11/04/10 06:50:49 AM
    @positan thanks for the fix. but since i put it in beforeRender of the App Controller. its running when ever i run any page. how to limit it to few pages or when Habtm is there in the form submission ?
  • Posted 09/27/10 04:50:30 AM
    Great work Alex, just what I was searching for.
    Needed to implement Brandon's fix too.
    Clean and versatile code from both of you.
    Many thanks!
  • Posted 06/22/10 03:51:09 PM
    I also had the problem where the error message was not printing. I determined that this was because the error message was showing up in the main model's validationErrors instead of the HABTM model's. I wrote a beforeRender function for my AppController to check for the errors and copy them back the the right place. See below:

    Controller Class:

    <?php 
    class AppController 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];
                }
            }
            
        }
    }
    ?>

    Now my error message shows up as I expect it to.
  • Posted 04/02/10 04:04:17 PM
    @Harsha basically the code at beforeValidate adds the info of the HABTM information(the id's passed at the html form post) to the current model's data.
    this way we can check it in the current model.

    @Daniel Hollands I couldn't find the problem, as for me it shows errors.
    I'm using cakephp 1.3 and use something like that in the view

    echo $form->input('School', array('title' => __('Select Schools',true),'label' => __('School',true)));

    Another thing i would suggest is using some sort of JS validaton, that auto generates from the validation rules.
    both jquery and prototype have very good plugins for that.
  • Posted 03/29/10 04:24:45 AM
    can some one explain how does the code in beforeFilter help to make this work. just curious.

    the normal rule for multiple is

    Model Class:

    <?php 

    var $validate = array(
        
    'multiple' => array(
            
    'rule' => array('multiple', array('in' => array('do''ray''me''fa''so''la''ti'), 'min' => 1'max' => 3)),
            
    'message' => 'Please select one, two or three options'
        
    )
    );

    ?>
  • Posted 03/16/10 10:32:27 AM
    I've tried to use this, and so far as I can tell, it's doing what it's meant to do by preventing less than 2 from being selected - only there are no error messages returned to confirm this.
    • Posted 06/10/10 11:14:18 AM
      I've tried to use this, and so far as I can tell, it's doing what it's meant to do by preventing less than 2 from being selected - only there are no error messages returned to confirm this.
      I have the same problem i'm using cakephp 1.3.1

      in my view

      Form->input('Agency',array('label'=>__('Agencias',true))); ?>
  • Posted 03/10/10 02:52:56 PM
    Thanks!

Comments are closed for articles over a year old