記錄hyperf框架表單驗證中的細枝末節

奕鵬發表於2021-07-01
[TOC]

簡介

本文對使用hyperf框架的表單驗證中遇到的兩個小細節做一個分享。具體的兩點如下:

  1. 自定義驗證異常資料返回格式。
    該問題主要在下面的第3點體現。

  2. 自定義驗證規則。
    該問題主要在下面的第6點體現。

    自定義驗證異常格式

  3. 首選根據官方文件進行操作,安裝驗證元件。

composer require hyperf/validation
php bin/hyperf.php vendor:publish hyperf/translation
php bin/hyperf.php vendor:publish hyperf/validation
  1. 接著在配置檔案config/autoload/middlewares.php,中新增驗證異常中介軟體。這裡的異常中介軟體為框架自帶的異常處理中介軟體。
<?php

declare(strict_types=1);
/**
 * This file is part of api.
 *
 * @link     https://www.qqdeveloper.io
 * @document https://www.qqdeveloper.wiki
 * @contact  2665274677@qq.com
 * @license  Apache2.0
 */
use Hyperf\Validation\Middleware\ValidationMiddleware;

return [
    'http' => [
        ValidationMiddleware::class,
    ],
];
  1. 自定義一個驗證異常處理器。這一步是最重要的非同步,官方文件有提及到使用框架自帶的異常處理器,如果你沒有特別的需求,可以直接按照官方文件操作即可。由於我們的異常介面返回資料格式要返回一個json的格式,而不是預設的一個文字格式。
<?php

declare(strict_types=1);
/**
 * This file is part of api.
 *
 * @link     https://www.qqdeveloper.io
 * @document https://www.qqdeveloper.wiki
 * @contact  2665274677@qq.com
 * @license  Apache2.0
 */
namespace App\Exception\Handler;

use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Validation\ValidationException;
use Psr\Http\Message\ResponseInterface;
use Throwable;

/**
 * 自定義表單驗證異常處理器.
 *
 * Class FromValidateExceptionHandler
 */
class FromValidateExceptionHandler extends ExceptionHandler
{
    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        if ($throwable instanceof ValidationException) {
            // 格式化異常資料格式
            $data = json_encode([
                'code' => $throwable->getCode(),
                // 獲取異常資訊
                'message' => $throwable->validator->errors()->first(),
                'data' => [],
            ]);
            $this->stopPropagation();
            return $response->withStatus(422)->withBody(new SwooleStream($data));
        }

        return $response;
    }
    // 異常處理器處理該異常
    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}
  1. 編寫完驗證異常處理器之後,將該異常新增到異常配置檔案config/autoload/exceptions.php中。由於hyperf中異常處理器的配置順序會影響到異常的處理順序,這裡可以隨機順序配置。
<?php

declare(strict_types=1);
/**
 * This file is part of api.
 *
 * @link     https://www.qqdeveloper.io
 * @document https://www.qqdeveloper.wiki
 * @contact  2665274677@qq.com
 * @license  Apache2.0
 */
use App\Exception\Handler\FromValidateExceptionHandler;

return [
    'handler' => [
        'http' => [
            Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
            App\Exception\Handler\AppExceptionHandler::class,
            // 自定義的驗證異常處理器
            FromValidateExceptionHandler::class,
        ],
    ],
];
  1. 剩下的程式碼就按照文件操作,編寫一個獨立的驗證類檔案,在對應的控制器中方法採用依賴注入的方式呼叫即可。輸出的結果,格式就和下面的一樣了。
    Snipaste_2021-06-30_18-38-48

自定義驗證規則

為什麼有自定義驗證規則呢?無非就是官網提供的驗證規則屬於常見的,可能你會根據專案的需要,自定義一些規則,這時候就需要你單獨定義一個規則了。我們這裡建立一個money的驗證規則,驗證金額是否合法。

  1. 建立一個監聽器。
<?php
declare(strict_types=1);
/**
 * This file is part of api.
 *
 * @link     https://www.qqdeveloper.io
 * @document https://www.qqdeveloper.wiki
 * @contact  2665274677@qq.com
 * @license  Apache2.0
 */
namespace App\Listener;

use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use Hyperf\Validation\Event\ValidatorFactoryResolved;

/**
 * 驗證器監聽器.
 *
 * Class ValidatorFactoryResolvedListener
 */
class ValidatorFactoryResolvedListener implements ListenerInterface
{
    public function listen(): array
    {
        return [
            ValidatorFactoryResolved::class,
        ];
    }

    public function process(object $event)
    {
        /** @var ValidatorFactoryInterface $validatorFactory */
        $validatorFactory = $event->validatorFactory;
        // 註冊了 money 驗證器
        $validatorFactory->extend('money', function ($attribute, $value, $parameters, $validator) {
            var_dump(time());
            $pregResult = preg_match('/^[0-9]{1,20}(\.[0-9]{1,2})?$/', $value);
            // true則返回錯誤資訊;false則不返回錯誤,表示驗證通過
            return empty($pregResult) ? true : false;
        });
        $validatorFactory->replacer('money', function ($message, $attribute, $rule, $parameters) {
            return str_replace(':money', $attribute, $message);
        });
    }
}
  1. 註冊監聽器到config/autoload/listeners配置檔案中。
<?php

declare(strict_types=1);
/**
 * This file is part of api.
 *
 * @link     https://www.qqdeveloper.io
 * @document https://www.qqdeveloper.wiki
 * @contact  2665274677@qq.com
 * @license  Apache2.0
 */
use App\Listener\ValidatorFactoryResolvedListener;

return [
    ValidatorFactoryResolvedListener::class,
];
  1. 自定義一個獨立驗證類檔案。
<?php

declare(strict_types=1);
/**
 * This file is part of api.
 *
 * @link     https://www.qqdeveloper.io
 * @document https://www.qqdeveloper.wiki
 * @contact  2665274677@qq.com
 * @license  Apache2.0
 */
namespace App\Request;

use Hyperf\Validation\Request\FormRequest;

class FooRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'money' => 'money',
        ];
    }
}
  1. 自定義驗證欄位資訊。找到storage/languages/zh_CN/validation.php檔案。在下面新增如下兩行程式碼,關於en檔案下的驗證欄位配置資訊,可以新增也可以不新增,根據實際需要新增即可。
'money' => ':attribute格式錯誤',
'attributes' => [
    'money' => '金額',
],
  1. 在對應的控制器中使用依賴注入的方式對獨立的驗證類檔案進行注訪問。這樣我們的一個獨立驗證規則就可以配置好了。效果如下:
    Snipaste_2021-06-30_18-38-48

  2. 或許這麼定義之後,發現自定義規則沒有起作用,這種情況,獲取是你沒有傳遞該引數名導致的。只有你傳遞了引數名,該驗證規則才會生效。

本作品採用《CC 協議》,轉載必須註明作者和本文連結
喜歡的,可以關注公眾號"卡二條的技術圈"。

相關文章