Validate 
Testing Is Documentation
构造器函数原型
public function __construct(array $data = [], array $rules = [], array $names = [], array $messages = []);- $data 验证的数据
- $rules 验证规则
- $names 校验名字隐射
- $messages 校验失败消息
可以通过构造器传递参数,也可以通过 name,message 等方法传入。
Uses
<?php
use Leevel\Di\Container;
use Leevel\Kernel\Utils\Api;
use Leevel\Validate\IValidator;
use Leevel\Validate\Validate;
use Leevel\Validate\Validator;
use Leevel\Validate\ValidatorException;
use PHPUnit\Framework\Attributes\DataProvider;验证器基本使用方法 
可以通过 success 判断是否通过验证,error 返回错误消息。
public function testBaseUse(): void
{
    $validate = new Validator(
        [
            'name' => '小牛哥',
        ],
        [
            'name' => 'required|max_length:10',
        ],
        [
            'name' => '用户名',
        ]
    );
    $this->assertInstanceof(IValidator::class, $validate);
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ],
                [
                    "max_length",
                    [
                        "10"
                    ]
                ]
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame([], $validate->error());
    self::assertSame([], $validate->getMessage());
    self::assertSame(['name' => '小牛哥'], $validate->getData());
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
}验证器规则支持数组写法 
可以通过 success 判断是否通过验证,error 返回错误消息。
public function testRuleIsArray(): void
{
    $validate = new Validator(
        [
            'name' => '小牛哥',
        ],
        [
            'name' => ['required', 'max_length:10'],
        ],
        [
            'name' => '用户名',
        ]
    );
    $this->assertInstanceof(IValidator::class, $validate);
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ],
                [
                    "max_length",
                    [
                        "10"
                    ]
                ]
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame([], $validate->error());
    self::assertSame([], $validate->getMessage());
    self::assertSame(['name' => '小牛哥'], $validate->getData());
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
}验证器规则支持数组写法:每一项都是一个数组(第一个是规则,第一个是参数非数组兼容为数组) 
可以通过 success 判断是否通过验证,error 返回错误消息。
public function testRuleIsArray2(): void
{
    $validate = new Validator(
        [
            'name' => '小牛哥',
        ],
        [
            'name' => ['required', ['max_length', 10]],
        ],
        [
            'name' => '用户名',
        ]
    );
    $this->assertInstanceof(IValidator::class, $validate);
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ],
                [
                    "max_length",
                    [
                        10
                    ]
                ]
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame([], $validate->error());
    self::assertSame([], $validate->getMessage());
    self::assertSame(['name' => '小牛哥'], $validate->getData());
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
}验证器规则支持数组写法:每一项都是一个数组(第一个是规则,第一个是参数数组用法) 
可以通过 success 判断是否通过验证,error 返回错误消息。
public function testRuleIsArray3(): void
{
    $validate = new Validator(
        [
            'name' => '小牛哥',
        ],
        [
            'name' => ['required', ['max_length', [10]]],
        ],
        [
            'name' => '用户名',
        ]
    );
    $this->assertInstanceof(IValidator::class, $validate);
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ],
                [
                    "max_length",
                    [
                        10
                    ]
                ]
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame([], $validate->error());
    self::assertSame([], $validate->getMessage());
    self::assertSame(['name' => '小牛哥'], $validate->getData());
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
}验证器规则支持数组每一项字符串支持分隔:可以用于实际业务中合并验证规则的需求 
可以通过 success 判断是否通过验证,error 返回错误消息。
public function testRuleIsArrayStringMixed(): void
{
    $validate = new Validator(
        [
            'name' => '小牛哥',
        ],
        [
            'name' => ['required|chinese|min_length:1', ['max_length', [10]]],
        ],
        [
            'name' => '用户名',
        ]
    );
    $this->assertInstanceof(IValidator::class, $validate);
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ],
                [
                    "chinese",
                    []
                ],
                [
                    "min_length",
                    [
                        "1"
                    ]
                ],
                [
                    "max_length",
                    [
                        10
                    ]
                ]
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame([], $validate->error());
    self::assertSame([], $validate->getMessage());
    self::assertSame(['name' => '小牛哥'], $validate->getData());
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
}make 创建验证器 
public function testMake(): void
{
    $validate = Validator::make(
        [
            'name' => '小牛哥',
        ],
        [
            'name' => 'required|max_length:10',
        ],
        [
            'name' => '用户名',
        ]
    );
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ],
                [
                    "max_length",
                    [
                        "10"
                    ]
                ]
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame([], $validate->error());
    self::assertSame([], $validate->getMessage());
    self::assertSame(['name' => '小牛哥'], $validate->getData());
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
}验证器校验错误 
public function testError(): void
{
    $validate = new Validator(
        [
            'name' => '小牛哥',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}设置校验数据 
public function testData(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->data(['name' => '12345678901234567890']);
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
}添加校验数据 
public function testAddData(): void
{
    $validate = new Validator(
        [
        ],
        [
            'name' => 'required|min_length:20|'.IValidator::OPTIONAL,
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    $validate->addData(['name' => '中国']);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}设置校验规则 
public function testRule(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    $validate->rule(['name' => 'required|min_length:20']);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->rule(['name' => 'required|max_length:20']);
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
}设置校验规则支持条件 
第一个闭包条件参数不为空,如果闭包返回 true 则添加改验证规则,否则忽略。
public function testRuleIf(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
        ],
        [
            'name' => '用户名',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    $validate->rule(['name' => 'required|min_length:20'], function (array $data) {
        $this->assertSame(['name' => '中国'], $data);
        return false;
    });
    $rule = <<<'eot'
        []
        eot;
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
}添加校验规则 
public function testAddRule(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
        ],
        [
            'name' => '用户名',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    $validate->addRule(['name' => 'required|min_length:20']);
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ],
                [
                    "min_length",
                    [
                        "20"
                    ]
                ]
            ]
        }
        eot;
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}添加校验规则支持条件 
第一个闭包条件参数不为空,如果闭包返回 true 则添加改验证规则,否则忽略。
public function testAddRuleIf(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
        ],
        [
            'name' => '用户名',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    $validate->addRule(['name' => 'required|min_length:20'], function (array $data) {
        $this->assertSame(['name' => '中国'], $data);
        return false;
    });
    $rule = <<<'eot'
        []
        eot;
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule()
        )
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
}设置验证消息 
public function testMessage(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->message(['min_length' => '{field} not min {rule}']);
    $error = <<<'eot'
        {
            "name": [
                "用户名 not min 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}添加验证消息 
设置规则所有字段的验证消息。
public function testAddMessage(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addMessage(['min_length' => '{field} foo bar {rule}']);
    $error = <<<'eot'
        {
            "name": [
                "用户名 foo bar 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}添加指定字段验证规则消息 
可以单独为某个字段指定验证消息规则,其它字段验证消息保持不变。
public function testAddMessageForOneField(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addMessage(['name' => ['min_length' => '{field} hello world {rule}']]);
    $error = <<<'eot'
        {
            "name": [
                "用户名 hello world 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}添加指定字段验证规则消息(圆点分隔) 
通过圆点 . 分隔开来。
public function testAddMessageForOneFieldSeparateByDot(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addMessage(['name.min_length' => '{field} hehe {rule}']);
    $error = <<<'eot'
        {
            "name": [
                "用户名 hehe 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}添加指定多层子字段验证规则消息(圆点分隔) 
通过圆点 . 分隔开来。
public function testSubDataWithSubMessage(): void
{
    $validate = new Validator(
        [
            'name' => ['sub' => ['sub' => '']],
        ],
        [
            'name.sub.sub' => 'required|'.IValidator::MUST,
        ],
        [
            'name' => '歌曲',
        ]
    );
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name.sub.sub": [
                "name.sub.sub 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addMessage(['name.sub.sub' => ['required' => '字段 {field} 不能为空']]);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name.sub.sub": [
                "字段 name.sub.sub 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}添加通配符字段验证规则消息 
通过 * 来代表通配符。
public function testWildcardSubDataWithSubMessage(): void
{
    $validate = new Validator(
        [
            'name' => ['sub' => ['sub' => '']],
        ],
        [
            'name.sub.sub' => 'required|'.IValidator::MUST,
        ],
        [
            'name' => '歌曲',
        ]
    );
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name.sub.sub": [
                "name.sub.sub 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addMessage(['name*' => ['required' => 'sub {field} must have value']]);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name.sub.sub": [
                "sub name.sub.sub must have value"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}设置验证字段隐射 
public function testName(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(['name' => '用户名'], $validate->getName());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->name(['name' => 'username']);
    $error = <<<'eot'
        {
            "name": [
                "username 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}添加验证字段隐射 
public function testAddName(): void
{
    $validate = new Validator(
        [
            'name' => '中国',
        ],
        [
            'name' => 'required|min_length:20',
        ],
        [
            'name' => '用户名',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "用户名 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(['name' => '用户名'], $validate->getName());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addName(['name' => 'hello world']);
    $error = <<<'eot'
        {
            "name": [
                "hello world 不满足最小长度 20"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}验证后回调 
无论成功或者失败都会执行回调。
public function testAfter(): void
{
    $validate = new Validator(
        [
            'name' => '成都',
        ],
        [
            'name' => 'required|max_length:10',
        ],
        [
            'name' => '地名',
        ]
    );
    $validate->after(function ($v): void {
        $this->assertSame(['name' => '地名'], $v->getName());
    });
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
}自定义扩展验证规则 
public function testExtend(): void
{
    $validate = new Validator(
        [
            'name' => 1,
        ],
        [
            'name' => 'required|custom_rule:10',
        ],
        [
            'name' => '地名',
        ]
    );
    $validate->extend('custom_rule', static function ($value, array $param, IValidator $validator, string $field): bool {
        if (1 === $value) {
            return true;
        }
        return false;
    });
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    $validate->data(['name' => 0]);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
}直接调用验证规则 
public function testCall(): void
{
    $validate = new Validator();
    self::assertTrue($validate->minLength('成都', 1));
    self::assertTrue($validate->minLength('成都', 2));
    self::assertFalse($validate->minLength('成都', 3));
    self::assertFalse($validate->alpha('成都'));
    self::assertTrue($validate->alpha('cd'));
}直接调用自定义验证规则 
public function testCallCustom(): void
{
    $validate = new Validator();
    $validate->extend('custom_foo_bar', static function (string $field, $value, array $param): bool {
        if ('成都' === $value) {
            return true;
        }
        return false;
    });
    self::assertTrue($validate->customFooBar('成都'));
    self::assertFalse($validate->customFooBar('魂之挽歌'));
}自定义扩展验证规则(类) 
自定义扩展规则可以为一个独立的类,例如下面的例子。
namespace Tests\Validate;
class ExtendClassTest1
{
    public function handle($value, array $param, IValidator $validator, string $field): bool
    {
        if (1 === $value) {
            return true;
        }
        return false;
    }
    public function handle2($value, array $param, IValidator $validator, string $field): bool
    {
        if (2 === $value) {
            return true;
        }
        return false;
    }
}默认情况下,此时自定义类的 handle 方法将作为验证入口。
public function testCallExtendClass(): void
{
    $validate = new Validator(
        [
            'name' => 1,
        ],
        [
            'name' => 'custom_foobar',
        ],
        [
            'name' => '地名',
        ]
    );
    $container = new Container();
    $validate->setContainer($container);
    $validate->extend('custom_foobar', ExtendClassTest1::class);
    self::assertTrue($validate->success());
    $validate->data(['name' => 'foo']);
    self::assertFalse($validate->success());
}自定义扩展验证规则(类),指定验证方法 
自定义扩展规则可以为一个独立的类,例如下面的例子。
namespace Tests\Validate;
class ExtendClassTest1
{
    public function handle($value, array $param, IValidator $validator, string $field): bool
    {
        if (1 === $value) {
            return true;
        }
        return false;
    }
    public function handle2($value, array $param, IValidator $validator, string $field): bool
    {
        if (2 === $value) {
            return true;
        }
        return false;
    }
}指定方法情况下,通过 @ 分隔开来,此时自定义类的 handle2 方法将作为验证入口。
public function testCallExtendClassWithCustomMethod(): void
{
    $validate = new Validator(
        [
            'name' => 2,
        ],
        [
            'name' => 'custom_foobar',
        ],
        [
            'name' => '地名',
        ]
    );
    $container = new Container();
    $validate->setContainer($container);
    $validate->extend('custom_foobar', ExtendClassTest1::class.'@handle2');
    self::assertTrue($validate->success());
    $validate->data(['name' => 'foo']);
    self::assertFalse($validate->success());
}验证失败则跳过其它验证规则 
只需要在校验规则中加入 SKIP_OTHER 即可。
public function testShouldSkipOther(): void
{
    $validate = new Validator(
        [
            'name' => '',
            'value' => '',
        ],
        [
            'name' => 'required|alpha',
            'value' => 'required',
        ],
        [
            'name' => '地名',
            'value' => '值',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "地名 不能为空",
                "地名 只能是字母"
            ],
            "value": [
                "值 不能为空"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(['name' => '地名', 'value' => '值'], $validate->getName());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addRule(['name' => 'required|alpha|'.IValidator::SKIP_OTHER]);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name": [
                "地名 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}验证失败则跳过自身其它验证规则 
只需要在校验规则中加入 SKIP_SELF 即可,只会跳过当前字段的其他验证规则,而其它字段的验证规则不受影响。
public function testShouldSkipSelf(): void
{
    $validate = new Validator(
        [
            'name' => '',
            'value' => '',
        ],
        [
            'name' => 'required|alpha',
            'value' => 'required',
        ],
        [
            'name' => '地名',
            'value' => '值',
        ]
    );
    $error = <<<'eot'
        {
            "name": [
                "地名 不能为空",
                "地名 只能是字母"
            ],
            "value": [
                "值 不能为空"
            ]
        }
        eot;
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(['name' => '地名', 'value' => '值'], $validate->getName());
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->addRule(['name' => 'required|alpha|'.IValidator::SKIP_SELF]);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name": [
                "地名 不能为空"
            ],
            "value": [
                "值 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}值为 null 会跳过可选验证规则 
如果校验规则中有 OPTIONAL ,那么字段值为 null 则不会执行验证规则。
public function testOptional(): void
{
    $validate = new Validator(
        [
            'name' => null,
        ],
        [
            'name' => 'required|'.IValidator::OPTIONAL,
        ],
        [
            'name' => '地名',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame(['name' => '地名'], $validate->getName());
}值为 null或者空字符串 会跳过可选字符串验证规则 
如果校验规则中有 OPTIONAL_STRING ,那么字段值为 null 或者空字符串则不会执行验证规则。
public function testOptionalString(): void
{
    $validate = new Validator(
        [
            'name' => null,
        ],
        [
            'name' => 'required|'.IValidator::OPTIONAL_STRING,
        ],
        [
            'name' => '地名',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame(['name' => '地名'], $validate->getName());
    $validate = new Validator(
        [
            'name' => '',
        ],
        [
            'name' => 'required|'.IValidator::OPTIONAL_STRING,
        ],
        [
            'name' => '地名',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame(['name' => '地名'], $validate->getName());
}值为 null 默认必须验证 
我们加入 MUST 或者默认不指定,那么 null 也会执行验证。
public function testMustRequired(): void
{
    $validate = new Validator(
        [
            'name' => null,
        ],
        [
            'name' => 'required|'.IValidator::OPTIONAL,
        ],
        [
            'name' => '地名',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    self::assertSame(['name' => '地名'], $validate->getName());
    $validate->rule(['name' => 'required']);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name": [
                "地名 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->data(['name' => null]);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    $error = <<<'eot'
        {
            "name": [
                "地名 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
}通配符验证规则支持 
可以通过 * 来表示通配符验证规则。
public function testWildcardRule(): void
{
    $validate = new Validator(
        [
            'name' => '',
            'nafoo' => '',
            'nabar' => '',
        ],
        [
        ],
        [
            'name' => '地名',
            'nafoo' => 'foo',
            'nabar' => 'bar',
        ]
    );
    self::assertTrue($validate->success());
    self::assertFalse($validate->fail());
    $validate->rule(['na*' => 'required']);
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(['name' => '地名', 'nafoo' => 'foo', 'nabar' => 'bar'], $validate->getName());
    $data = <<<'eot'
        {
            "name": "",
            "nafoo": "",
            "nabar": ""
        }
        eot;
    self::assertSame(
        $data,
        $this->varJson(
            $validate->getData()
        )
    );
    $rule = <<<'eot'
        {
            "name": [
                [
                    "required",
                    []
                ]
            ],
            "nafoo": [
                [
                    "required",
                    []
                ]
            ],
            "nabar": [
                [
                    "required",
                    []
                ]
            ]
        }
        eot;
    self::assertSame(
        $rule,
        $this->varJson(
            $validate->getRule(),
            1
        )
    );
    $error = <<<'eot'
        {
            "name": [
                "地名 不能为空"
            ],
            "nafoo": [
                "foo 不能为空"
            ],
            "nabar": [
                "bar 不能为空"
            ]
        }
        eot;
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error(),
            2
        )
    );
}类的静态方法验证规则支持 
可以直接指定类的静态方法为验证规则,例如下面的例子。
namespace Tests\Validate;
class ClassStaticDemo1
{
    public static function handle(mixed $value, array $param, Validator $validator): bool
    {
        return false;
    }
    public static function demoValidator1(mixed $value, array $param, Validator $validator): bool
    {
        return true;
    }
    public static function demoValidator2(mixed $value, array $param, Validator $validator): bool
    {
        return false;
    }
    public static function demoValidator3(mixed $value, array $param, Validator $validator): bool
    {
        return 'foo' === $value;
    }
    public static function demoValidator4(mixed $value, array $param, Validator $validator): bool
    {
        throw new ValidatorException('我的名字验证失败');
    }
}指定方法情况下,通过 @ 分隔开来,此时自定义类的 demoValidator1 方法将作为验证入口。
public function test2(): void
{
    $validate = new Validator(
        [
            'name' => 2,
        ],
        [
            'name' => [
                ClassStaticDemo1::class.'@demoValidator1',
            ],
        ],
        [
            'name' => '地名',
        ]
    );
    $container = new Container();
    $validate->setContainer($container);
    self::assertTrue($validate->success());
    $validate->data(['name' => 'foo']);
    self::assertTrue($validate->success());
}类的静态方法验证规则支持通过异常抛出错误 
可以在类的静态方法中抛出异常消息,异常必须为\Leevel\Validate\ValidatorException,例如下面的例子。
namespace Tests\Validate;
class ClassStaticDemo1
{
    public static function handle(mixed $value, array $param, Validator $validator): bool
    {
        return false;
    }
    public static function demoValidator1(mixed $value, array $param, Validator $validator): bool
    {
        return true;
    }
    public static function demoValidator2(mixed $value, array $param, Validator $validator): bool
    {
        return false;
    }
    public static function demoValidator3(mixed $value, array $param, Validator $validator): bool
    {
        return 'foo' === $value;
    }
    public static function demoValidator4(mixed $value, array $param, Validator $validator): bool
    {
        throw new ValidatorException('我的名字验证失败');
    }
}指定方法情况下,通过 @ 分隔开来,此时自定义类的 demoValidator4 方法将作为验证入口。
public function test6(): void
{
    $validate = new Validator(
        [
            'name' => 2,
        ],
        [
            'name' => [
                ClassStaticDemo1::class.'@demoValidator4',
            ],
        ],
        [
            'name' => '地名',
        ]
    );
    $container = new Container();
    $validate->setContainer($container);
    self::assertFalse($validate->success());
    $error = <<<'eot'
"name": [
    "我的名字验证失败"
]
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
    $validate->data(['name' => 'foo']);
    self::assertFalse($validate->success());
}验证器支持反义规则 
定义反义规则,只需要在规则前面加上英文感叹号即可。
public function test7(): void
{
    $validate = new Validator(
        [
            'name' => 8,
        ],
        [
            'name' => '!min:5',
        ],
        [
            'name' => '地名',
        ]
    );
    self::assertFalse($validate->success());
    self::assertTrue($validate->fail());
    self::assertSame(['name' => '地名'], $validate->getName());
    $error = <<<'eot'
"name": [
    "不满足【地名 值不能小于 5】"
]
    self::assertSame(
        $error,
        $this->varJson(
            $validate->error()
        )
    );
} QueryPHP
QueryPHP