Pre-processing

Before you can use a custom validation rule, you must define the namespace prefix for the custom validation rule

ValidateConfig::instance()->setRulesPath('W7\\App\\Model\\Validate\\Rules\\');

It is recommended to define the validate-related settings in Provider.

Priority

The validator's Built-in Rules is greater than that of the extended rules, so care needs to be taken that the rule names are not consistent.

Extending global rules

Global rules refer to rules that can be used in all validators

Using rule objects

There are many useful validation rules within the validator; custom rules are also supported。 One way to register a custom validation rule is to create a new rule and inherit from W7\Validate\Support\Rule\BaseRule. The new rule is stored in the directory you have set up.

Once the rule is created, we can define its behavior. The passes method takes the attribute value and name and returns true or false depending on whether the attribute value matches the rule. The message attribute is the validation error message used in case of validation failure, which can be overridden by the message defined in the validator.

ImplicitRule

If you would like a rule object to run when an attribute is empty, you should implement the Itwmw\Validation\Support\Interfaces\ImplicitRule interface. This interface serves as a "marker interface" for the validator; therefore, it does not contain any methods you need to implement.

namespace W7\App\Model\Validate\Rules;

class Chs extends BaseRule
{
    /**
     * Default error message
     * @var string
     */
    protected $message = 'The value of :attribute can only have Chinese';
    
    /**
     * Determine if the validation rules pass。
     *
     * @param mixed $attribute
     * @param mixed $value
     * @return bool
     */
    public function passes($attribute, $value): bool
    {
        return is_scalar($value) && 1 === preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', (string)$value);
    }
}

Once the rule object has been defined, you can pass an instance of the rule object to the validator by passing it along with other validation rules:

protected $rule = [
    'title' => 'required|chs',
];

The first letter of the custom extension rule can be lowercase, it is also recommended to use lowercase.

Rule object error message formatting support:Formatting error messages

The rules also support standalone calls to use

Chs::make()->check("name");

Validation returns true, failure returns false

extend: Extend Custom validation rules

In validators, you can use the extend method to register a rule. For example:

class UserValidator extends Validate
{
}

$v = UserValidator::make();

$v->extend("chs",function ($attribute, $value, $parameters, $validator) {
    return is_scalar($value) && 1 === preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', (string)$value);
}, ':attribute must only contain Chinese characters');

The custom validation closure takes four parameters: the name of the attribute to be validated $attribute, the value of the attribute $value, the array of parameters passed to the validation rule $parameters, and the Validator instance. In addition to using a closure, you can also pass a class and method to the extend method:

class Rules
{
    public function chs($attribute, $value, $parameters, $validator) {
        return is_scalar($value) && 1 === preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', (string)$value);
    }
}

$v->extend("chs","Rules@chs", ':attribute must only contain Chinese characters');

If your method is a static method, you can also pass it in array form [full class name, method name]:

class Rules
{
    public static function chs($attribute, $value, $parameters, $validator)
    {
        return is_scalar($value) && 1 === preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', (string)$value);
    }
}

$v->extend('chs', [Rules::class, 'chs'], ':attribute must only contain Chinese characters');

Note

When passing a class and method, the method must be of public visibility, and the full namespace of the class must be provided. If no method name is passed, the default method name is validate.

Replacer: Error Message Customizer

If you need to define error messages, you can pass them in as the third argument of extend, or define them using the extendReplacer method of the validator. The extendReplacer method takes two parameters: ruleName and a closure. The closure accepts four parameters: the error message $message, the name of the validated attribute $attribute, the current rule name $rule, and the parameter array passed to the validation rule $parameters.

$v->extendReplacer('chs', function ($message, $attribute, $rule, $parameters) {
    return 'Custom error message';
});

In addition to closures, you can also pass classes and methods to the extendReplacer method:

$v->extendReplacer('chs', "Rules@chsMessage");
// For static methods
$v->extendReplacer('chs', [Rules::class, 'chsMessage']);

Note

When passing a class and method to extendReplacer, the method must be public and the class must be the fully qualified namespace. If no method name is passed, the default method name is replace, which can override the custom message of the default rule.

Usage is the same as using the rule object:

protected $rule = [
    'title' => 'required|chs',
];

extendImplicit

By default, when an attribute being validated is not present or contains an empty string, normal validation rules, including custom extensions, are not run. For example, the unique rule will not be run against an empty string:

$rules = ['name' => 'unique:users,name'];

$input = ['name' => ''];

// Validate passed

For a rule to run even when an attribute is empty, the rule must imply that the attribute is required. To create such an "implicit" extension, use the extendImplicit() method in Validate:

$v->extendImplicit('foo', function ($attribute, $value, $parameters, $validator) {
    return $value == 'foo';
});

An "implicit" extension only implies that the attribute is required. Whether it actually invalidates a missing or empty attribute is up to you.

extendDependent

If you want to define a custom extension to validate an array, you may find that extend and extendImplicit do not parse *. In this case, you can use the extendDependent method in Validate:

$v = new Validate();

$v->extendDependent('contains', function ($attribute, $value, $parameters, $validator) {
    // The $parameters passed from the validator below is ['*.provider'], when we imply that this
    // custom rule is dependent the validator tends to replace the asterisks with the current
    // indices as per the original attribute we're validating, so *.provider will be replaced
    // with 0.provider, now we can use array_get() to get the value of the other field.
    
    // So this custom rule validates that the attribute value contains the value of the other given attribute
    return str_contains($value,Arr::get($validator->getData(),$parameters[0]));
});

$v->setRules([
    '*.email' => 'contains:*.provider'
])->check([
    [
        'email' => '995645888@qq.com', 'provider' => 'qq.com'
    ]
]);

Custom rules within the validator

Using class methods

Custom rules also support the direct use of methods under the current validator class, the rule is rule + rule name, e.g. ruleCheckLogin

Note

The checkLogin here and other methods registered under the current validator must not duplicate the rule name, otherwise it will overwrite

The Custom Rule method takes four parameters: The name of the attribute to be validated $attribute, the value of the attribute $value, an array of parameters to be passed into the validation rule $parameters, and a Validator instance.

class LoginValidate extends Validate
{
    protected $rule = [
        'user' => 'required|alphaNum|checkLogin'
    ];

    protected $message = [
        'user.checkLogin' => 'Login failure'
    ];

    public function ruleCheckLogin($attribute, $value, $parameters, $validator): bool
    {
        return 'admin' === $value;
    }
}

You can also set error messages for class method rules with the $ruleMessage parameter

class Test extends Validate
{
    protected $ruleMessage = [
        'chs' => 'The value of :attribute can only have Chinese'
    ];

    protected function ruleChs($attribute, $value, $parameters, $validator): bool
    {
        return is_scalar($value) && 1 === preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', (string)$value);
    }
}

Regular Expression Rule

Supports direct use of regular validation, e.g:

'id' => 'regex:/^\d+$/',

If your regular expression contains the | symbol, it must be defined in an array.

'id' => ['regex:/^\d+$/']

You can also implement a predefined regular expression and call it directly, for example, by defining the regex property in the validator class and then using regex: + regular name in the rule

class Test extends \W7\Validate\Validate
{
    protected $regex = [
        'number' => '/^\d+$/'
    ];

    protected $rule = [
        'id' => 'regex:number'
    ];
}



 



 


Custom rule incoming parameters

Custom rules, like other rules, also support passing in parameters, similar to max:100, in:0,1,2, which will be passed into the constructor of the custom rule class in order. as follows:

class Length extends BaseRule
{
    protected $message = 'The length of :attribute does not meet the requirement';

    protected $size;

    public function __construct(int $size)
    {
        $this->size = $size;
    }

    public function passes($attribute, $value): bool
    {
        return strlen($value) === $this->size;
    }
}







 










Or Rule

When you need to pass validation if any of multiple rules pass, you can use the or rule. For example:

class User extends Validate {
    protected $rule = [
        'username' => 'required|or:email,mobile'
    ];
}


 


This means that if username satisfies either the email or mobile rule, it will pass validation:

User::make()->check([
    'username' => '995645888@qq.com'
]);

User::make()->check([
    'username' => '18899996666'
]);

 



 

Both 995645888@qq.com and 18899996666 satisfy the rule.

Using Rule Groups

The or rule also supports using rule groups. For example:

class User extends Validate {
    protected $group = [
        'username' => 'email|mobile'
    ];

    protected $rule = [
        'username' => 'required|or:username'
    ];
}

You can also use multiple rule groups, for example:

class User extends Validate
{
    protected $group = [
        'username'    => 'email|mobile',
        'username_nl' => 'alpha|chs'
    ];

    protected $rule = [
        'username' => 'required|or:username,username_nl'
    ];
}

In this definition, username will pass validation as long as it satisfies any rule in either the username or username_nl rule groups.

You can also use rule groups and individual rules together, for example:

class User extends Validate
{
    protected $group = [
        'username_nl'       => 'alpha|chs',
        'username_specific' => 'in:admin123,root520'
    ];

    protected $rule = [
        'username' => 'required|or:username_specific,username_nl,email,mobile'
    ];
}

In this example, the username will pass the validation if it satisfies any rule in either the username_specific or username_nl rule group, or if it satisfies any rule in the email and mobile rule groups.

User::make()->check([
    'username' => '995645888@qq.com'
]);

User::make()->check([
    'username' => '18899996666'
]);

User::make()->check([
    'username' => '虞灪'
]);

User::make()->check([
    'username' => 'yapyuyu'
]);

User::make()->check([
    'username' => 'admin123'
]);

User::make()->check([
    'username' => 'root520'
]);

All of the above are valid/acceptable for validation.