Overview
Phalcon\Filter\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:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Email;
use Phalcon\Filter\Validation\Validator\PresenceOf;
$validation = new Validation();
$validation->add(
'name',
new PresenceOf(
[
'message' => 'The name is required',
]
)
);
$validation->add(
'email',
new PresenceOf(
[
'message' => 'The e-mail is required',
]
)
);
$validation->add(
'email',
new Email(
[
'message' => 'The e-mail is not valid',
]
)
);
$messages = $validation->validate($_POST);
if (count($messages)) {
foreach ($messages as $message) {
echo $message, '<br>';
}
}The loosely-coupled design of this component allows you to create your own validators along with the ones provided by the framework.
Methods
public function __construct(
array $validators = []
)public function add(
mixed $field,
ValidatorInterface $validator
): ValidationInterfaceAdds a validator to a field
public function appendMessage(
MessageInterface $message
): ValidationInterfaceAppends a message to the messages list
public function bind(
object $entity,
array | object $data,
array $whitelist = []
): ValidationInterfaceAssigns the data to an entity. The entity is used to obtain the validation values. When $whitelist is supplied, only the fields listed in it will be assigned to the entity; all other fields are skipped.
public static function getDefaultMessage(
string $validatorClassName
): stringReturns the default message registered for a validator class, or an empty string when none has been registered
public function getEntity(): objectReturns the bound entity
public function getFilters(
string $field = null
): mixedReturns all the filters or a specific one
public function getLabel(
string $field
): stringGet a label for the field
public function getMessages(): MessagesReturns the registered validators
public function getValidators(): arrayReturns the validators added to the validation
public function getValue(
string $field
): mixedGets a value to validate in the array/object data source
public function getValueByEntity(mixed $entity, string $field): mixedGets the value to validate in the object entity source
public function getValueByData(mixed $data, string $field): mixedGets the value to validate in the array/object data source
public function rule(
mixed $field,
ValidatorInterface $validator
): ValidationInterfaceAlias of add method
public function rules(
mixed $field,
array $validators
): ValidationInterfaceAdds the validators to a field
public static function setDefaultMessages(
array $messages = []
): arrayRegisters default messages for validators, keyed by validator class name. Calls are merged with any previously registered defaults. Returns the full map of registered defaults.
public function setEntity(
object $entity
): voidSets the bound entity
public function setFilters(
string $field,
array | string $filters
): ValidationInterfaceAdd filters to the field
public function setLabels(
array $labels
): voidAdds labels for fields
public function validate(
array | object $data = null,
object $entity = null,
array $whitelist = []
): MessagesValidate a set of data according to a set of rules. When $whitelist is supplied, only the listed fields are bound to $entity; validation itself still runs over all configured fields.
public function fails(): boolVerify if the validation has failed or not. Returns true when validation fails, false when validation succeeds.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\PresenceOf;
$validation = new Validation();
$validation->add('name', new PresenceOf(['message' => 'Name is required']));
$validation->validate(['name' => '']);
if ($validation->fails()) {
foreach ($validation->getMessages() as $message) {
echo $message, PHP_EOL;
}
}Activation
Validation chains can be initialized in a direct manner by adding validators to the Phalcon\Filter\Validation object. You can put your validations in a separate file for better code reuse and organization.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Email;
use Phalcon\Filter\Validation\Validator\PresenceOf;
class MyValidation extends Validation
{
public function initialize()
{
$this->add(
'name',
new PresenceOf(
[
'message' => 'The name is required',
]
)
);
$this->add(
'email',
new PresenceOf(
[
'message' => 'The e-mail is required',
]
)
);
$this->add(
'email',
new Email(
[
'message' => 'The e-mail is not valid',
]
)
);
}
}Then initialize and use your own validator:
<?php
$validation = new MyValidation();
$messages = $validation->validate($_POST);
if (count($messages)) {
foreach ($messages as $message) {
echo $message, '<br>';
}
}Validators
Phalcon offers a set of built-in validators for this component:
Alnum
Check for alphanumeric character(s)
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Alnum;
$validator = new Validation();
$validator->add(
"username",
new Alnum(
[
"message" => ":field must contain only alphanumeric characters",
]
)
);
$validator->add(
[
"username",
"name",
],
new Alnum(
[
"message" => [
"username" => "username must contain only alphanumeric characters",
"name" => "name must contain only alphanumeric characters",
],
]
)
);Alpha
Check for alphabetic character(s)
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Alpha;
$validator = new Validation();
$validator->add(
"username",
new Alpha(
[
"message" => ":field must contain only letters",
]
)
);
$validator->add(
[
"username",
"name",
],
new Alpha(
[
"message" => [
"username" => "username must contain only letters",
"name" => "name must contain only letters",
],
]
)
);Between
Validates that a value is between an inclusive range of two values. The validation passes if for a value L, the minimum is less or equal to L, and L is less or equal to the maximum. The boundaries are included in this validation. The formula is:
minimum <= value <= maximum<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Between;
$validator = new Validation();
$validator->add(
"price",
new Between(
[
"minimum" => 0,
"maximum" => 100,
"message" => "The price must be between 0 and 100",
]
)
);
$validator->add(
[
"price",
"amount",
],
new Between(
[
"minimum" => [
"price" => 0,
"amount" => 0,
],
"maximum" => [
"price" => 100,
"amount" => 50,
],
"message" => [
"price" => "The price must be between 0 and 100",
"amount" => "The amount must be between 0 and 50",
],
]
)
);Callback
By using Phalcon\Filter\Validation\Validator\Callback you can execute a custom function that must return boolean or a 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 on what it is - if it’s an entity (i.e. a model, a stdClass etc.) then the entity will be passed, otherwise data (i.e. an array like $_POST). There is an example:
<?php
use \Phalcon\Filter\Validation;
use \Phalcon\Filter\Validation\Validator\Callback;
use \Phalcon\Filter\Validation\Validator\PresenceOf;
$validation = new Validation();
$validation->add(
'amount',
new Callback(
[
'callback' => function ($data) {
return $data['amount'] % 2 == 0;
},
'message' => 'Only even number of products are accepted'
]
)
);
$validation->add(
'amount',
new Callback(
[
'callback' => function ($data) {
if ($data['amount'] % 2 == 0) {
return $data['amount'] != 2;
}
return true;
},
'message' => "You cannot buy 2 products"
]
)
);
$validation->add(
'description',
new Callback(
[
'callback' => function ($data) {
if ($data['amount'] >= 10) {
return new PresenceOf(
[
'message' => 'You must write why you need so big amount.'
]
);
}
return true;
}
]
)
);
// Validator #1
$messages = $validation->validate(['amount' => 1]);
// Validator #2
$messages = $validation->validate(['amount' => 2]);
// Validator #3
$messages = $validation->validate(['amount' => 10]);<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Callback;
use Phalcon\Filter\Validation\Validator\Numericality;
$validator = new Validation();
$validator->add(
["user", "admin"],
new Callback(
[
"message" => "User cannot belong to two groups",
"callback" => function($data) {
if (!empty($data->getUser()) &&
!empty($data->getAdmin())) {
return false;
}
return true;
}
]
)
);
$validator->add(
"amount",
new Callback(
[
"callback" => function($data) {
if (!empty($data->getProduct())) {
return new Numericality(
[
"message" => "Amount must be a number."
]
);
}
}
]
)
);The closure passed as the callback option keeps its own $this. A closure that you write inside a class can therefore still read the properties and call the methods of the object that created it.
To reach the validator from inside the callback, declare a second parameter. The Phalcon\Filter\Validation\Validator\Callback validator is passed as the second argument to every closure that declares one. The callback can then call the validator’s own public methods - such as setTemplate() - to change the failure message depending on which check failed. A closure that declares one parameter receives the data only. String function names and [object, method] callables never receive the validator.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Callback;
$validation = new Validation();
$validation->add(
'title',
new Callback(
[
'message' => 'The title is not valid',
'callback' => function ($data, $validator) {
if (!is_string($data['title'])) {
$validator->setTemplate('Title is not a string');
return false;
}
if (strlen($data['title']) > 10) {
$validator->setTemplate('Title too long');
return false;
}
return true;
},
]
)
);A template set this way applies to the current call only. The validator restores the previous template when the call ends. A later call that does not call setTemplate() therefore falls back to the message or template option.
Confirmation
Checks that two values have the same value
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Confirmation;
$validator = new Validation();
$validator->add(
"password",
new Confirmation(
[
"message" => "Password doesn't match confirmation",
"with" => "confirmPassword",
]
)
);
$validator->add(
[
"password",
"email",
],
new Confirmation(
[
"message" => [
"password" => "Password doesn't match confirmation",
"email" => "Email doesn't match confirmation",
],
"with" => [
"password" => "confirmPassword",
"email" => "confirmEmail",
],
]
)
);CreditCard
Checks if a value has a valid credit card number
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\CreditCard;
$validator = new Validation();
$validator->add(
"creditCard",
new CreditCard(
[
"message" => "The credit card number is not valid",
]
)
);
$validator->add(
[
"creditCard",
"secondCreditCard",
],
new CreditCard(
[
"message" => [
"creditCard" => "The credit card number is not valid",
"secondCreditCard" => "The second credit card number is not valid",
],
]
)
);Date
Checks if a value is a valid date
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Date as DateValidator;
$validator = new Validation();
$validator->add(
"date",
new DateValidator(
[
"format" => "d-m-Y",
"message" => "The date is invalid",
]
)
);
$validator->add(
[
"date",
"anotherDate",
],
new DateValidator(
[
"format" => [
"date" => "d-m-Y",
"anotherDate" => "Y-m-d",
],
"message" => [
"date" => "The date is invalid",
"anotherDate" => "The another date is invalid",
],
]
)
);Digit
Check for numeric character(s)
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Digit;
$validator = new Validation();
$validator->add(
"height",
new Digit(
[
"message" => ":field must be numeric",
]
)
);
$validator->add(
[
"height",
"width",
],
new Digit(
[
"message" => [
"height" => "height must be numeric",
"width" => "width must be numeric",
],
]
)
);Checks if a value has a correct e-mail format. If the data to be validated contains UTF-8 characters, you can set the allowUTF8 option to true to allow them.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Email;
$validator = new Validation();
$validator->add(
"email",
new Email(
[
"message" => "The e-mail is not valid",
]
)
);
$validator->add(
[
"email",
"anotherEmail",
],
new Email(
[
"message" => [
"email" => "The e-mail is not valid",
"anotherEmail" => "The another e-mail is not valid",
],
]
)
);
$validator->add(
"tä[email protected]",
new Email(
[
"message" => "The e-mail is not valid",
"allowUTF8" => true,
]
)
);ExclusionIn
Check if a value is not included in a list of values
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\ExclusionIn;
$validator = new Validation();
$validator->add(
"status",
new ExclusionIn(
[
"message" => "The status must not be A or B",
"domain" => [
"A",
"B",
],
]
)
);
$validator->add(
[
"status",
"type",
],
new ExclusionIn(
[
"message" => [
"status" => "The status must not be A or B",
"type" => "The type must not be 1 or "
],
"domain" => [
"status" => [
"A",
"B",
],
"type" => [1, 2],
],
]
)
);File
Checks if a value has a correct file
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File;
$validator = new Validation();
$validator->add(
"file",
new File(
[
"maxSize" => "2M",
"messageSize" => ":field exceeds the max size (:size)",
"allowedTypes" => [
"image/jpeg",
"image/png",
],
"messageType" => "Allowed file types are :types",
"maxResolution" => "800x600",
"messageMaxResolution" => "Max resolution of :field is :resolution",
"aspectRatio" => "16x9",
"messageAspectRatio" => "Aspect ratio of :field has to be :ratio",
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new File(
[
"maxSize" => [
"file" => "2M",
"anotherFile" => "4M",
],
"messageSize" => [
"file" => "file exceeds the max size 2M",
"anotherFile" => "anotherFile exceeds the max size 4M",
],
"allowedTypes" => [
"file" => [
"image/jpeg",
"image/png",
],
"anotherFile" => [
"image/gif",
"image/bmp",
],
],
"messageType" => [
"file" => "Allowed file types are image/jpeg and image/png",
"anotherFile" => "Allowed file types are image/gif and image/bmp",
],
"maxResolution" => [
"file" => "800x600",
"anotherFile" => "1024x768",
],
"messageMaxResolution" => [
"file" => "Max resolution of file is 800x600",
"anotherFile" => "Max resolution of file is 1024x768",
],
]
)
);The File validator forwards an allowWildcards option to the File MimeType check it builds from allowedTypes. Set it to true to treat each allowedTypes entry as an anchored regular expression:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File;
$validator = new Validation();
$validator->add(
"file",
new File(
[
"allowedTypes" => [
"image/.*",
"video/.*",
],
"allowWildcards" => true,
"messageType" => "Allowed file types are :types",
]
)
);File MimeType
Checks if a value has a correct file mime type
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\MimeType;
$validator = new Validation();
$validator->add(
"file",
new MimeType(
[
"types" => [
"image/jpeg",
"image/png",
],
"message" => "Allowed file types are :types"
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new MimeType(
[
"types" => [
"file" => [
"image/jpeg",
"image/png",
],
"anotherFile" => [
"image/gif",
"image/bmp",
],
],
"message" => [
"file" => "Allowed file types are image/jpeg and image/png",
"anotherFile" => "Allowed file types are image/gif and image/bmp",
]
]
)
);By default the detected MIME type must match one of the configured types exactly. Set the allowWildcards option to true to match each configured entry as an anchored regular expression instead, which accepts a whole MIME family without listing every subtype:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\MimeType;
$validator = new Validation();
$validator->add(
"file",
new MimeType(
[
"types" => [
"image/.*",
"video/.*",
],
"allowWildcards" => true,
"message" => "Allowed file types are :types",
]
)
);Each entry is anchored on both ends (#^...$#), so image/.* matches image/png and image/jpeg but not text/plain. An exact string comparison is tried first, so literal types that contain regular-expression metacharacters, such as image/svg+xml, still match themselves. The option defaults to false, which preserves the exact-match behavior.
File Resolution AspectRatio
Checks if a file has the exact aspect ratio
The ratio option uses the same WxH format as the resolution validators (for instance 16x9). The comparison uses integer cross-multiplication, so the image dimensions must match the ratio exactly: 1920x1080 matches 16x9, 1366x768 does not. The message supports the :ratio placeholder.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\Resolution\AspectRatio;
$validator = new Validation();
$validator->add(
"file",
new AspectRatio(
[
"ratio" => "16x9",
"message" => "The aspect ratio of the field :field has to be :ratio",
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new AspectRatio(
[
"ratio" => [
"file" => "16x9",
"anotherFile" => "4x3",
],
"message" => [
"file" => "Aspect ratio of file has to be 16x9",
"anotherFile" => "Aspect ratio of anotherFile has to be 4x3",
],
]
)
);File Resolution Equal
Check if a file has the right resolution
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\Resolution\Equal;
$validator = new Validation();
$validator->add(
"file",
new Equal(
[
"resolution" => "800x600",
"message" => "The resolution of the field :field has to be equal :resolution",
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new Equal(
[
"resolution" => [
"file" => "800x600",
"anotherFile" => "1024x768",
],
"message" => [
"file" => "Equal resolution of file has to be 800x600",
"anotherFile" => "Equal resolution of file has to be 1024x768",
],
]
)
);File Resolution Max
Check if a file has the right resolution
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\Resolution\Max;
$validator = new Validation();
$validator->add(
"file",
new Max(
[
"resolution" => "800x600",
"message" => "Max resolution of :field is :resolution",
"included" => true,
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new Max(
[
"resolution" => [
"file" => "800x600",
"anotherFile" => "1024x768",
],
"included" => [
"file" => false,
"anotherFile" => true,
],
"message" => [
"file" => "Max resolution of file is 800x600",
"anotherFile" => "Max resolution of file is 1024x768",
],
]
)
);File Resolution Min
Check if a file has the right resolution
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\Resolution\Min;
$validator = new Validation();
$validator->add(
"file",
new Min(
[
"resolution" => "800x600",
"message" => "Min resolution of :field is :resolution",
"included" => true,
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new Min(
[
"resolution" => [
"file" => "800x600",
"anotherFile" => "1024x768",
],
"included" => [
"file" => false,
"anotherFile" => true,
],
"message" => [
"file" => "Min resolution of file is 800x600",
"anotherFile" => "Min resolution of file is 1024x768",
],
]
)
);File Size Equal
Checks if a value has a correct file
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\Size\Equal;
$validator = new Validation();
$validator->add(
"file",
new Equal(
[
"size" => "2M",
"included" => true,
"message" => ":field exceeds the size (:size)",
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new Equal(
[
"size" => [
"file" => "2M",
"anotherFile" => "4M",
],
"included" => [
"file" => false,
"anotherFile" => true,
],
"message" => [
"file" => "file does not have the correct size",
"anotherFile" => "anotherFile wrong size (4MB)",
],
]
)
);File Size Max
Checks if a value has a correct file
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\Size\Max;
$validator = new Validation();
$validator->add(
"file",
new Max(
[
"size" => "2M",
"included" => true,
"message" => ":field exceeds the max size (:size)",
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new Max(
[
"size" => [
"file" => "2M",
"anotherFile" => "4M",
],
"included" => [
"file" => false,
"anotherFile" => true,
],
"message" => [
"file" => "file exceeds the max size 2M",
"anotherFile" => "anotherFile exceeds the max size 4M",
],
]
)
);File Size Min
Checks if a value has a correct file
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\File\Size\Min;
$validator = new Validation();
$validator->add(
"file",
new Min(
[
"size" => "2M",
"included" => true,
"message" => ":field exceeds the min size (:size)",
]
)
);
$validator->add(
[
"file",
"anotherFile",
],
new Min(
[
"size" => [
"file" => "2M",
"anotherFile" => "4M",
],
"included" => [
"file" => false,
"anotherFile" => true,
],
"message" => [
"file" => "file exceeds the min size 2M",
"anotherFile" => "anotherFile exceeds the min size 4M",
],
]
)
);Files
Checks that a field holds a correct array of uploaded files.
The Files validator accepts the same options as File and applies them to every file in the field. It validates the <input type="file" name="photos[]" multiple> case, where one input carries several files. Validation stops at the first file that fails a rule.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Files;
$validator = new Validation();
$validator->add(
"photos",
new Files(
[
"maxSize" => "2M",
"messageSize" => ":field exceeds the max size (:size)",
"allowedTypes" => [
"image/jpeg",
"image/png",
],
"messageType" => "Allowed file types are :types",
]
)
);PHP delivers a multiple-file input as one $_FILES entry whose name, type, tmp_name, error and size members each hold one value per file. The validator normalizes that structure into individual files and validates each one through a File validator built from the supplied options. A single (non-multiple) file entry is also accepted and validated as one file.
Set the allowEmpty option to true to pass validation when no file is uploaded:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Files;
$validator = new Validation();
$validator->add(
"photos",
new Files(
[
"allowedTypes" => [
"image/jpeg",
"image/png",
],
"allowEmpty" => true,
]
)
);Identical
Checks if a value is identical to other
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Identical;
$validator = new Validation();
$validator->add(
"terms",
new Identical(
[
"accepted" => "yes",
"message" => "Terms and conditions must be accepted",
]
)
);
$validator->add(
[
"terms",
"otherTerms",
],
new Identical(
[
"accepted" => [
"terms" => "yes",
"otherTerms" => "yes",
],
"message" => [
"terms" => "Terms and conditions must be accepted",
"otherTerms" => "Other terms must be accepted",
],
]
)
);InclusionIn
Check if a value is included in a list of values
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\InclusionIn;
$validator = new Validation();
$validator->add(
"status",
new InclusionIn(
[
"message" => "The status must be A or B",
"domain" => ["A", "B"],
]
)
);
$validator->add(
[
"status",
"type",
],
new InclusionIn(
[
"message" => [
"status" => "The status must be A or B",
"type" => "The status must be 1 or 2",
],
"domain" => [
"status" => ["A", "B"],
"type" => [1, 2],
]
]
)
);Ip
Check for IP addresses
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Ip;
$validator = new Validation();
$validator->add(
"ip_address",
new Ip(
[
"message" => ":field must contain only ip addresses",
// v6 and v4. The same if not specified
"version" => Ip::VERSION_4 | Ip::VERSION_6,
// False if not specified. Ignored for v6
"allowReserved" => false,
// False if not specified
"allowPrivate" => false,
"allowEmpty" => false,
]
)
);
$validator->add(
[
"source_address",
"destination_address",
],
new Ip(
[
"message" => [
"source_address" => "source_address must be a valid IP address",
"destination_address" => "destination_address must be a valid IP address",
],
"version" => [
"source_address" => Ip::VERSION_4 | Ip::VERSION_6,
"destination_address" => Ip::VERSION_4,
],
"allowReserved" => [
"source_address" => false,
"destination_address" => true,
],
"allowPrivate" => [
"source_address" => false,
"destination_address" => true,
],
"allowEmpty" => [
"source_address" => false,
"destination_address" => true,
],
]
)
);Numericality
Check for a valid numeric value
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Numericality;
$validator = new Validation();
$validator->add(
"price",
new Numericality(
[
"message" => ":field is not numeric",
]
)
);
$validator->add(
[
"price",
"amount",
],
new Numericality(
[
"message" => [
"price" => "price is not numeric",
"amount" => "amount is not numeric",
]
]
)
);PresenceOf
Validates whether a field is present
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\PresenceOf;
$validation = new Validation();
$validation->add(
'name',
new PresenceOf(
[
'message' => 'The name is required',
]
)
);Regex
Validates a field based on a regex pattern.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Regex;
$validation = new Validation();
$validation->add(
'telephone',
new Regex(
[
'message' => 'The telephone is required',
'pattern' => '/\+1 [0-9]+/',
]
)
);StringLength
Validates that a string has the specified maximum and minimum constraints. The validation passes if for a string length L, the minimum is less or equal to L and L is less or equal to the maximum. The boundaries are included in this validation. The formula is:
minimum <= string length <= maximumThis validator works like a container.
Both boundaries are inclusive by default. includedMinimum and includedMaximum control one boundary each. Set an option to false to exclude that boundary.
| Option | Default | false changes the test to |
|---|---|---|
includedMinimum |
true |
minimum < string length |
includedMaximum |
true |
string length < maximum |
The two options are independent. Setting one leaves the other at its default. The included option sets both boundaries at once and takes precedence over includedMinimum and includedMaximum.
Both options also accept an array keyed by field name, in the same way as min, max and the message options.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\StringLength;
$validation = new Validation();
$validation->add(
"name_last",
new StringLength(
[
"max" => 50,
"min" => 2,
"messageMaximum" => "Name too long",
"messageMinimum" => "Only initials please",
"includedMaximum" => true,
"includedMinimum" => false,
]
)
);
$validation->add(
[
"name_last",
"name_first",
],
new StringLength(
[
"max" => [
"name_last" => 50,
"name_first" => 40,
],
"min" => [
"name_last" => 2,
"name_first" => 4,
],
"messageMaximum" => [
"name_last" => "Last name too short",
"name_first" => "First name too short",
],
"messageMinimum" => [
"name_last" => "Last name too long",
"name_first" => "First name too long",
],
"includedMaximum" => [
"name_last" => false,
"name_first" => true,
],
"includedMinimum" => [
"name_last" => false,
"name_first" => true,
]
]
)
);StringLength Max
Validates that a string has the specified maximum constraints. The validation passes if for a string length L it is less or equal to the maximum. The formula is:
string length <= maximumThe maximum is inclusive by default. Set included to false to exclude it, which changes the test to string length < maximum. The option also accepts an array keyed by field name.
includedMaximum is an alias of included, so the option name used by the StringLength container also works here. If you set both, included takes precedence.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\StringLength\Max;
$validation = new Validation();
$validation->add(
"name_last",
new Max(
[
"max" => 50,
"message" => "Last name too long",
"included" => true
]
)
);
$validation->add(
[
"name_last",
"name_first",
],
new Max(
[
"max" => [
"name_last" => 50,
"name_first" => 40,
],
"message" => [
"name_last" => "Last name too long",
"name_first" => "First name too long",
],
"included" => [
"name_last" => false,
"name_first" => true,
]
]
)
);Using the alias, which rejects a last name of exactly 50 characters:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\StringLength\Max;
$validation = new Validation();
$validation->add(
"name_last",
new Max(
[
"max" => 50,
"message" => "Last name too long",
"includedMaximum" => false,
]
)
);StringLength Min
Validates that a string has the specified minimum constraints. The validation passes if for a string length L it is more or equal to the minimum. The formula is:
minimum <= string length The minimum is inclusive by default. Set included to false to exclude it, which changes the test to minimum < string length. The option also accepts an array keyed by field name.
includedMinimum is an alias of included, so the option name used by the StringLength container also works here. If you set both, included takes precedence.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\StringLength\Min;
$validation = new Validation();
$validation->add(
"name_last",
new Min(
[
"min" => 2,
"message" => "Only initials please",
"included" => true
]
)
);
$validation->add(
[
"name_last",
"name_first",
],
new Min(
[
"min" => [
"name_last" => 2,
"name_first" => 4,
],
"message" => [
"name_last" => "Last name too short",
"name_first" => "First name too short",
],
"included" => [
"name_last" => false,
"name_first" => true,
]
]
)
);Using the alias, which rejects a last name of exactly 2 characters:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\StringLength\Min;
$validation = new Validation();
$validation->add(
"name_last",
new Min(
[
"min" => 2,
"message" => "Last name too short",
"includedMinimum" => false,
]
)
);Uniqueness
Check that a field is unique in the related table
<?php
use MyApp\Models\Customers;
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Uniqueness;
$validator = new Validation();
$validator->add(
"cst_email",
new Uniqueness(
[
"model" => new Customers(),
"message" => ":field must be unique",
]
)
);Different attributes from the field:
<?php
$validator->add(
"cst_email",
new Uniqueness(
[
"model" => new Invoices(),
"attribute" => "nick",
]
)
);In the model:
<?php
$validator->add(
"cst_email",
new Uniqueness()
);Combination of fields in the model:
<?php
$validator->add(
[
"cst_name_last",
"cst_name_first",
],
new Uniqueness()
);It is possible to convert values before validation. This is useful in situations where values need to be converted for the database lookup:
<?php
$validator->add(
"cst_email",
new Uniqueness(
[
"convert" => function (array $values) {
$values["cst_email"] = trim($values["cst_email"]);
return $values;
}
]
)
);Using except for fields (SQL operation “value NOT IN (except)”)
Single field
<?php
$validator->add(
"cst_email",
new Uniqueness(
[
"except" => "[email protected]"
]
)
);Multiple fields with keys (each except will be applied to the value defined by the key)
<?php
$validator->add(
["cst_email", "cst_phone"],
new Uniqueness(
[
"except" => [
"cst_email" => "[email protected]",
"cst_phone" => "82918304-3843",
]
]
)
);Multiple fields without keys (each except will be applied to all values recursively)
<?php
$validator->add(
["cst_email", "cmp_email"],
new Uniqueness(
[
"except" => [
"[email protected]",
"[email protected]",
],
]
)
);Multiple fields with single except (except will be applied to all values recursively)
<?php
$validator->add(
["cst_email", "cmp_email"],
new Uniqueness(
[
"except" => "[email protected]",
]
)
);Url
Checks if a value has a url format
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Url;
$validator = new Validation();
$validator->add(
"url",
new Url(
[
"message" => ":field must be a URL",
]
)
);
$validator->add(
[
"url",
"homepage",
],
new Url(
[
"message" => [
"url" => "url must be a url",
"homepage" => "homepage must be a url",
]
]
)
);You can also pass the flags option in the array, defining FILTER_FLAG_PATH_REQUIRED or FILTER_FLAG_QUERY_REQUIRED if necessary.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Url;
$validation = new Validation();
$validation->add(
'url',
new Url(
[
'options' => FILTER_FLAG_PATH_REQUIRED
]
)
);
$messages = $validation->validate(
[
'url' => 'phalcon.io',
]
);
$validation->add(
'url',
new Url(
[
'options' => FILTER_FLAG_QUERY_REQUIRED
]
)
);
$messages = $validation->validate(
[
'url' => 'https://',
]
);
$validation->add(
'url',
new Url(
[
'options' => [
'flags' => [
FILTER_FLAG_PATH_REQUIRED,
FILTER_FLAG_QUERY_REQUIRED,
],
],
]
)
);
$messages = $validation->validate(
[
'url' => 'phalcon',
]
);Custom Validators
You can create your own validators by implementing the Phalcon\Filter\Validation\ValidatorInterface or Phalcon\Filter\Validation\Validator\CompositeInterface. You can also extend the Phalcon\Filter\Validation\AbstractCombinedFieldsValidator, Phalcon\Filter\Validation\AbstractValidator or Phalcon\Filter\Validation\AbstractValidatorComposite.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\AbstractValidator;
class IpValidator extends AbstractValidator
{
/**
* Adding the default template error message
*
* @param array $options
*/
public function __construct(array $options = [])
{
$this->template = 'The IP :ip_address is not valid';
parent::__construct($options);
}
/**
* Executes the validation
*
* @param Validation $validation
* @param string $field
*
* @return boolean
*/
public function validate(Validation $validation, $field)
{
$value = $validation->getValue($field);
if (!filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
$replacements = [':ip_address' => $value];
$validation->appendMessage(
$this->messageFactory($validation, $field, $replacements)
);
return false;
}
return true;
}
}It is important that validators return a valid boolean value indicating if the validation was successful or not.
Messages
Phalcon\Filter\Validation utilizes the Phalcon\Messages\Messages collection, providing 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\Messages\Message. The set of messages generated can be retrieved with the getMessages() method. Each message provides extended information such as the field that generated the message or the message type:
<?php
$messages = $validation->validate();
if (count($messages)) {
foreach ($messages as $message) {
echo 'Message: ', $message->getMessage(), "\n";
echo 'Field: ', $message->getField(), "\n";
echo 'Type: ', $message->getType(), "\n";
}
}You can pass a message parameter to change/translate the default message in each validator. You can also use the placeholder :field in the message to be replaced by the label of the field:
<?php
use Phalcon\Filter\Validation\Validator\Email;
$validation->add(
'email',
new Email(
[
'message' => 'The e-mail is not valid',
]
)
);By default, the getMessages() method returns all the messages generated during validation. You can filter messages for a specific field using the filter() method:
<?php
$messages = $validation->validate();
if (count($messages)) {
$filteredMessages = $messages->filter('name');
foreach ($filteredMessages as $message) {
echo $message;
}
}Default Messages
You can register a default failure message for a validator class. The default is used whenever that validator runs without a message of its own. This lets you translate or override the built-in message of every validator of a given type in one place, instead of passing a message option to each instance.
Register defaults with the static Phalcon\Filter\Validation::setDefaultMessages() method, keyed by validator class name. Read a registered default with Phalcon\Filter\Validation::getDefaultMessage(). Calls to setDefaultMessages() are merged, so defaults can be registered incrementally.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\PresenceOf;
Validation::setDefaultMessages(
[
PresenceOf::class => 'Default message :field is required',
]
);
$validation = new Validation();
$validation->add('name', new PresenceOf());
$messages = $validation->validate([]);
echo $messages[0]->getMessage(); // "Default message name is required"The message for a validator is resolved in the following order, from highest priority to lowest:
- A per-field template set on the validator through
setTemplates(). - A message set on the validator instance - the
messageortemplateoption, orsetTemplate(). - A default registered for the validator class through
setDefaultMessages(). - The validator’s built-in class default message.
A message set on the validator instance therefore always takes precedence over a registered default:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\PresenceOf;
Validation::setDefaultMessages(
[
PresenceOf::class => 'Default message :field is required',
]
);
$validation = new Validation();
$validation->add(
'name',
new PresenceOf(
[
'message' => 'Custom message :field is required',
]
)
);
$messages = $validation->validate([]);
echo $messages[0]->getMessage(); // "Custom message name is required"The :field placeholder is replaced with the field label, as in any validator message. Registered defaults apply to every validator whose message is produced through the message factory (getTemplate() / messageFactory()) - the built-in validators and any custom validator extending Phalcon\Filter\Validation\AbstractValidator. The File validators’ upload-specific messages (messageFileEmpty, messageIniSize and messageValid) are produced separately and are not affected; set those through their own options.
Iteration and Offsets
Messages are stored and iterated by integer position. An entry added under a string key through the array-access interface stays reachable by that offset but is not visited during iteration. A foreach loop walks the integer sequence only. Use appendMessage() when an entry must take part in iteration.
<?php
use Phalcon\Messages\Message;
use Phalcon\Messages\Messages;
$messages = new Messages();
$messages->appendMessage(new Message('Visited during iteration'));
$messages['database'] = new Message('Reachable by offset only');
foreach ($messages as $message) {
echo $message->getMessage(), "\n"; // "Visited during iteration"
}
echo $messages['database']->getMessage(); // "Reachable by offset only"Message Type Enforcement
Every entry in the collection must implement Phalcon\Messages\MessageInterface. Assigning a value of any other type through the array-access interface throws Phalcon\Messages\Exceptions\MessageNotObject with the message The message must be an instance of MessageInterface.
<?php
use Phalcon\Messages\Exceptions\MessageNotObject;
use Phalcon\Messages\Messages;
$messages = new Messages();
try {
$messages[0] = 'not a message';
} catch (MessageNotObject $ex) {
echo $ex->getMessage(); // "The message must be an instance of MessageInterface"
}The appendMessages() method accepts an array or any Traversable. Passing any other value throws Phalcon\Messages\Exceptions\MessagesNotIterable. The collection implements the Phalcon\Contracts\Messages\Messages contract. Type-hint against this contract when a method needs to accept the message collection without depending on the concrete class.
Whitelist
When validating data that will be applied to an entity (e.g. a model), you can restrict which fields are assigned to the entity by passing a $whitelist array. Only the fields listed in the whitelist will be bound; all other incoming fields are ignored. Validators still run over all configured fields regardless of the whitelist.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\PresenceOf;
$validation = new Validation();
$validation->add('name', new PresenceOf(['message' => 'Name is required']));
$validation->add('email', new PresenceOf(['message' => 'Email is required']));
$validation->add('role', new PresenceOf(['message' => 'Role is required']));
$entity = new stdClass();
// Only 'name' and 'email' are assigned to $entity even though 'role' is in the data
$messages = $validation->validate(
['name' => 'Phalcon', 'email' => '[email protected]', 'role' => 'admin'],
$entity,
['name', 'email']
);Filtering of Data
Data can be filtered prior to the validation ensuring that malicious or incorrect data is not validated.
<?php
use Phalcon\Filter\Validation;
$validation = new Validation();
$validation->add(
'name',
new PresenceOf(
[
'message' => 'The name is required',
]
)
);
$validation->add(
'email',
new PresenceOf(
[
'message' => 'The email is required',
]
)
);
$validation->setFilters('name', 'trim');
$validation->setFilters('email', 'trim');Filtering and sanitizing are performed using the filter component. You can add more filters to this component or use the built-in ones.
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 canceled:
<?php
use Phalcon\Http\Request;
use Phalcon\Messages\Message;
use Phalcon\Filter\Validation;
/**
* @property Request $request
*/
class LoginValidation extends Validation
{
public function initialize()
{
// ...
}
public function beforeValidation($data, $entity, $messages)
{
if ($this->request->getHttpHost() !== 'admin.mydomain.com') {
$messages->appendMessage(
new Message(
'Only users can log on in the admin domain'
)
);
return false;
}
return true;
}
public function afterValidation($data, $entity, $messages)
{
// ... Add additional messages or perform more validations
}
}Cancelling Validations
By default, all validators assigned to a field are tested regardless if one of them has failed or not. You can change this behavior by telling the validation component which validator may stop the validation:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Regex;
use Phalcon\Filter\Validation\Validator\PresenceOf;
$validation = new Validation();
$validation->add(
'telephone',
new PresenceOf(
[
'message' => 'The telephone is required',
'cancelOnFail' => true,
]
)
);
$validation->add(
'telephone',
new Regex(
[
'message' => 'The telephone is required',
'pattern' => '/\+44 [0-9]+/',
]
)
);
$validation->add(
'telephone',
new StringLength(
[
'messageMinimum' => 'The telephone is too short',
'min' => 2,
]
)
);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:
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator;
use Phalcon\Messages\Message;
class MyValidator extends Validator
{
public function validate(Validation $validator, $attribute)
{
// If the attribute value is `name` we must stop the chain
if ($attribute === 'name') {
$validator->setOption('cancelOnFail', true);
}
// ...
}
}Empty Values
You can pass the option allowEmpty to any of the built-in validators to ignore empty values.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Regex;
$validation = new Validation();
$validation->add(
'telephone',
new Regex(
[
'message' => 'The telephone is required',
'pattern' => '/\+1 [0-9]+/',
'allowEmpty' => true,
]
)
);The allowEmpty option accepts three forms:
true- the field is skipped when its value is empty (PHPempty()semantics)- a list of values, e.g.
[null, '']- the field is skipped when its value strictly matches one of the listed values. The comparison uses===, so'0'is not treated as empty unless listed. - a per-field map, e.g.
['address' => true, 'phone' => false]- used with validators that run against multiple fields, enabling the skip per field name
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\Regex;
$validation = new Validation();
$validation->add(
'telephone',
new Regex(
[
'message' => 'The telephone is required',
'pattern' => '/\+1 [0-9]+/',
'allowEmpty' => [null, ''],
]
)
);The allowEmpty rule is owned by the public AbstractValidator::isAllowEmpty() method, and the validation run delegates to it before each validator executes. Validators can override the method to define their own emptiness semantics - the File validators do, treating an upload with UPLOAD_ERR_NO_FILE as empty - and custom validators extending AbstractValidator inherit the behavior described above. The per-field map form is honored consistently in this pre-check as well.
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:
<?php
use Phalcon\Filter\Validation;
class CompanyValidation extends Validation
{
/**
* @var PhoneValidation
*/
protected $phoneValidation;
public function initialize()
{
$this->phoneValidation = new PhoneValidation();
}
public function afterValidation($data, $entity, $messages)
{
$phoneValidationMessages = $this->phoneValidation->validate(
$data['phone']
);
$messages->appendMessages(
$phoneValidationMessages
);
}
}Exceptions
Any exceptions thrown in the Phalcon\Filter\Validation namespace will be of type Phalcon\Filter\Validation\Exception or Phalcon\Filter\Validation\Validator\Exception. You can use this exception to selectively catch exceptions thrown only from this component.
<?php
use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Exception;
use Phalcon\Filter\Validation\Validator\InclusionIn;
try {
$validator = new Validation();
$validator->add(
"status",
new InclusionIn(
[
"message" => "The status must be A or B",
"domain" => false,
]
)
);
} catch (Exception $ex) {
echo $ex->getMessage();
}Granular Exceptions
The component raises granular subclasses of Phalcon\Filter\Validation\Exception so callers can catch a specific failure mode. Existing catch (Phalcon\Filter\Validation\Exception $e) blocks continue to work unchanged.
| Class | Parent | Thrown when |
|---|---|---|
Phalcon\Filter\Validation\Exceptions\FieldNotPrintable |
Phalcon\Filter\Validation\Exception |
A field name in the validator chain cannot be cast to string. |
Phalcon\Filter\Validation\Exceptions\FilterServiceUnavailable |
Phalcon\Filter\Validation\Exception |
A Filter service is required but the DI container has none registered. |
Phalcon\Filter\Validation\Exceptions\InvalidAllowedTypes |
Phalcon\Filter\Validation\Exception |
An allowedTypes option is not an array of strings. |
Phalcon\Filter\Validation\Exceptions\InvalidCallbackReturn |
Phalcon\Filter\Validation\Exception |
The Callback validator returns a value that is not a boolean or Validator. |
Phalcon\Filter\Validation\Exceptions\InvalidDomainOption |
Phalcon\Filter\Validation\Exception |
InclusionIn / ExclusionIn is configured without a domain array. |
Phalcon\Filter\Validation\Exceptions\InvalidFieldType |
Phalcon\Filter\Validation\Exception |
The validator is given a field reference that is not a string or array. |
Phalcon\Filter\Validation\Exceptions\InvalidFilterService |
Phalcon\Filter\Validation\Exception |
The filter service in the DI container does not implement FilterInterface. |
Phalcon\Filter\Validation\Exceptions\InvalidStrictOption |
Phalcon\Filter\Validation\Exception |
A strict option is not a boolean (single field or array form). |
Phalcon\Filter\Validation\Exceptions\InvalidValidationData |
Phalcon\Filter\Validation\Exception |
The data passed to validate() is not an array or object. |
Phalcon\Filter\Validation\Exceptions\InvalidValidator |
Phalcon\Filter\Validation\Exception |
A registered validator does not implement ValidatorInterface. |
Phalcon\Filter\Validation\Exceptions\InvalidValidatorScope |
Phalcon\Filter\Validation\Exception |
A composite validator is given a field that has no validators attached. |
Phalcon\Filter\Validation\Exceptions\MissingMbstring |
Phalcon\Filter\Validation\Exception |
A validator that relies on mbstring is used but the extension is not loaded. |
Phalcon\Filter\Validation\Exceptions\NoDataToValidate |
Phalcon\Filter\Validation\Exception |
validate() is called without setting an entity, data array, or fields. |
Phalcon\Filter\Validation\Exceptions\NoValidators |
Phalcon\Filter\Validation\Exception |
validate() is called but no validators have been added. |
Phalcon\Filter\Validation\Exceptions\NoValidatorsInComposite |
Phalcon\Filter\Validation\Exception |
A composite validator wraps an empty list of validators. |
Phalcon\Filter\Validation\Exceptions\UniquenessConversionMustBeArray |
Phalcon\Filter\Validation\Exception |
The Uniqueness validator’s convert option is not an array. |
Phalcon\Filter\Validation\Exceptions\UniquenessModelRequired |
Phalcon\Filter\Validation\Exception |
The Uniqueness validator is invoked without an associated model. |
Phalcon\Filter\Validation\Exceptions\UniquenessOnlyForPhalconModel |
Phalcon\Filter\Validation\Exception |
The Uniqueness validator is given an entity that is not a Phalcon\Mvc\Model. |
Phalcon\Filter\Validation\Exceptions\ValidationEntityNotObject |
Phalcon\Filter\Validation\Exception |
setEntity() is given a value that is not an object. |