swoft 学习笔记之验证器

一、创建验证器

  • @Validator(name="ValidatorName") 声明一个名字为 ValidatorName 的验证器
  • 验证项是组成验证器的唯一条件,标记有类型注解的属性就是一个验证项,一个验证器可以有多个验证项
验证项
  • 属性的默认值就是参数的默认值,如果属性没有定义默认值,代表参数没有定义默认值且必须传递。
  • 一个属性必须定义一个类型注解,否则不是一个验证项且对参数验证无效。
  • 一个属性可以多个条件注解,按照定义顺序验证数据。
  • 默认属性名称就是需要验证的参数名称,也可以通过类型注解的 name 参数映射需要验证的字段名称。
  • 若验证不通过时,将会抛出 Swoft\Validator\Exception\ValidatorException 异常。
类型注解

@IsInt、@IsArray、@IsString、@IsFloat、@IsBool
参数 name 指定需要验证字段名字,message 指定验证不通过时的错误信息

条件注解

@AfterDate、@Alpha、@AlphaDash、@AlphaNum、@BeforeDate、@Chs、@ChsAlpha等比较多,在此无需一一罗列,参考官方文档即可
使用条件注解的时候一定要注意引用正确的验证类

代码样例

验证器 TestValidator.php

<?php declare(strict_types=1);

namespace App\Validator;

use Swoft\Validator\Annotation\Mapping\AlphaDash;
use Swoft\Validator\Annotation\Mapping\Confirm;
use Swoft\Validator\Annotation\Mapping\IsString;
use Swoft\Validator\Annotation\Mapping\Length;
use Swoft\Validator\Annotation\Mapping\Validator;

/**
 * Class TestValidator
 * @Validator(name="TestValidator")
 */
class TestValidator
{
    /**
     * @IsString()
     * @AlphaDash(message="名字必须是数字,字母,短横,下划线组合")
     * @Length(min=4,max=20,message="名字长度在4~20之间")
     * @var string
     */
    protected $name;

    /**
     * @IsString()
     * @AlphaDash(message="密码必须是数字,字母,短横,下划线组合")
     * @Length(min=6,max=15,message="密码长度在6~15之间")
     * @var string
     */
    protected $password;

    /**
     * @IsString()
     * @Confirm(name="password",message="确认密码不一致")
     * @var string
     */
    protected $confirmPassword;
}

控制器类 TestController.php

<?php declare(strict_types=1);

namespace App\Http\Controller;

use Swoft\Context\Context;
use Swoft\Http\Message\ContentType;
use Swoft\Http\Message\Request;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Swoft\Validator\Annotation\Mapping\Validate;

/**
 * Class TestController
 * @package App\Http\Controller
 * @Controller(prefix="test")
 */
class TestController
{
    /**
     * @RequestMapping(route="register",method={RequestMethod::POST})
     * @Validate(validator="TestValidator")
     * @param Request $request
     * @return Response
     */
    public function register(Request $request):Response
    {
        $name     = $request->post('name');
        $password = $request->post('password');
        $age      = $request->post('age');

        $data = [
            'name'     => $name,
            'age'      => $age ?? 18,
            'password' => $password,
        ];
        $response = Context::mustGet()->getResponse();
        $response = $response->withStatus(201)
            ->withContentType(ContentType::JSON)
            ->withData($data);
        return $response;
    }
}

在控制器中使用 @Validate 进行验证

  • validator 指定验证器名称
  • fields 指定验证器里面验证的字段,这样可以高效的重复使用验证器
  • type 默认 body,ValidateType::GET 验证 GET 请求 query 参数
  • params 自定义验证器使用,传递给自定义验证器的参数

二、自定义验证规则

以定义一个正整数的验证规则为实例进行讲解

步骤一:声明注解命令
<?php declare(strict_types=1);

namespace App\Annotation\Mapping;

use Doctrine\Common\Annotations\Annotation\Attribute;
use Doctrine\Common\Annotations\Annotation\Attributes;

/**
 * Class PositiveInteger
 * @package App\Annotation\Mapping
 * @Annotation //声明这个类是一个注解命令
 * @Attributes({ //声明注解参数集合
 *      @Attribute("message",type="string") //声明注解具体的参数 name 参数的名字 type 参数值的类型
 * })
 */
class PositiveInteger
{
    /**
     * @var string
     */
    private $message = '';

    /**
     * PositiveInteger constructor.
     * @param array $values
     */
    public function __construct(array $values)
    {
        if( isset($values['value']) ){
            $this->message = $values['value'];
        }

        if( isset($values['message']) ){
            $this->message = $values['message'];
        }
    }

    /**
     * @return string
     */
    public function getMessage(): string
    {
        return $this->message;
    }
}
步骤二:声明注解解析

注解命令要想能够执行,则还需要定义一个注解命令的解析器,需要继承
Swoft\Annotation\Annotation\Parser\Parser

<?php declare(strict_types=1);

use Swoft\Annotation\Annotation\Parser\Parser;
use Swoft\Annotation\Annotation\Mapping\AnnotationParser;
use Swoft\Validator\ValidatorRegister;

/**
 * Class PositiveIntegerParser
 * @AnnotationParser(annotation="PositiveInteger::class") //声明要解析的注解命令
 */
class PositiveIntegerParser extends Parser{
    /**
     * @param int $type
     * @param object $annotationObject
     * @return array
     * @throws ReflectionException
     * @throws \Swoft\Validator\Exception\ValidatorException
     */
    public function parse(int $type,$annotationObject):array
    {
        if($type !== self::TYPE_PROPERTY){
            return [];
        }
        //向验证器注册一个验证规则
        ValidatorRegister::registerValidatorItem($this->className,
        $this->propertyName,$annotationObject);
        return [];
    }
}
步骤三:声明一个验证规则
<?php declare(strict_types=1);

namespace App\Validator\Rule;

use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Validator\Contract\RuleInterface;
use Swoft\Validator\Exception\ValidatorException;

/**
 * Class PositiveIntegerRule
 * @package App\Validator\Rule
 * @Bean(PositiveInteger::class) //验证器内部是通过 Bean 容器来获得到我们的验证规则的
 */
class PositiveIntegerRule implements RuleInterface
{
    /**
     * @param array $data 待验证的所有数据
     * @param string $propertyName 需要验证的字段名
     * @param object $item 注解类的对象
     * @param null $default 字段的默认值
     * @return array
     * @throws ValidatorException
     */
    public function validate(array $data, string $propertyName, $item, $default = null) :array
    {
        $message = $item->getMessage();
        if( !isset($data[$propertyName]) && $default == null){
            $message = empty($message) ? sprintf("s% 不能为空",$propertyName) : $message;
            throw new ValidatorException($message,400);
        }

        if (is_numeric($data[$propertyName]) 
        && is_int($data[$propertyName] + 0) 
        && ($data[$propertyName] + 0) > 0) {
            return [$data];
        }

        $message = empty($message) ? sprintf("s% 必须是正整数",$propertyName) : $message;
        throw new ValidatorException($message,400);
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
今年不学习,明天惨唧唧。
zs4336
讨论数量: 5

https://www.supjos.cn/archives/89.html

合伙搞个原生注解的项目不?

4年前 评论
zs4336 (楼主) 4年前

大兄弟,终于找到你了。 这东西麻烦得很, 请再详细点, thanks

4年前 评论
zs4336 (楼主) 4年前

例如type字段可以不传入,但如果传入的话type必须是int类型,这样怎么实现?

4年前 评论
zs4336 (楼主) 4年前
zxr615 (作者) 4年前
zs4336 (楼主) 4年前

楼主,问你一个问题,验证器能发与中间件使用,我想把数据检查方法中间件里面,中间件负责权限检查,数据检查,jwt检查,到控制器的数据都是安全的,这样能行么?能否给一个示例,十分感谢

4年前 评论
zs4336 (楼主) 4年前

楼主,swoft的验证器 如果一个参数不是必须,传了需要验证不传 可以忽略怎么写?,还有就是我在验证器离写了一个protected $name; 文档说没给默认是必传,但是我没给 验证也通过了是怎么回事

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!