Keep data under control

it's No secret that user data cannot be trusted. So one person came up with data validation. Well, I, for the sake of interest and benefit to, wrote my own implementation of the validator in PHP.

Kontrolio "another library validation", designed to be independent from frameworks, extensible and user-friendly containers services. Alternatives: Respect, Sirius Validation, Valitron and many others.

Ideally, it is assumed that you are using some container implementation services (e.g., PHP-DI, PHP League Container, etc.), so to start you must register Kontrolio in it:

the
use Kontrolio\Factory;

// Register
$container- > singleton('validation', function() {
return new Factory;
});

// Use
$validator = $container- > get('validation')
->make($data, $rules, $messages)
->validate();


In those situations, when to inject the container to the project is difficult, you can use the good old (actually no) singleton:

the
use Kontrolio\Factory;

$validator = Factory::getInstance()
->make($data, $rules, $messages)
->validate();


Perhaps you will notice that the validation process is similar to that of Laravel. I really liked how there it is implemented, so I decided to use a similar solution. $data, $rules and $messages — associative arrays, where $data is just an array of pairs key-value (can be multidimensional), where key is the name of the attribute that you want to providerbut. The most interesting — in validation rules and error messages.

the

validation Rules and error messages


Validation rule in Kontrolio can be represented by an object of class rules or circuit. Circuit — the easiest way to describe validation rules:

the
$rules = [
'attribute' = > function($value) {
return $value === 'foo';
}
];

$valid = $validator
->make(['attribute' => 'bar'], $rules)
->validate();

var_dump($valid); // false


Rules-circuit in the processing validator is wrapped in an object of class Kontrolio\Rules\CallbackRuleWrapperso they offer all the same options and classes rules and you can write a closure like this:

the
'attribute' = > function($value) {
return [
'valid' => $value === 'foo'
'name' => 'value_is_foo_rule',
'empty_allowed' => true,
'skip' => false,
'violations' => []
];
}


Circuit convenient for simple rules that are not designed to be reusable. But if you plan to use a rule in different places, it is better to write a separate rule class and then create object:

the
use Kontrolio\Rules\AbstractRule;

class FooRule extends AbstractRule
{
public function isValid($input = null)
{
return $input === 'foo';
}
}

$rules = ['attribute' => new FooRule];

note: Kontrolio comes with a set of rules out of the box.

the

Options validation rules


In the recording rules in the form of a circuit you notice several options, which supports any rule. A little bit about each option below.

valid. It directly condition. The equivalent for class rules — the method isValid that takes one argument, you want to validate the attribute value. To make it clearer, I'll show you how you can set a validation rule for a certain attribute:

the
// The easiest method where the return value is the rule's condition.
'attribute' = > function($value) {
return $value === 'foo';
}

// If you want to use options, you need to return an array of circuit
// in the array must be specified 'valid',
// which defines a rule condition.
'attribute' = > function($value) {
return [
'valid' => $value === 'foo'
// other options...
];
}

// Using a separate class you inherit their rule from a base class
// define a method isValid, which returns the condition.
use Kontrolio\Rules\AbstractRule;

class FooRule extends AbstractRule
{
public function isValid($input = null)
{
return $input === 'foo';
}
}


This is the simplest way to set a rule to an attribute.

name. Is the name or identifier of the rule. Mainly used for the formation of the messages about validation errors:

the
$data = ['attribute' => 'invalid'];
$rules = ['attribute' => new Email];
$messages = ['attribute.email' => 'The attribute must be an email'];

$validator = $container- > get('validation')
->make($data, $rules, $messages);
if ($validator- > validate()) {
//
} else {
$messages = $validator- > getErrors();
}


If you create a rule based on the class, you do not need to specify the name/identifier of a rule manually, because nasledujuci from Kontrolio\Rules\AbstractRule you get this functionality by default in the method getName. However, you can change the name of the rule simply by overriding this method.

empty_allowed. This option is useful in situations where you need to apply the validation rule only if attribute value is present. With closures, it looks like this:

the
'attribute' = > function($value) {
return [
'valid' => $value === 'foo'
'empty_allowed' => true
];
}


Using the class-rule with this option, you can apply it to the attribute in two ways:

the
// a Named constructor
'attribute' => FooRule::allowingEmptyValue()

// Or the appropriate non-static method
'attribute' => (new FooRule)->allowEmptyValue()


In this case, the validator will respond positively if the attribute value is the value of 'foo' or it will be empty.

skip. This option is similar to the previous one. It allows you to specify a condition which will command the validator to skip validation of the attribute as if the rule never existed at all.

the
'confirmed' = > function($value) {
return [
'valid' => (bool)$value === true
'skip' => is_admin()
];
}


The equivalent rule for class- method canSkipValidation, and it works exactly the same:

the
class FooRule
{
public function isValid($input = null)
{
return (bool)$value === true;
}
public function canSkipValidation()
{
return is_admin();
}
}
$rules = ['confirmed' => new FooRule];


violations. I kindly borrowed this term from Symfony. Using "violations", the user can obtain a more accurate error message (which you must define), although the validator, the same as before, just return false

the
$data = 'nonsense';
$rules = ['attribute' => new Email(true, true)];
$messages = [
'attribute' => [
'email' => "Something's wrong with your email.",
'email.mx' => 'MX record is wrong.',
'email.host' => 'Unknown email host.'
]
];


You can ask as many "violations" as you wish, and each of them can then be used for a more detailed description of validation errors: from the General to the detailed message. View, as an example, the class Kontrolio\Rules\Core\Email.

the

a few rules Apply to attributes


Before that, all examples have shown the description of one rule for one attribute. But, of course, you can add any number of rules to arbitrarily many attributes :) moreover, you can combine the use of closures and classes:

the
$rules = [
'some' = > function($value) {
return $value === 'foo';
},
'another' => [
function($value) {
return $value !== 'foo';
},
new FooBarRule,
// and so on...
]
];


All cool, of course, but there is another interesting way of writing of a set of rules — as a string:

the
'attribute' => 'not_empty|length:5,15'


Here each rule is separated by a vertical bar. This idea I borrowed from Laravel, but the difference is that any such string is "unpacked" in the usual array of rules that you have seen more than once in the article. So the above line in this case is just sugar for this array:

the
'attribute' => [
new NotEmpty,
new Length(5, 15)
]


Please note that everything you write after the colon, gets straight to the constructor arguments of the rule class:

the
'length:5, 15' -> new Length(5, 15)


So you've got to be careful.

the

Skip the validation of the attribute as a whole


Pass separate rules or permission of null values would not be enough, so Kontrolio contains a special rule, called by analogy with Laravel 'sometimes' and is represented by a class Kontrolio\Rules\Core\Sometimes. When you add this rule to the attribute, it tells the validator to skip checking attribute, if it is not present in the data array passed to the validator, or if its value is empty. This rule must always be put first in the list.

the
$data = [];
$rules = ['attribute' => 'sometimes|length:5,15'];

$valid = $container
->get('validator')
->make($data, $rules)
->validate();

var_dump($valid); // true


By analogy with the previous examples this can be written as:

the
$data = [];
$rules = [
'attribute' => [
new Sometimes,
new Length(5, 15)
]
];

$valid = $container
->get('validator')
->make($data, $rules)
->validate();

var_dump($valid); // true


the

Conclusion validation errors


Validation errors are stored in an associative array where the keys are attribute names and values are arrays themselves with messages:

the
$data = ['attribute' => "];
$rules = [
'attribute' => [
new NotBlank,
new Length(5, 15)
]
];

$messages = [
'attribute.not_blank' => 'The attr. is required.',
'attribute.length.min' => 'It must contain at lest 5 chars'
];

$valid = $container
->get('validator')
->make($data, $rules)
->validate();

$errors = $validator- > getErrors();


Dump the error will look like the following:

the
[
'attribute' => [
0 => 'The attr. is required.',
1 => 'It must contain at lest 5 chars'
]
]


So if you want to just display all errors in a row, use the method validator getErrorsList. It will return a flat array with the message:

the
$errors = $validator->getErrorsList();

<ul class="errors">
<?php foreach($errors as $error): ?>
<li class="errors__error"><?= $error; ?></li>
<?php endforeach; ?>
</ul>


For more complex error output you can use the method getErrors. He returns messages grouped by the names of the attributes:

the
<ul class="errors">
<?php foreach ($errors as $attribute = > $messages):
<li class="errors__attribute">
<b><?= $attribute; ?></b>
<ul>
<?php foreach ($messages as $message): ?>
<li><?= $message; ?></li>
<?php endforeach; ?>
</ul>
</li>
<?php endforeach; ?>
</ul>


the

in conclusion of this story


Here is how you can use Kontrolio, another library of data validation in PHP. During the writing of this article, I thought that a simple retelling of the documentation will not be enough. So I plan to write an article which tries to compare your library with other solutions.

Thank you for reading!
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Briefly on how to make your Qt geoservice plugin

Database replication PostgreSQL-based SymmetricDS

Yandex.Widget + adjustIFrameHeight + MooTools