Validation Component


Validation - 图1

Overview

Phalcon\Validation is an independent validation component that validates an arbitrary set of data. This component can be used to implement validation rules on data objects that do not belong to a model or collection.

The following example shows its basic usage:

  1. <?php
  2. use Phalcon\Validation;
  3. use Phalcon\Validation\Validator\Email;
  4. use Phalcon\Validation\Validator\PresenceOf;
  5. $validation = new Validation();
  6. $validation->add(
  7. 'name',
  8. new PresenceOf(
  9. [
  10. 'message' => 'The name is required',
  11. ]
  12. )
  13. );
  14. $validation->add(
  15. 'email',
  16. new PresenceOf(
  17. [
  18. 'message' => 'The e-mail is required',
  19. ]
  20. )
  21. );
  22. $validation->add(
  23. 'email',
  24. new Email(
  25. [
  26. 'message' => 'The e-mail is not valid',
  27. ]
  28. )
  29. );
  30. $messages = $validation->validate($_POST);
  31. if (count($messages)) {
  32. foreach ($messages as $message) {
  33. echo $message, '<br>';
  34. }
  35. }

The loosely-coupled design of this component allows you to create your own validators along with the ones provided by the framework.

Initializing Validation

Validation chains can be initialized in a direct manner by just adding validators to the Phalcon\Validation object. You can put your validations in a separate file for better re-use code and organization:

  1. <?php
  2. use Phalcon\Validation;
  3. use Phalcon\Validation\Validator\Email;
  4. use Phalcon\Validation\Validator\PresenceOf;
  5. class MyValidation extends Validation
  6. {
  7. public function initialize()
  8. {
  9. $this->add(
  10. 'name',
  11. new PresenceOf(
  12. [
  13. 'message' => 'The name is required',
  14. ]
  15. )
  16. );
  17. $this->add(
  18. 'email',
  19. new PresenceOf(
  20. [
  21. 'message' => 'The e-mail is required',
  22. ]
  23. )
  24. );
  25. $this->add(
  26. 'email',
  27. new Email(
  28. [
  29. 'message' => 'The e-mail is not valid',
  30. ]
  31. )
  32. );
  33. }
  34. }

Then initialize and use your own validator:

  1. <?php
  2. $validation = new MyValidation();
  3. $messages = $validation->validate($_POST);
  4. if (count($messages)) {
  5. foreach ($messages as $message) {
  6. echo $message, '<br>';
  7. }
  8. }

Validators

Phalcon exposes a set of built-in validators for this component:

ClassExplanation
Phalcon\Validation\Validator\AlnumValidates that a field’s value is only alphanumeric character(s).
Phalcon\Validation\Validator\AlphaValidates that a field’s value is only alphabetic character(s).
Phalcon\Validation\Validator\BetweenValidates that a value is between two values
Phalcon\Validation\Validator\CallbackValidates using callback function
Phalcon\Validation\Validator\ConfirmationValidates that a value is the same as another present in the data
Phalcon\Validation\Validator\CreditCardValidates a credit card number
Phalcon\Validation\Validator\DateValidates that a field’s value is a valid date.
Phalcon\Validation\Validator\DigitValidates that a field’s value is only numeric character(s).
Phalcon\Validation\Validator\EmailValidates that field contains a valid email format
Phalcon\Validation\Validator\ExclusionInValidates that a value is not within a list of possible values
Phalcon\Validation\Validator\FileValidates that a field’s value is a correct file.
Phalcon\Validation\Validator\File\AbstractFile
Phalcon\Validation\Validator\File\MimeType
Phalcon\Validation\Validator\File\Resolution\Equal
Phalcon\Validation\Validator\File\Resolution\Max
Phalcon\Validation\Validator\File\Resolution\Min
Phalcon\Validation\Validator\File\Size\Equal
Phalcon\Validation\Validator\File\Size\Max
Phalcon\Validation\Validator\File\Size\Min
Phalcon\Validation\Validator\IdenticalValidates that a field’s value is the same as a specified value
Phalcon\Validation\Validator\InclusionInValidates that a value is within a list of possible values
Phalcon\Validation\Validator\Ip
Phalcon\Validation\Validator\NumericalityValidates that a field’s value is a valid numeric value.
Phalcon\Validation\Validator\PresenceOfValidates that a field’s value is not null or empty string.
Phalcon\Validation\Validator\RegexValidates that the value of a field matches a regular expression
Phalcon\Validation\Validator\StringLengthValidates the length of a string
Phalcon\Validation\Validator\StringLength\Max
Phalcon\Validation\Validator\StringLength\Min
Phalcon\Validation\Validator\UniquenessValidates that a field’s value is unique in the related model.
Phalcon\Validation\Validator\UrlValidates that field contains a valid URL

The following example explains how to create additional validators for this component:

  1. <?php
  2. use Phalcon\Validation;
  3. use Phalcon\Validation\Message;
  4. use Phalcon\Validation\Validator;
  5. class IpValidator extends Validator
  6. {
  7. /**
  8. * Executes the validation
  9. *
  10. * @param Validation $validator
  11. * @param string $attribute
  12. * @return boolean
  13. */
  14. public function validate(Validation $validator, $attribute)
  15. {
  16. $value = $validator->getValue($attribute);
  17. if (!filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
  18. $message = $this->getOption('message');
  19. if (!$message) {
  20. $message = 'The IP is not valid';
  21. }
  22. $validator->appendMessage(
  23. new Message($message, $attribute, 'Ip')
  24. );
  25. return false;
  26. }
  27. return true;
  28. }
  29. }

It is important that validators return a valid boolean value indicating if the validation was successful or not.

Callback Validator

By using Phalcon\Validation\Validator\Callback you can execute custom function which must return boolean or new validator class which will be used to validate the same field. By returning true validation will be successful, returning false will mean validation failed. When executing this validator Phalcon will pass data depending what it is - if it’s an entity (i.e. a model, a stdClass etc.) then entity will be passed, otherwise data (i.e an array like $_POST). There is example:

  1. <?php
  2. use \Phalcon\Validation;
  3. use \Phalcon\Validation\Validator\Callback;
  4. use \Phalcon\Validation\Validator\PresenceOf;
  5. $validation = new Validation();
  6. $validation->add(
  7. 'amount',
  8. new Callback(
  9. [
  10. 'callback' => function($data) {
  11. return $data['amount'] % 2 == 0;
  12. },
  13. 'message' => 'Only even number of products are accepted'
  14. ]
  15. )
  16. );
  17. $validation->add(
  18. 'amount',
  19. new Callback(
  20. [
  21. 'callback' => function($data) {
  22. if($data['amount'] % 2 == 0) {
  23. return $data['amount'] != 2;
  24. }
  25. return true;
  26. },
  27. 'message' => "You can't buy 2 products"
  28. ]
  29. )
  30. );
  31. $validation->add(
  32. 'description',
  33. new Callback(
  34. [
  35. 'callback' => function($data) {
  36. if($data['amount'] >= 10) {
  37. return new PresenceOf(
  38. [
  39. 'message' => 'You must write why you need so big amount.'
  40. ]
  41. );
  42. }
  43. return true;
  44. }
  45. ]
  46. )
  47. );
  48. $messages = $validation->validate(['amount' => 1]); // will return message from first validator
  49. $messages = $validation->validate(['amount' => 2]); // will return message from second validator
  50. $messages = $validation->validate(['amount' => 10]); // will return message from validator returned by third validator

Validation Messages

Phalcon\Validation has a messaging subsystem that provides a flexible way to output or store the validation messages generated during the validation processes.

Each message consists of an instance of the class Phalcon\Validation\Message. The set of messages generated can be retrieved with the getMessages() method. Each message provides extended information like the attribute that generated the message or the message type:

  1. <?php
  2. $messages = $validation->validate();
  3. if (count($messages)) {
  4. foreach ($messages as $message) {
  5. echo 'Message: ', $message->getMessage(), "\n";
  6. echo 'Field: ', $message->getField(), "\n";
  7. echo 'Type: ', $message->getType(), "\n";
  8. }
  9. }

You can pass a message parameter to change/translate the default message in each validator, even it’s possible to use the wildcard :field in the message to be replaced by the label of the field:

  1. <?php
  2. use Phalcon\Validation\Validator\Email;
  3. $validation->add(
  4. 'email',
  5. new Email(
  6. [
  7. 'message' => 'The e-mail is not valid',
  8. ]
  9. )
  10. );

By default, the getMessages() method returns all the messages generated during validation. You can filter messages for a specific field using the filter() method:

  1. <?php
  2. $messages = $validation->validate();
  3. if (count($messages)) {
  4. // Filter only the messages generated for the field 'name'
  5. $filteredMessages = $messages->filter('name');
  6. foreach ($filteredMessages as $message) {
  7. echo $message;
  8. }
  9. }

Filtering of Data

Data can be filtered prior to the validation ensuring that malicious or incorrect data is not validated.

  1. <?php
  2. use Phalcon\Validation;
  3. $validation = new Validation();
  4. $validation->add(
  5. 'name',
  6. new PresenceOf(
  7. [
  8. 'message' => 'The name is required',
  9. ]
  10. )
  11. );
  12. $validation->add(
  13. 'email',
  14. new PresenceOf(
  15. [
  16. 'message' => 'The email is required',
  17. ]
  18. )
  19. );
  20. // Filter any extra space
  21. $validation->setFilters('name', 'trim');
  22. $validation->setFilters('email', 'trim');

Filtering and sanitizing is performed using the filter component. You can add more filters to this component or use the built-in ones.

Validation Events

When validations are organized in classes, you can implement the beforeValidation() and afterValidation() methods to perform additional checks, filters, clean-up, etc. If the beforeValidation() method returns false the validation is automatically cancelled:

  1. <?php
  2. use Phalcon\Validation;
  3. class LoginValidation extends Validation
  4. {
  5. public function initialize()
  6. {
  7. // ...
  8. }
  9. /**
  10. * Executed before validation
  11. *
  12. * @param array $data
  13. * @param object $entity
  14. * @param Phalcon\Validation\Message\Group $messages
  15. * @return bool
  16. */
  17. public function beforeValidation($data, $entity, $messages)
  18. {
  19. if ($this->request->getHttpHost() !== 'admin.mydomain.com') {
  20. $messages->appendMessage(
  21. new Message('Only users can log on in the administration domain')
  22. );
  23. return false;
  24. }
  25. return true;
  26. }
  27. /**
  28. * Executed after validation
  29. *
  30. * @param array $data
  31. * @param object $entity
  32. * @param Phalcon\Validation\Message\Group $messages
  33. */
  34. public function afterValidation($data, $entity, $messages)
  35. {
  36. // ... Add additional messages or perform more validations
  37. }
  38. }

Cancelling Validations

By default all validators assigned to a field are tested regardless if one of them have failed or not. You can change this behavior by telling the validation component which validator may stop the validation:

  1. <?php
  2. use Phalcon\Validation;
  3. use Phalcon\Validation\Validator\Regex;
  4. use Phalcon\Validation\Validator\PresenceOf;
  5. $validation = new Validation();
  6. $validation->add(
  7. 'telephone',
  8. new PresenceOf(
  9. [
  10. 'message' => 'The telephone is required',
  11. 'cancelOnFail' => true,
  12. ]
  13. )
  14. );
  15. $validation->add(
  16. 'telephone',
  17. new Regex(
  18. [
  19. 'message' => 'The telephone is required',
  20. 'pattern' => '/\+44 [0-9]+/',
  21. ]
  22. )
  23. );
  24. $validation->add(
  25. 'telephone',
  26. new StringLength(
  27. [
  28. 'messageMinimum' => 'The telephone is too short',
  29. 'min' => 2,
  30. ]
  31. )
  32. );

The first validator has the option cancelOnFail with a value of true, therefore if that validator fails the remaining validators in the chain are not executed.

If you are creating custom validators you can dynamically stop the validation chain by setting the cancelOnFail option:

  1. <?php
  2. use Phalcon\Validation;
  3. use Phalcon\Validation\Message;
  4. use Phalcon\Validation\Validator;
  5. class MyValidator extends Validator
  6. {
  7. /**
  8. * Executes the validation
  9. *
  10. * @param Phalcon\Validation $validator
  11. * @param string $attribute
  12. * @return boolean
  13. */
  14. public function validate(Validation $validator, $attribute)
  15. {
  16. // If the attribute value is name we must stop the chain
  17. if ($attribute === 'name') {
  18. $validator->setOption('cancelOnFail', true);
  19. }
  20. // ...
  21. }
  22. }

Avoid validating empty values

You can pass the option allowEmpty to all the built-in validators to avoid the validation to be performed if an empty value is passed:

  1. <?php
  2. use Phalcon\Validation;
  3. use Phalcon\Validation\Validator\Regex;
  4. $validation = new Validation();
  5. $validation->add(
  6. 'telephone',
  7. new Regex(
  8. [
  9. 'message' => 'The telephone is required',
  10. 'pattern' => '/\+44 [0-9]+/',
  11. 'allowEmpty' => true,
  12. ]
  13. )
  14. );

Recursive Validation

You can also run Validation instances within another via the afterValidation() method. In this example, validating the CompanyValidation instance will also check the PhoneValidation instance:

  1. <?php
  2. use Phalcon\Validation;
  3. class CompanyValidation extends Validation
  4. {
  5. /**
  6. * @var PhoneValidation
  7. */
  8. protected $phoneValidation;
  9. public function initialize()
  10. {
  11. $this->phoneValidation = new PhoneValidation();
  12. }
  13. public function afterValidation($data, $entity, $messages)
  14. {
  15. $phoneValidationMessages = $this->phoneValidation->validate(
  16. $data['phone']
  17. );
  18. $messages->appendMessages(
  19. $phoneValidationMessages
  20. );
  21. }
  22. }