swoft 學習筆記之驗證器

zs4336發表於2019-08-12

一、建立驗證器

  • @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 協議》,轉載必須註明作者和本文連結
今年不學習,明天慘唧唧。

相關文章