Pre-processing
Before you can use a custom validation rule, you must define the namespace prefix for the custom validation rule
ValidateConfig::instance()->setRulesPath('Itwmw\\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 Itwmw\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 Itwmw\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',
];
If you haven't configured the custom rule class path, you can also pass the full rule class namespace:
use Itwmw\App\Model\Validate\Rules\Chs;
protected $rule = [
'title' => [
'required', Chs::class
],
];
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): true|string
{
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);
}
}
Also supports inline error messages in $message.
class Test extends Validate
{
protected $message = [
'chs.scalar' => 'The value of :attribute must be a constant',
'chs' => 'The value of :attribute can only contain Chinese characters'
];
protected function ruleChs($attribute, $value, $parameters, $validator): bool
{
if (!is_scalar($value)){
return 'chs.scalar';
}
if (!1 === preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', (string) $value)){
return 'chs';
}
return true;
}
}
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 \Itwmw\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.