jump to navigation

Complex Validation with classes or callback methods February 11, 2006

Posted by rossoft in CakePHP.
trackback

Complex Validation
——————–

There are several implementations of custom validation made by CakePHP users. I just show you another one. Some of the stuff is from CakeBaker and other cakers solution

My solution has these features:
* Each field can be validated for more than one validator. You can show a different message for know what validator has failed.
* A validator can be: a regular expression, a callback method of your model or a validator subclass. With validator subclasses you can share a custom validator between apps easily (simply put a file in the validators folder)

1. Edit the /app/app_model.php (if not exists, copy from /cake/app_model.php)
Edit and merge this with your file:

vendor('validator'. DS. 'validator');

class AppModel extends FixModel 

{
   	function invalidFields($data)

   	{

   		return validator_invalidFields($this,$data);	

   	}
}

2. Download this and uncompress into your /vendors folder. You will get a validator folder.

3. Copy to the file /app/helpers/error.php

<?php
class ErrorHelper extends Helper
{
    function showMessage($target)
    {
        list($model, $field) = explode('/', $target);

        if (isset($this->validationErrors[$model][$field]))
        {
            return sprintf('<div class="error_message">%s</div>',
                              $this->validationErrors[$model][$field]);
        }
        else
        {
            return null;
        }
    }
}
?>

4. Ready to go!! Example of usage:

var $validate=
  	array(
'empresa'=>array(array(VALID_NOT_EMPTY,'This is not optional'), array(VALID_UNIQUE,'This value is repeated')),
	 'responsable'=>array(array(VALID_NOT_EMPTY, 'This is not optional')),

     'other'=>array(VALID_UNIQUE,'Error in this field',array(12,42))

);		

In the example, the code field, needs to be a unique field not empty.
VALID_NOT_EMPTY is a CakePHP generic regexp. VALID_UNIQUE is a custom class validator (is the file /vendors/validator/validators/unique.php). Have a look at it for the syntax of custom classes. If you create the class MyownValidator, simply put the file myown.php in this folder, and the constant VALID_MYOWN will be automatically populated in all models for it’s use.

In the example, the other field, is validated with the validator VALID_BETWEEN. This class validator not exists (the file /vendors/validator/validators/between.php doesn’t exists). Then, you will get a notice because the constant VALID_BETWEEN is not defined. This is a custom callback function. In your model or app_model, define the constant like this:
define(‘VALID_BETWEEN’,’VALID_BETWEEN’);
Then, in your model, create this function (is equivalent of a BetweenValidator class, the method has precedence)

function BetweenValidator($data,$field_name, $validator_params)
{
	if (..) return true;
    else return false;
}

Then in the example, this function will be called with the $data array, $field_name=’other’ and $validator_params=array(12,42).

(If you don’t want to define the VALID_BETWEEN constant, simply put the value ‘VALID_BETWEEN’ in the $validate array )

5. Show the error messages in the view
a) Include the error helper in your controller (var $helpers=array(‘xxx’,’yyy’,’Error’)

b) Use this in your view:

<?=$error->showMessage($elementName)?>

$elementName is in the form Model/field

6. Test it !

Advertisements

Comments»

1. rossoft - April 22, 2006

I’ve extended FixModel class at app_model.php, if you don’t use flexifix, then change app_model to

vendor(‘validator’. DS. ‘validator’);
class AppModel extends Model

{
function invalidFields($data)

{

return validator_invalidFields($this,$data);

}
}

2. rossoft - April 22, 2006

Complete model example

array(
array(VALID_NOT_EMPTY,’Please enter your username.’),
array(VALID_ALPHANUMERIC,’Invalid username. (no special characters – !*^%>+ etc)’),
array(VALID_LENGTH,’Invalid username. Must be between 4 and 16 characters.’,array(4,16))
),
‘password’=>array(
array(VALID_NOT_EMPTY, ‘Please enter your password’),
array(VALID_LENGTH,’Invalid password. Must be between 4 and 16 characters.’,array(4,16))
)
);

function LengthValidator($data,$field_name, $validator_params){
$field_data=$data[$this->name][$field_name];
return (strlen($field_data)>=$validator_params[0] &&strlen($field_data)

3. Naonak - May 6, 2006

To validate field only if it required :

class AppModel extends Model

{
function invalidFields($data)
{
if( isset($data[$this->name]) ){
foreach ($this->validate as $field=>$valid) {
$can_be_empty = true;

foreach ($valid as $v) {
if($v[0] == VALID_NOT_EMPTY){
$can_be_empty = false;
break;
}
}

if($can_be_empty && empty($data[$this->name][$field])
&& (string)$data[$this->name][$field] != ‘0’){
unset($this->validate[$field]);
}
}
}
return validator_invalidFields($this, $data);
}
}

Bug fix for cake 1.0 on model_extension.php :

function validator_invalidFields(&$model,$data=array())
{
$errors=array();
if (!empty($model->validationErrors))
{
return $model->validationErrors;
}

Other bug not solved :

Method “saveField” with validation don’t work correctly. It valide all fields.

$this->ModelA->saveField(‘fieldA’,’value’,true)

4. Naonak - May 6, 2006

Fix the second bug on model_extension.php on line 124:
if (isset($data[$model->name][$field_name]))
{
$value=$data[$model->name][$field_name];
}
else {
return true;// instead of $value=”;
}

5. Naonak - May 6, 2006

My solution to validate field only if it required is not very smart.

Better idea Rossoft ?

6. Mark Quinn - August 1, 2006

the loadValidators function in vendors/validator/validator.php has a slight error, in that it will try and include every file in the validators subdirectory, regardless of file types.

As many editors save backup files, this can be a problem.

Change the function to read:

function loadValidators() {

// Cargar las clases restantes
$validator_dh = opendir( VALIDATORS_DIR );
while (false !== ($validator_filename = readdir($validator_dh))) {

if (! is_dir($validator_filename)
&& (preg_match(‘/(.+)\\.php$/’, $validator_filename ))) {

loadValidator( $validator_filename );
}
}

}


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: