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

Use the extend static method in Validate to register global rules. Let's use this method in the validate to register a custom validation rule.

Validate::extend('chs', function ($attribute, $value, $parameters, $validator) {
    return is_scalar($value) && 1 === preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', (string)$value);
}, 'The value of :attribute can only have Chinese');

The custom validation closure 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.

In addition to using closures, you can also pass in classes and methods to the extend method:

Validate::extend("check_admin","permissionValidate@checkAdmin");

Note

If your method is a static method, you can also pass in an array of [full class name, method name], if the method name is not passed, the default method name is validate.

replacer

If you need to define an error message, you can fill in the third parameter of extend, or define it via the replacer method

The replacer method accepts two parameters ruleName and a closure parameter, and the closure accepts four parameters: error message $message, the name of the attribute being validated $attribute, the name of the current rule $rule, an array of parameters to be passed into the validation rule $parameters

Validate::replacer("check_admin",function($message,$attribute,$rule,$parameters){
  return "Customized error messages"
});

In addition to using closures, passing in classes and methods to the replacer method is also supported

Validate::replacer("check_admin","permissionValidate@checkAdminMessage");

Note

Passing in classes and methods requires specifying the method as a public type, if it's a class, you need to pass in the full namespace, does not support array passing, such as the method name is not passed, the default method name replace.

Custom messages that can override default rules. To define error messages for custom methods, be sure to define the error rule extend first, then the error message replacer.

Use in the same way as with rule objects

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

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:

Validate::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 we want to define a custom extension to validate the array, we will find that neither extend nor extendImplicit will resolve *, so we need to use the extendDependent method in Validate:

Validate::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 = new Validate();
$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'
    ];
}



 



 


Defining the Dependent Validator

Use the extendDependentRule method in the Validate class to have the same effect as extendDependent, but only with this validator

class LoginValidate extends Validate
{
    public function __construct()
    {
        $this->extendDependentRule('contains', function ($attribute, $value, $parameters, $validator) {
            return str_contains($value, Arr::get($validator->getData(), $parameters[0]));
        });
    }
}

Defining the Implicit Validator

Use the extendImplicitRule method in the Validate class to have the same effect as extendImplicit, but only with this validator

class LoginValidate extends Validate
{
    public function __construct()
    {
        $this->extendImplicitRule('isEmpty', function ($attribute, $value, $parameters, $validator) {
            return empty($value);
        });
    }
}

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;
    }
}