
Introducing Rock Validate

bring to your attention a library for data validation with customization, internationalization and other "goodies." Using the well-known Respect / Validation tool with many crutches driven along the way, at some point I said to myself: Enough!
The tasks were set:
- keep elegant syntax (chaining principle for rules);
- implement an “easy” and flexible alternative;
- add internationalization;
- provide the ability to add your own rules;
- to prepare the foundation for the sanitizer - to provide a uniform implementation style for both libraries.
Everything is outrageously simple
$v = Validate::length(10, 20, true)->regex('/^[a-z]+$/i');
$v->validate('O’Reilly'); // output: false
$v->getErrors();
/*
output:
[
'length' => 'value must have a length between 10 and 20',
'regex' => 'value contains invalid characters'
]
*/
$v->getFirstError();
// output: value must have a length between 10 and 20
The list of errors is presented in the form of an associative array.
- getErrors () - output of the entire error stack;
- getFirstError () - returns the first error;
- getLastError () - returns the last error.
rules
The set of rules is wide enough, because with minor changes I pumped a “competitor” out of the camp.
There are groups of rules:
- general purpose
- string
- numeric
- date and time
- file system
- network
- and etc.
Full list of rules.
Any additional whim is implemented by customization, or by pull request.
Attribute Validation
To validate an array / object by attributes, the attributes () method is used.
$input = [
'username' => 'O’Reilly',
'email' => 'o-reilly@site'
];
$attributes = [
'username' => Validate::required()
->length(2, 20, true)
->regex('/^[a-z]+$/i'),
'email' => Validate::required()->email()
];
$v = Valiadte::attributes($attributes);
$v->validate($input); // output: false
$v->getErrors();
/*
output:
[
'username' => [
'regex' => 'value contains invalid characters',
],
'email' => [
'email' => 'email must be valid',
],
]
*/
Using one set of rules for each attribute:
Validate::attributes(Validate::required()->string())->validate($input);
Denial of the rules
Invert the behavior of rules using the notOf () method. In this case, the “negative” Locale :: MODE_NEGATIVE message template is used.
$v = Validate::notOf(Validate::required());
$v->validate(''); // output: true
This method is applicable both for the rules of the internal attribute ['email' => Validate :: notOf (Validate :: email ())], and for all attributes as a whole. Example:
$input = [
'email' => 'tom@site',
'username' => ''
];
$attributes = Validate::attributes([
'email' => Validate::email(),
'username' => Validate::required()
]);
$v = Validate::notOf($attributes);
$v->validate($input); // output: true
OneOf () rule
If at least one rule is incorrect, then the check stops. Example:
$input = 7;
$v = Validate::oneOf(Validate::string()->email());
$v->validate($input); // output: false
$v->getErrors();
/*
output:
[
'string' => 'value must be string'
]
*/
For attribute validation, the scenario is similar to negation:
$input = [
'email' => 'tom@site',
'username' => ''
];
$attributes = Validate::attributes([
'email' => Validate::email(),
'username' => Validate::required()
]);
$v = Validate::oneOf($attributes);
$v->validate($input); // output: false
$v->getErrors();
/*
output:
[
'email' => [
'email' => 'email must be valid',
]
]
*/
When () rule
It is necessary to implement the condition (ternary conditional operation). The general syntax of the method is as follows:
v::when(v $if, v $then, v $else = null)
Example:
$v = Validate::when(Validate::equals('Tom'), Validate::numeric());
$v->validate('Tom'); // output false
$v->getErrors();
/*
output:
[
'numeric' => 'value must be numeric',
]
*/
Replacing Placeholders, Messages, and Templates
Many error messages contain placeholders (for example, {{name}}), which are replaced with default values. Replace with your own is not difficult:
$v = Validate::length(10, 20)
->regex('/^[a-z]+$/i')
->placeholders(['name' => 'username']);
$v->validate('O’Reilly'); // output: false
$v->getErrors();
/*
output:
[
'length' => 'username must have a length between 10 and 20',
'regex' => 'username contains invalid characters',
]
*/
Similarly, the entire message is subject to such a "hot" replacement:
$v = Validate::length(10, 20)
->regex('/^[a-z]+$/i')
->messages(['regex' => 'Хьюстон, у нас проблемы!']);
$v->validate('O’Reilly'); // output: false
$v->getErrors();
/*
output:
[
'length' => 'username must have a length between 10 and 20',
'regex' => 'Хьюстон, у нас проблемы!'
]
*/
Depending on the specified arguments in the rule method, the message template is selected automatically, but no one bothers to substitute any other that is described in the current locale. Example:
$v = Validate::length(10, 20)->templates(['length' => Length::GREATER]);
$v->validate('O’Reilly'); // output: false
$v->getErrors();
/*
output:
[
'length' => 'value must have a length lower than 20',
]
*/
Internationalization
Currently there are two message dictionaries: Russian and English. By default, error messages will be displayed in English. You can set the locale through the locale () method:
$v = Validate::locale('ru')
->length(10, 20)
->regex('/^[a-z]+$/i');
$v->validate('O’Reilly'); // output: false
$v->getErrors();
/*
output:
[
'length' => 'значение должно иметь длину в диапазоне от 10 до 20',
'regex' => 'значение содержит неверные символы',
]
*/
Customization
You can create your own rules in two steps.
Step 1. Create a class with a rule:
use rock\validate\rules\Rule
class CSRF extends Rule
{
public function __construct($compareTo, $compareIdentical = false, $config = [])
{
$this->parentConstruct($config);
$this->params['compareTo'] = $compareTo;
$this->params['compareIdentical'] = $compareIdentical;
}
public function validate($input)
{
if ($this->params['compareIdentical']) {
return $input === $this->params['compareTo'];
}
return $input == $this->params['compareTo'];
}
}
Step # 2. Create a class with messages:
use rock\validate\locale\Locale;
class CSRF extends Locale
{
const REQUIRED = 1;
public function defaultTemplates()
{
return [
self::MODE_DEFAULT => [
self::STANDARD => '{{name}} must be valid',
self::REQUIRED => '{{name}} must not be empty'
],
self::MODE_NEGATIVE => [
self::STANDARD => '{{name}} must be invalid',
self::REQUIRED => '{{name}} must be empty'
]
];
}
public function defaultPlaceholders($compareTo)
{
if (empty($compareTo)) {
$this->defaultTemplate = self::REQUIRED;
}
return [
'name' => 'CSRF-token'
];
}
}
As previously noted, when using the notOf () rule, the message template Locale :: MODE_NEGATIVE will be substituted. The subpattern allows you to diversify messages depending on the given arguments in the rule method. By default, Locale :: STANDARD.
Profit:
$config = [
'rules' => [
'csrf' => [
'class' => \namespace\to\CSRF::className(),
'locales' => [
'en' => \namespace\to\en\CSRF::className(),
]
],
]
];
$sessionToken = 'foo';
$requestToken = 'bar';
$v = new Validate($config);
$v->csrf($sessionToken)->validate($requestToken); // output: false
$v->getErrors();
/*
output:
[
'csrf' => 'CSRF-token must be valid',
]
*/
Thus, it is possible to implement the substitution of existing rules .
Additional features
There is a scenario where you need to skip the "empty" values. For example, for form fields that are optional. For these purposes, there is a skipEmpty property - a reaction is set for each rule to “empty” values. For some rules, this property is set to false (do not skip), namely: Required, Arr, Bool, String, Int, Float, Numeric, Object, NullValue, Closure, all ctype rules. Example:
$v = Validate::email();
$v->validate(''); // output: true
This behavior can be undone:
$v->skipEmpty(false)->validate(''); // output: false
By default, null values are $ value === null || $ value === [] || $ value === ''. For each of the rules, it is possible to set its isEmpty handler:
$config = [
'rules' => [
'custom' => [
'class' => \namespace\to\CustomRule::className(),
'locales' => [
'en' => \namespace\to\en\Custom::className(),
],
'isEmpty' => function($input){
return $input === '';
}
],
]
];
$v = new Validate($config);
Installation
composer require romeoz/rock-validate:*
A look?
There is a small demo that can be launched using Docker :
docker run --name demo -d -p 8080:80 romeoz/docker-rock-validate
The demo will be available at: http: // localhost: 8080 /