The package provides data validation capabilities.
- Could be used with any object.
- Skip further validation if an error occurred for the same field.
- Skip validation of empty value.
- Error message translations.
- Conditional validation.
- Could pass context to validation rule.
- Common rules bundled.
Library could be used in two ways: validating a single value and validating a set of data.
use Yiisoft\Validator\Rules;
use Yiisoft\Validator\Rule\Required;
use Yiisoft\Validator\Rule\Number;
use Yiisoft\Validator\Result;
$rules = new Rules([
new Required(),
(new Number())->min(10),
static function ($value): Result {
$result = new Result();
if ($value !== 42) {
$result->addError('Value should be 42!');
}
return $result;
}
]);
$result = $rules->validate(41);
if ($result->isValid() === false) {
foreach ($result->getErrors() as $error) {
// ...
}
}use Yiisoft\Validator\DataSetInterface;
use Yiisoft\Validator\Validator;
use Yiisoft\Validator\Rule\Number;
use Yiisoft\Validator\Result;
class MoneyTransfer implements DataSetInterface
{
private $amount;
public function __construct($amount) {
$this->amount = $amount;
}
public function getAttributeValue(string $key){
if (!isset($this->$key)) {
throw new \InvalidArgumentException("There is no \"$key\" in MoneyTransfer.");
}
return $this->$key;
}
}
$moneyTransfer = new MoneyTransfer(142);
$validator = new Validator([
'amount' => [
(new Number())->integer()->max(100),
static function ($value): Result {
$result = new Result();
if ($value === 13) {
$result->addError('Value should not be 13!');
}
return $result;
}
],
]);
$results = $validator->validate($moneyTransfer);
foreach ($results as $attribute => $result) {
if ($result->isValid() === false) {
foreach ($result->getErrors() as $error) {
// ...
}
}
}By default, if an error occurred during validation of an attribute, further rules for this attribute are skipped.
To change this behavior use skipOnError(false) when configuring rules:
(new Number())->integer()->max(100)->skipOnError(false)By default, empty values are validated. That is undesirable if you need to allow not specifying a field.
To change this behavior use skipOnEmpty(true):
(new Number())->integer()->max(100)->skipOnEmpty(true)In some cases there is a need to apply rule conditionally. It could be performed by using when():
(new Number())->integer()->min(100)->when(static function ($value, DataSetInterface $dataSet) {
return $dataSet->getAttributeValue('country') === Country::USA;
});If callable returns true rule is applied, when the value returned is false, rule is skipped.
To create your own validation rule you should extend Rule class:
namespace MyVendor\Rules;
use Yiisoft\Validator\DataSetInterface;
use Yiisoft\Validator\Result;
use Yiisoft\Validator\Rule;
class Pi extends Rule
{
protected function validateValue($value, DataSetInterface $dataSet = null): Result
{
$result = new Result();
if ($value != M_PI) {
$result->addError('Value is not PI');
}
return $result;
}
}Note that validateValue() second argument is an instance of DataSetInterface so you can use it if you need
whole data set context. For example, implementation might be the following if you need to validate "company"
property only if "hasCompany" is true:
namespace MyVendor\Rules;
use Yiisoft\Validator\DataSetInterface;
use Yiisoft\Validator\Result;
use Yiisoft\Validator\Rule;
class CompanyName extends Rule
{
protected function validateValue($value, DataSetInterface $dataSet = null): Result
{
$result = new Result();
$hasCompany = $dataSet !== null && $dataSet->getAttributeValue('hasCompany') === true;
if ($hasCompany && $this->isCompanyNameValid($value) === false) {
$result->addError('Company name is not valid');
}
return $result;
}
private function isCompanyNameValid(string $value): bool
{
// check company name
}
}To reuse multiple validation rules it is advised to group rules into validation sets:
use Yiisoft\Validator\Rule\HasLength;
use Yiisoft\Validator\Rule\MatchRegularExpression;
class UsernameRules
{
public static function get(): array
{
return [
(new HasLength())->min(2)->max(20),
new MatchRegularExpression('~[a-z_\-]~i')
];
}
}Then it could be used like the following:
use Yiisoft\Validator\Validator;
use Yiisoft\Validator\Rule\Email;
$validator = new Validator([
'username' => UsernameRules::get(),
'email' => [new Email()]
]);
$results = $validator->validate($user);
foreach ($results as $attribute => $result) {
if ($result->isValid() === false) {
foreach ($result->getErrors() as $error) {
// ...
}
}
}

