文章目錄
- 校驗器
- 校驗器類型
- @Validate 注解
- 屬性說明
- 校驗器校驗主要流程
- 系統校驗器每個屬性存儲結構
- 校驗器規則定義,注解、注解解析器定義
- 校驗器注解使用
- 實現一個自定義的校驗器
- 校驗器注解
- 校驗器注解解析器
- 校驗器規則
- 系統校驗器
- Controller/Action 綁定校驗器
校驗器
校驗器是 swoft2 中一個常用的組件。
校驗器在 RPC服務、WS服務、HTTP 服務中均有涉及,用來校驗客戶端上傳到服務端的數據是否合法。
校驗器類型
校驗器一般分為兩種,系統校驗器,和自定義校驗器。
系統校驗器是通過 @Validator 標簽進行注解的一個校驗器類(沒有方法只有屬性),每個屬性上通過不同的注解(如:@Length @IsString )來說明校驗時候參數要符合的規則。
自定義校驗器,同樣需要 @Validator 標簽對校驗的類進行注解,但是類必須要實現 ValidatorInterface
接口,只有實現接口validate(array $data, array $params)
,才會稱為自定義校驗器(源碼中有此判斷,參見:src/Annotation/Parser/ValidatorParser.php
)。注意自定義校驗器,只會校驗 body 中數據,且自定義校驗器,只會使用 body 中數據和 params,其他 @Validate 屬性,并不會使用。
/*** Class CustomerValidator** @since 2.0** @Validator(name="userValidator")*/
class CustomerValidator implements ValidatorInterface
{/*** @param array $data 這是自定義校驗器中* @param array $params** @return array* @throws ValidatorException*/public function validate(array $data, array $params): array{$start = $data['start'] ?? null;$end = $data['end'] ?? null;if ($start === null && $end === null) {throw new ValidatorException('Start time and end time cannot be empty');}if ($start > $end) {throw new ValidatorException('Start cannot be greater than the end time');}return $data;}
}
@Validate 注解
屬性說明
/*** Class** @since 2.0** @Annotation* @Target("METHOD")* @Attributes({* @Attribute("validator", type="string"),* @Attribute("fields", type="array"),* @Attribute("params", type="array"),* @Attribute("message", type="string"),* })*/
class Validate {}
以上為 @Validate 注解的參數要求,具體說明見下表:
注解參數 | 參數類型 | 是否必須 | 備注 |
---|---|---|---|
validator | 字符串 | 是 | 已經定義好的校驗器的名字 |
fields | 數組 | 是 | 校驗器中的屬性(對應請求中的參數)。 不指定,默認校驗校驗器中所有屬性。 如果指定的值在校驗器中不存在,那么控制器中仍然可以接收到參數,但是不會有任何校驗!!! |
unfields | 數組 | 否 | 不進行校驗的屬性 |
params | 數組 | 否 | 用在自定義校驗器中,用戶手動傳遞到校驗器的數據 注:自定義校驗器時候才會使用 |
message | 字符串 | 否 | 校驗失敗時候提示信息 |
type | 字符串 | 否 | 校驗數據所在請求對象中的位置(get/body/path) |
@Validate
注解用于 method 上,示例:
// 示例1:通過系統默認校驗器,校驗 post 請求中的參數
/*** @RequestMapping("account")* @param Request $request* @param Response $response* @return Response* @throws InvalidArgumentException* @Validate(validator="userValidator", fields={"name", "password"}, type="body")*/
public function account(Request $request, Response $response): Response;// 示例2:通過系統默認的校驗器校驗自定義 path 參數/*** @RequestMapping(route="/[list-{page}.html|index.html]", params={"page"="[2-9]\d*|1\d+"}, method={"GET"})* @View("home/index")* @Validate(validator=PageListDto::class, fields={"page", "size"}, type="path")** @param Request $request* @param Response $response* @return Response*/
public function index(Request $request, Response $response): Response
注意:@Validate 的 type 參數十分重要,默認值為 body,也就是默認校驗 post 請求參數。如果是校驗 get 參數,或者自定義 path 中的自定義參數,必須要寫明類型。否則校驗出錯。
校驗器校驗主要流程
以 HTTP 服務為例,可以參照 http-server 組件中的 src/Middleware/ValidatorMiddleware.php
中間件,此中間件可以通過定義核心 Bean 的方式,將其掛載到 HTTP 服務上。從相關代碼可以看出,中間件運行期間,通過 ValidateRegister::getValidates()
方法提取訪問接口上綁定的校驗器相關信息。
class ValidatorMiddleware implements MiddlewareInterface
{/*** @param ServerRequestInterface $request* @param RequestHandlerInterface $handler** @return ResponseInterface* @throws ValidatorException*/public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface{// 獲取路由匹配結果,如果未匹配成功,此中間件不做處理,交給下一個中間件。/* @var Route $route */[$status, , $route] = $request->getAttribute(Request::ROUTER_ATTRIBUTE);if ($status !== Router::FOUND) {return $handler->handle($request);}// 如果路由匹配成功,獲取路由綁定的處理器(controller/action)// Controller and method$handlerId = $route->getHandler();[$className, $method] = explode('@', $handlerId);// 獲取 controller/action 方法上通過注解綁定的校驗器(可以多個)// Query validates$validates = ValidateRegister::getValidates($className, $method);// 如果沒有,說明不用校驗,交給下一個中間件處理if (empty($validates)) {return $handler->handle($request);}// 獲取校驗涉及的相關數據$data = $request->getParsedBody();$query = $request->getQueryParams();$path = $route->getParams();// ParsedBody is empty string$parsedBody = $data = empty($data) ? [] : $data;$notParsedBody = !is_array($data);if ($notParsedBody) {$parsedBody = [];}// 獲取校驗器組件的實例對象/* @var Validator $validator */