Laravel驗證器用法歸納

唐章明發表於2024-01-09

laravel表單驗證的文件寫的比較雜亂無章,在此總結歸納一下

<?php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

class TestRequest extends FormRequest
{

    /**
     * 表示驗證器是否應在第一個規則失敗時停止
     * 注意此處是停止所有屬性與規則,與停止單個屬性的bail規則不同
     * 
     * @var bool
     */
    protected $stopOnFirstFailure = false;


    /**
     * 確定使用者是否有權提出此請求
     * 可以在該處做許可權判斷,比如使用者發表帖子,可以在此處判斷使用者是否有權發帖
     *
     * @return bool
     */
    public function authorize(): bool
    {
        // 例子
        $registerTimestamp = strtotime(Auth::user()->created_at);
        if( (time() - $registerTimestamp) < 86400 ){
            //註冊時間不足24小時,禁止發表新帖子
            return false;
        }

        return true;
    }


    /**
     * 要驗證的資料,可省略,預設值 request()->all()
     */
    public function validationData()
    {
        return [
            'title'    => '不像我只會心疼哥哥',
            'content'  => '哥哥,你女朋友要是知道我倆吃同一個棒棒糖,你女朋友不會吃醋吧!',
            'password' => '88888888',  
        ];
    }

    /**
     * 驗證規則
     */
    public function rules(): array
    {
        return [
            'title'    => 'required|between:8,50',
            'content'  => 'required|min:100',
            //假設我們為了使用者安全,發帖時必須提交密碼二次驗證
            'password' => 'required|between:6,20',
        ];
    }

    /**
     * 自定義屬性別名,可省略
     */
    public function attributes()
    {
        return [
            'title'   => '帖子標題',
            'content' => '帖子內容',
        ];
    }

    /**
     * 自定義錯誤訊息,可省略
     */
    public function messages()
    {
        return [
            'required'         => ':attribute不能為空, 請填寫後再提交',
            'title.between'    => '帖子標題長度限制在:min至:max個字之間',
            'content.min'      => '帖子內容至少需要100個字',
            'password.between' => '密碼錯誤', //密碼長度不符合規則,直接返回密碼錯誤,節省資料庫查詢
        ];
    }

    /**
     * 行內驗證器
     * 也許你在yii2和thinkphp中經常這樣用且十分好用, 但是laravel中無法實現,請參考驗證器閉包文件代替
     * 
     * laravel驗證器閉包
     * @link https://learnku.com/docs/laravel/10.x/validation/14856#bf0dbb
     *
     * yii行內驗證器     
     * @link https://www.yiiframework.com/doc/guide/2.0/zh-cn/input-validation#inline-validators
     * 
     * tp自定義驗證規則  
     * @link https://doc.thinkphp.cn/v8_0/validator.html
     */
    public function validateTitle($attribute, $value, $fail)
    {
        return ;
    }


    /**
     *  配置驗證器例項。
     *
     * @param  \Illuminate\Validation\Validator  $validator
     * @return void
     */
    public function withValidator(\Illuminate\Validation\Validator $validator)
    {
        // 這裡是驗證器的後置操作
        $validator->after(function (\Illuminate\Validation\Validator $validator) {

            /**
             * errors 具體內容可以參考 Illuminate\Support\MessageBag
             */
            if( $validator->errors()->isEmpty() ){

                /**
                 * 執行到 isEmpty() 時,表示rules裡面的驗證規則都透過了
                 * 此時密碼只進行了rules裡的規則驗證,我們需要繼續驗證密碼是否與持久儲存相同
                 */
                $password = $this->input('password');
                if( $password !== '123456' ){
                    $validator->errors()->add('password', '資料庫比對密碼錯誤');
                } 

            }

        });
    }




    /**
     *
     * 自定義驗證失敗後的錯誤處理
     *
     * 必需丟擲一個Exception,否則業務程式碼會繼續執行,丟擲了Exception則會被框架捕捉處理
     * 直接return返回一個response物件是無效的
     * 
     * 父類 FormRequest 裡面預設丟擲的是 Illuminate\Validation\ValidationException
     * 如果是表單請求(application/x-www-form-urlencoded)它會重定向回來源頁面,並且把錯誤資訊寫入flash session,
     * 非表單請求否則返回一個固定格式的json響應
     * 
     * 父類預設的failedValidation不能滿足以下需求
     * 1、在實際使用中,有的時候我們想驗證失敗時始終返回json而不跳轉,甚至是xml
     * 2、預設返回的json格式是固定,而我們可能需要自定義一些json欄位
     * 
     */
    protected function failedValidation(Validator $validator)
    {
        // 具體內容可以參考 Illuminate\Support\MessageBag 
        $error = $validator->errors()->all();

        // 自定義response物件 Illuminate\Http\Response
        $response = response()->json([
            //...自定義的錯誤響應內容
            'code'    => 10001,
            'message' => $error->first(),
            'errors'  => $error->errors(),
        ]);

        /**
         * 丟擲一個HttpResponseException異常類,
         * 這將阻止驗證器呼叫後的後續程式碼,直接傳送response到瀏覽器
         */
        throw new HttpResponseException($response);
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結
我,秦始皇,打錢!!!

相關文章