Validator is a full-featured class for implementing FORM data validation. Based on PEAR QuickForm functionality and Cake's basic validation features, Validator provides an easy approach to validating FORM submissions. In addition, Validator can be used to filter FORM data (trimming extra spaces, for example).
Validator operates on a single-failure approach, meaning that validation of a field stops when a rule fails to validate. There are two reasons for this:
Another important aspect of Validator to keep in mind is that optional fields which are empty are not validated. Empty fields will only be validated if they have the VALID_NOT_EMPTY rule assigned to them.
Validator provides a rule registry, consisting of registered validation rules. A number of rules are predefined:
| VALID_NOT_EMPTY | Validates presence of a value |
| VALID_COMPARE | Validates whether two fields contain the same value |
| Extra parameter(s): name of field to compare with |
|
| VALID_EMAIL | Validates that the value is a properly formed e-mail address |
| VALID_NUMBER | Checks to see if value is a number |
| VALID_RANGE | Checks to see if value is within a specified range |
| Extra parameter(s): (optional) minimum value for range (optional) maximum value for range |
|
| VALID_RANGE_LENGTH | Checks to see if length of value is within a specified range |
| Extra parameter(s): (optional) minimum value for range (optional) maximum value for range |
|
| VALID_LETTERS_ONLY | Checks to see if value consists only of letters |
| VALID_NO_PUNCTUATION | Checks to see if value does not contain any special punctuation characters |
| VALID_ALPHANUMERIC | Checks to see if value consists only of letters and numbers |
| VALID_NONZERO | Checks to see if value is non-zero |
Validator's primary use is with the Cake MVC framework, though it can also be used as a general purpose validator.
To use Validator with Cake, you will first need to place the validator.php script somewhere that will be easily accessible to your
controllers. The easiest place to put it is in the /libs folder.
To include Validator support in all controllers, simply add the following line to the /app/app_controller.php file:
uses('validator');
Once you have enabled support for Validator, you are ready to add the validation rules.
NOTE: In an effort to make the switch from Cake's validator to the Validator class, the constants have been re-defined in
Validator. As a result, Cake's validators cannot be used. This requires the removal of any references to the validators.php
file. So far, the only location I am aware of is in libs/model.php, in a uses() call.
Validator supports the array-based approach of Cake's validation, with a number of enhancements, as well as a programmatic approach. Both of these will be covered in the sections that follow.
Within the action (function) that will receive FORM data, rules can be assigned using an array:
$this->validate = array(
'username' => VALID_NOT_EMPTY,
'password' => VALID_NOT_EMPTY
);
The validate[] array uses field names for keys, and validation rule constants for values.
In the above example, 'username' is a field name used as a key, and the value is a single validation rule named
VALID_NOT_EMPTY.
The previous example demonstrates that Validator can be used as a drop-in replacement for single validation rulesets previously created for Cake. However, Validator can do much more.
In the previous example, 'username' and 'password' only have a single validation rule assigned to them. However, multiple
rules can easily be assigned by passing an array for the value:
$this->validate = array(
'username' => array(VALID_NOT_EMPTY, VALID_ALPHANUMERIC),
'password' => VALID_NOT_EMPTY
);
Now, 'username' must not only be non-empty, but must also consist only of alphanumeric characters. Note that the array of rules
is essentially unlimited.
In addition to providing support for array-based rulesets, Validator provides a simple way of assigning rules programmatically.
Consider the previous example, created using an array. The same validation rules could be created using the addRule()
function of Validator (assume $v is an instance of class Validator):
$v->addRule('username', VALID_NOT_EMPTY);
$v->addRule('username', VALID_ALPHANUMERIC);
$v->addRule('password', VALID_NOT_EMPTY);
If you want to assign a particular rule to multiple fields, simply pass an array of field names as the first argument:
$v->addRule(array('username', 'password'), VALID_NOT_EMPTY);
$v->addRule('username', VALID_ALPHANUMERIC);
Validator provides default error messages for all pre-defined validation rules. However, it is likely that you'll want to override these
with your own messages. The following examples allow you to do this:
$this->validate = array(
'username' => array(VALID_NOT_EMPTY => 'Username is required'),
'password' => array(VALID_NOT_EMPTY => 'Password is required')
);
$this->validate = array(
'username' => array(VALID_NOT_EMPTY => 'Username is required',
VALID_ALPHANUMERIC => 'Username must contain only letters and/or numbers'),
'password' => array(VALID_NOT_EMPTY => 'Password is required')
);
Notice that now the validation rule names are keys, and the error messages are the values.
Custom error messages can also be provided programmatically:
$v->addRule('username', VALID_NOT_EMPTY, 'Username is required');
$v->addRule('password', VALID_NOT_EMPTY, 'Password is required');
All of the previous examples used simple validation rules such as VALID_NOT_EMPTY which do not require extra parameters. However,
some rules, such as VALID_COMPARE, need extra information in order to operate. These extra parameters are passed similiar to the way
custom error messages are passed. Consider the case of having two fields, 'password' and 'confirm_pass', and you want to validate that the
two contain the same value. This is accomplished using VALID_COMPARE (note: VALID_NOT_EMPTY is omitted in this example for clarity):
$this->validate = array(
'password' => array(VALID_COMPARE =>
array('Passwords do not match', 'confirm_pass')
)
);
Now, the custom error message is replace with an array, whose first value is the error message. All subsequent entries in the array
are extra parameters used by the particular validation rule. VALID_COMPARE, for example, requires one extra parameter, which is the
field name to compare against. In this case, 'confirm_pass' is the name of this second field.
Naturally, we can also do this programmatically:
$v->addRule('password', VALID_COMPARE, 'Passwords do not match', 'confirm_pass');
Tip: If you need to pass extra parameters but don't want to provide a custom error message, simply pass null
where the custom error message is required
Validator provides a function known as registerValidator which allows for
custom validators to be registered for use. There are three types of validators:
regex)internal)callback)
Registration of any type of validator is performed with the registerValidator.
regex validator
Regular expression validators are the simplest type of validators, and as a result are
quite easy to register. The VALID_LETTERS_ONLY validator is implemented with a simple
regular expression: /^[a-zA-Z]+$/. Suppose that this rule was not already
registered. The following code will register this validator:
$v->registerValidator('VALID_LETTERS_ONLY', 'regex', '/^[a-zA-Z]+$/');
The first parameter is a string name for the validator. In the above example it was passed
as a literal string. However, it's better to create a constant instead, to simplify the
addition of validation rules:
define('VALID_LETTERS_ONLY', 'VALID_LETTERS_ONLY');
The second parameter is the type of validator, in this case regex. The third
parameter is the regular expression itself. An optional fourth parameter allows you to
provide the default error message:
define('VALID_LETTERS_ONLY', 'VALID_LETTERS_ONLY');
...
...
$v->registerValidator(
VALID_LETTERS_ONLY,
'regex',
'/^[a-zA-Z]+$/',
'This field must consist only of letters'
);
internal callback validator
Internal callback validators are "internal" because they are defined within the Validator
class. The VALID_COMPARE validator, for example, is a separate function within the
Validator class, and as such is registered as internal. Internal callback
validators can only be created by either modifiying the Validator class itself (not such
a good idea), or by subclassing the Validator and then adding the additional callback
functions and registration.
To register an internal callback validator, you first need to create the callback function.
As an example, consider the VALID_COMPARE function:
function validatorValidCompare($field, $compare)
{
$data =& $this->data;
// if either field isn't set, exit
if (!isset($data[$field]) || !isset($data[$compare])) {
return false;
} else {
return ($data[$field] == $data[$compare]);
} // end if
} // end if
First, we obtain all the arguments with func_get_args(). Next, we ensure
that the necessary number of parameters have been passed (two in this case). Then, we
obtain a reference to the data. Notice that this step references $this->data,
a clear indication that this is an internal callback function.
The next step is to actually pull out the parameters. Internal callback functions will always have the primary field being validated as the first parameter, with additional parameters following it. Note that any custom error messages defined for callback functions are NOT passed to the callback, as they are dealt with internally by the Validator.
The final step is the actual validation, which first checks to ensure that the fields are
set in the data[].
Now that we have an internal callback function, we need to register it. This is performed
with registerValidator:
$v->registerValidator(
VALID_COMPARE,
'internal',
'validatorValidCompare',
'The fields do not match'
);
Notice that the third parameter is now the string name of the callback function to associate with the validator.
In the previous example, the validator was registered through the $v instance
object that has been used throughout this documentation. In practice, however, the registration
for internal callbacks would be performed in the constructor (this is in fact the case for
all pre-defined validators in the Validator). The following example demonstrates fully how
to subclass the validator and create and register a new internal callback function:
define('VALID_ADMIN_PASS', 'VALID_ADMIN_PASS');
class MyValidator extends Validator()
{
function validatorAdminPass($field)
{
$data =& $this->data;
return ($data[$field] == 'admin');
} // end function validator_admin_pass
function MyValidator($obj=null, $rules=null, $data=null)
{
// call parent constructor
$pclass = get_parent_class($this);
$this->$pclass($obj, $rules, $data);
$this->registerValidator(
VALID_ADMIN_PASS,
'internal',
'validatorAdminPass',
"The password must be 'admin'"
);
} // end constructor
} // end class MyValidator
callback validator
A simpler approach to creating callbacks is to create external callbacks, which associate
with regular functions defined outside of the Validator class. The only real difference
is the way you access the data[] array, since it will not have
access to the $this->data member. Rather, Validator provides a static
function which will access a reference to the data, called using
Validator::get_data(). Note that this function can also be used with internal
callback functions, allowing you to easily move the function into or out of a class definition
if necessary. The following example reproduces the previous example but with an external
callback:
define('VALID_ADMIN_PASS', 'VALID_ADMIN_PASS');
...
...
function validatorAdminPass($field)
{
$data =& Validator::getData();
return ($data[$field] == 'admin');
} // end function validator_admin_pass
A filter is a simple way to "clean" field values before validating them. Validator implements filters via callbacks, and keeps the feature lightweight. Unlike validation rules, filters do not need registered in order to use. The callback used to filter can be any number of built-in PHP functions, or it can be a custom function.
The following example demonstrates the use of the PHP trim() function as a
filter:
$v->applyFilter('username', 'trim');
The previous example applies the trim() function to the value of the 'username'
field.
If you want to apply a filter to every element, Validator provides a special constant to
make it easy - simply pass ALL_ELEMENTS as the first argument:
$v->applyFilter(ALL_ELEMENTS, 'trim');
Validator provides two functions, hasError() and getError() for handling error
messages. Both functions accept a field name as a parameter. The hasError() function returns true
if the specified field failed to validate. The getError() function will return the error message of
the validation rule that failed.
As an example, the following function could be created in the app/app_controller.php file, to be used
in any view:
function validationErrors($field)
{
if (isset($this->validator)) {
// hasError returns true if the given field contains errors
if ($this->validator->hasError($field)) {
return sprintf('span>%s</span>',
$this->validator->getError($field));
} // end if
} // end if isset
}
Note that the example assumes that a Validator object is assigned to a member named validator of the
controller (if using Cake).
Now, the new validationErrors() function can be used in a view:
<div>
<label>First name:</label>
<?=$this->inputTag('first_name'); ?>
<?=$this->validationErrors('first_name');?>
</div>
Now, let's look at the code necessary to actually use Validator from a controller (if using Cake).
Consider the following function register() in some controller (perhaps MembersController):
function register()
{
$this->validate = array(
'first_name' => VALID_NOT_EMPTY,
'last_name' => VALID_NOT_EMPTY,
'username' => array(VALID_ALPHANUMERIC,
VALID_RANGE_LENGTH => array("Username must be between 6 and 10 characters", 6, 10)
),
'password' => array(VALID_NOT_EMPTY,
VALID_RANGE_LENGTH => array(null, 6, 10)
),
'confirm' => array(VALID_COMPARE => array(null, 'password')),
'age' => array(VALID_NUMBER, VALID_RANGE => array("You must be at least 13 to register", 13, null))
);
// create new validator
$this->validator = new Validator(&$this);
// trim() all the fields to remove spaces
$this->validator->applyFilter(ALL_ELEMENTS, 'trim');
// perform validation
$result = $this->validator->validates();
// if validation passed, show message
if ($result) {
die('Validation passed!');
} // end if
} // end register()
Now, assume that the MembersController contains the validationErrors() function that was
created before. The register.thtml view may be something like this:
<?=$this->formTag('/members/register/'); ?>
<div>
<label>First name:</label>
<?=$this->inputTag('first_name'); ?>
<?=$this->validationErrors('first_name');?>
</div>
<div>
<label>Last name:</label>
<?=$this->inputTag('last_name'); ?>
<?=$this->validationErrors('last_name');?>
</div>
<div>
<label>Age: </label>
<?=$this->inputTag('age'); ?>
<?=$this->validationErrors('age');?>
</div>
<div>
<label>Username:</label>
<?=$this->inputTag('username'); ?>
<?=$this->validationErrors('username');?>
</div>
<div>
<label>Password:</label>
<?=$this->passwordTag('password'); ?>
<?=$this->validationErrors('password');?>
</div>
<div>
<label>Confirm password:</label>
<?=$this->passwordTag('confirm'); ?>
<?=$this->validationErrors('confirm');?>
</div>
<div>
<?=$this->submitTag('Submit'); ?>
</div>
</form>