Rules and validation
Вернуться к: HTML_QuickForm2
Rules and validation
Server-side validation in HTML_QuickForm2 is performed by HTML_QuickForm2::validate() method. Validation rules doing actual checks on element values are implemented as subclasses of HTML_QuickForm2_Rule, they are added to elements via HTML_QuickForm2_Node::addRule().
Basically, the form is invalid if it contains at least one invalid element. The element is considered invalid if it has an error message (accessible by HTML_QuickForm2_Node::getError()) set and valid otherwise. That error can appear in two different ways:
You can manually set an error message for an element using HTML_QuickForm2_Node::setError().
A rule added to the element will set an error message if it has such a message and its validation routine returned FALSE.
Do not forget to provide an error message to the rule, otherwise the element will be considered valid even if rule's validation routine returns FALSE. Not setting an error message is only useful when chaining (see below).
Some of the elements may perform additional hardcoded validation. For example, file uploads will check the value of 'error' field in $_FILES and assign a relevant error message when file upload was attempted but failed.
Instantiating Rule objects directly
<?php
require_once 'HTML/QuickForm2.php';
require_once 'HTML/QuickForm2/Rule/Required.php';
require_once 'HTML/QuickForm2/Rule/Regex.php';
$form = new HTML_QuickForm2('tutorial');
$username = $form->addElement('text', 'username');
$form->addElement('submit', null, array('value' => 'Send!'));
$username->addRule(new HTML_QuickForm2_Rule_Required(
$username, 'Username is required!'
));
$username->addRule(new HTML_QuickForm2_Rule_Regex(
$username, 'Username should contain only letters, digits and underscores', '/^[a-zA-Z0-9_]+$/'
));
if ($form->validate()) {
// process form
}
echo $form;
?>
Of course, you will rarely need to instantiate Rule subclasses directly, Rule objects can be created by HTML_QuickForm2_Node::createRule() or automatically by addRule() if first parameter is a string representing registered rule type.
Automatic creation of Rule objects
<?php
require_once 'HTML/QuickForm2.php';
$form = new HTML_QuickForm2('tutorial');
$username = $form->addElement('text', 'username');
$form->addElement('submit', null, array('value' => 'Send!'));
$username->addRule('required', 'Username is required!');
$username->addRule('regex', 'Username should contain only letters, digits and underscores',
'/^[a-zA-Z0-9_]+$/');
if ($form->validate()) {
// process form
}
echo $form;
?>
New rule types are registered by HTML_QuickForm2_Factory::registerRule() which accepts rule type name, corresponding class name and optionally file name containing that class and default configuration data for all rules of the given type.
Built-in validation rules
For your convenience, all rules included in the package are already registered with HTML_QuickForm2_Factory and can be easily created with createRule() / addRule(). Some of the rule classes are registered under several names with different configuration data to save keystrokes and improve readability:
<?php
// these calls are identical
$username->addRule('minlength', 'Username should be at least 4 characters long', 4);
$username->addRule('length', 'Username should be at least 4 characters long', array('min' => 4));
// as are these
$start->addRule('lt', 'Start should be less than finish', $finish);
$start->addRule('compare', 'Start should be less than finish',
array('operator' => '<', 'operand' => $finish));
?>
Rule name | Class name | Description | Configuration |
---|---|---|---|
nonempty | HTML_QuickForm2_Rule_Nonempty | Checks that the field is not empty | Minimum number of nonempty values for Containers / arrays, integer |
empty | HTML_QuickForm2_Rule_Empty | Checks that the field is empty | |
required | HTML_QuickForm2_Rule_Required | Like nonempty, but the field is marked as required in output | Like nonempty |
compare | HTML_QuickForm2_Rule_Compare | Compares the value of the field with some other value using the given operator | Either of the following:
|
eq | As compare rule with hardcoded '===' operator | Operand. The values are compared as strings. | |
neq | As compare rule with hardcoded '!==' operator | ||
lt | As compare rule with hardcoded '<' operator | Operand. The values are compared as numbers. | |
lte | As compare rule with hardcoded '<=' operator | ||
gt | As compare rule with hardcoded '>' operator | ||
gte | As compare rule with hardcoded '>=' operator | ||
regex | HTML_QuickForm2_Rule_Regex | Checks that the field value matches the given regular expression. | Regular expression, string. Use slashes for delimiters if you intend to do client-side validation. |
callback | HTML_QuickForm2_Rule_Callback | Checks the value using a provided callback function (method). It is expected to return TRUE if the element is valid | Either of
|
length | HTML_QuickForm2_Rule_Length | Checks that the value's length is within the given limits | Either of
|
minlength | Checks that the value's length is at least the given number of characters | Minimal length, integer | |
maxlength | Checks that the value's length is at most the given number of characters | Maximal length, integer | |
notcallback | HTML_QuickForm2_Rule_NotCallback | Checks the value using a provided callback function (method). It is expected to return FALSE if the element is valid. | Like callback |
notregex | HTML_QuickForm2_Rule_NotRegex | Checks that the field value does not match the given regular expression. | Like regex |
Rules specific for file uploads | |||
maxfilesize | HTML_QuickForm2_Rule_MaxFileSize | Checks that uploaded file size does not exceed the given limit | Maximum allowed file size, integer |
mimetype | HTML_QuickForm2_Rule_MimeType | Checks that uploaded file is of the correct MIME type | Allowed MIME type or an array of types |
Rules specific for containers | |||
each | HTML_QuickForm2_Rule_Each | Validates all elements in a Container using a template Rule | Template Rule, instance of HTML_QuickForm2_Rule |
Usage of builtin rules is covered in builtin-rules.php example installed with the package.
Validating containers
Most of the built-in rules are designed to check scalar values and will not work properly if added to a Container (this includes Groups and Group-based elements as Date and Hierselect), as Containers return their values in an associative array. One notable exception is nonempty / required rule that can validate a container (or <select multiple="multiple" />):
Checks that at least two checkboxes in a group are selected
<?php
$boxGroup = $form->addElement('group', 'boxes')->setLabel('Check at least two:');
$boxGroup->addElement('checkbox', null, array('value' => 'first'))->setContent('First');
$boxGroup->addElement('checkbox', null, array('value' => 'second'))->setContent('Second');
$boxGroup->addElement('checkbox', null, array('value' => 'third'))->setContent('Third');
$boxGroup->addRule('required', 'Check at least two boxes', 2);
?>
It is of course possible to implement a custom rule that will properly handle an associative array as the element's value. It is also possible to leverage existing "scalar" rules to validate Containers by using each rule, it applies a template rule to all the elements in a Container and considers Container valid if its validation routine returns TRUE for all of them:
Checks that all phone fields in a group contain numeric data
<?php
$phones = $form->addElement('group', 'phones')->setLabel('Phones (numeric):')
->setSeparator('<br />');
$phones->addElement('text', '0');
$phones->addElement('text', '1');
$phones->addRule('each', 'Phones should be numeric',
$phones->createRule('regex', '', '/^\\d+([ -]\\d+)*$/'));
?>
More specific rules are run first: rules added to container will be checked after rules added to its contained elements.
Chaining the rules
HTML_QuickForm2 allows validation of elements based on values and validation status of other elements. This is done by building a "chain" of validation rules using HTML_QuickForm2_Rule::and_() and HTML_QuickForm2_Rule::or_() methods. Execution of the chain starts with a rule that was added to an element, then results of other rules' validation routines are combined using corresponding logical operators. Error is only set on the element if the whole chain returned FALSE.
Behaviour of and_() and or_() is similar to PHP's and and or operators:
and_() has higher precedence than or_().
Evaluation is short-circuited. If first argument of and_() evaluates to FALSE then FALSE is returned without evaluating second argument, if first argument of or_() evaluates to TRUE then TRUE is returned without evaluating second argument.
Rules that are added to the chain behave the same way as the rules that are added directly to the element they validate (this is not necessarily the same element the chain is added to), they will set an error if the rule itself returns FALSE, not the chain. Thus it is often needed not to provide error messages to the rules. It may also make sense to add a chain of rules to a chain (this is similar to adding parentheses to a PHP expression with and and or).
Skips checking email field if "receive email" box is not checked
<?php
$emailPresent = $email->createRule('nonempty', 'Supply a valid email if you want to receive our spam');
// note lack of error message here, error should only be set by previous rule
$emailValid = $email->createRule('callback', '', array('callback' => 'filter_var',
'arguments' => array(FILTER_VALIDATE_EMAIL)));
// note lack of error message for 'empty' rule, we don't want error on a checkbox
$spamCheck->addRule('empty')
->or_($emailPresent->and_($emailValid));
?>
Checks password fields in password change form
<?php
$newPassword->addRule('empty')
->and_($repPassword->createRule('empty'))
->or_($newPassword->createRule('minlength', 'The password is too short', 6))
->and_($repPassword->createRule('eq', 'The passwords do not match', $newPassword))
->and_($oldPassword->createRule('nonempty', 'Supply old password if you want to change it'));
?>
Client-side validation
Validation library
Client-side validation depends on a JS library residing in quickform.js file. Neither a link to that file nor its contents is automatically included in the output generated by a renderer, the next section describes how you can properly handle including it.
You can tell a rule to also generate Javascript necessary for client-side validation. This is done by passing a $runAt parameter with HTML_QuickForm2_Rule::CLIENT flag set to addRule():
<?php
// if first parameter to addRule() is a string:
$username->addRule('required', 'Username is required', null,
HTML_QuickForm2_Rule::SERVER | HTML_QuickForm2_Rule::CLIENT);
// if first parameter to addRule() is a Rule instance:
$username->addRule($username->createRule('required', 'Username is required'),
HTML_QuickForm2_Rule::CLIENT_SERVER); // using a shorthand for above constants
?>
If more rules were chained to the added one with and_() and or_(), Javascript will be generated for the whole chain.
Since release 0.6.0 it is possible to run client-side rules for an element on changing its value or on it losing input focus ('onchange' and 'onblur' events) in addition to form submit ('onsubmit' event). This is triggered by passing a $runAt parameter with HTML_QuickForm2_Rule::ONBLUR_CLIENT flag set to addRule(). If a rule has chained rules, then validation will be triggered by all elements appearing in a chain.
<?php
// here validation will be run onchange / onblur of both $newPassword and $repPassword fields
$newPassword->addRule('empty', '', null, HTML_QuickForm2_Rule::ONBLUR_CLIENT_SERVER)
->and_($repPassword->createRule('empty'))
->or_($repPassword->createRule('eq', 'The passwords do not match', $newPassword));
?>
Another change introduced in 0.6.0 is that validation errors are now output near the elements instead of being shown in Javascript alert(). In a nuthshell, client-side validation behaviour in HTML_QuickForm2 0.6.0+ is more similar to that of HTML_QuickForm_DHTMLRulesTableless than to that of old HTML_QuickForm.
Most of the built-in rules are able to run client-side, the only exceptions are maxfilesize and mimetype rules specific for file uploads.
If you want to run callback rule client-side, you will obviously need to implement a callback in Javascript as well as in PHP. If you don't explicitly set 'js_callback' configuration parameter, callback rule will try to run Javascript function having the same name as provided PHP 'callback'. This may be especially useful if you use HTML_AJAX to proxy PHP classes or callbacks in Javascript.
When running regex rules client-side, you should stick to regular expression syntax common in PHP and Javascript:
Use a slash / as a delimiter.
Use only i, m, u pattern modifiers. If u modifier is used, PHP's Unicode escapes \x{NNNN} are automatically converted to Javascript's Unicode escapes \uNNNN when creating a client-side rule.
Do not use regular expession features that are not supported in Javascript (e.g. lookbehind assertions).
While it is possible to add a client-side only rule
<?php
$username->addRule('minlength', 'Username should be at least 4 characters long', 4,
HTML_QuickForm2_Rule::CLIENT);
?>it is not recommended unless you perform the same validation server-side using some other rule.
Вернуться к: HTML_QuickForm2