iT邦幫忙

2022 iThome 鐵人賽

0
自我挑戰組

laravel+vue 學習系列 第 31

Day 31. Laravel Validation

  • 分享至 

  • xImage
  •  

一、Request

  1. 在經過路由進行增刪修時, 會產生 Illuminate\Http\Request 實例帶入到 Controller 參數, Request 身上自帶 validate() 方法產生驗證器, 對使用者輸入值進行驗證
    public function update(Request $request){
        $validated = $request->validate([
            'name' => ['require', 'string', 'max:255']
        ]);
    }    
  1. 使用 named error bag 區分錯誤訊息, 常用在單一頁面有多張表單
    public function update(Request $request){
        $validated = $request->validateWithBag('product', [
            'name' => ['require', 'string', 'max:255']
        ]);
    }
    
    // View 中可以區隔取出錯誤訊息
    // {{ $errors->product->first('name') }}
  1. 驗證後若有不符合驗證規則的資料, 會拋出錯誤訊息, 預設會回傳到表單頁面

    • 表單頁面上可以用 $errors 變數接受到錯誤訊息
    • 可以使用 old('name) 方法來取得輸入的資料內容
    • 可以使用 @error('name') ... @enderror 來判斷驗證錯誤後要顯示的內容
        <!-- 判斷是否有驗證錯誤訊息 -->
        @if ( $errors->any() )
            @foreach ( $errors->all() as $error )
                <!-- 單筆錯誤訊息 -->
                <p>{{ $error }}</p>
            @endforeach
        @endif
    
    • 其他顯示錯誤訊息方式
        // 若有單一欄位名稱多筆錯誤訊息, 預取出第一個錯誤訊息
        echo $errors->first('spec_name');
    
        // 單一欄位名稱多筆錯誤訊息, 取出所有錯誤訊息
        foreach ( $errors->get('spec_name') as $spec ) {
            echo "<li>".$spec."</li>";
        }
    
        // 陣列欄位顯示錯誤訊息, 使用 * 遍歷規格名稱
        foreach ($errors->get('spec_name.*') as $spec) {
            // ... 要顯示的內容
        }        
    
  2. 自訂錯誤訊息內容

    • 預設會讀取 lang/en/validation.php 內設定的文字回傳
    • 可以調整語言與在 lang/* 下建立其他語言檔案設定回傳文字
  3. 當請求的 header 內指定要回傳 json 格式, 會產稱 JSON response 並設定狀態碼為 422

    • 可以在 Form Request Validation 時可自訂回傳方式

二、Form Request Validation

  1. 建立自訂的 Request, 可以封裝表單驗證規則, 提供新增、修改時驗證輸入值
  2. 使用 artisan 建立 Request, 預設會產生 authorize 和 rules 方法
    php artisan make:request ProductPostRequest
  1. 在 rules 方法內設定驗證規則
    public function rules()
    {
        // 判斷是否有 id 值
        $id = $this->route('id');
        $unique_name = Rule::unique('pj_category');
        // 驗證名稱不能重複, 排除本身
        if ($id != '')  $unique_name->ignore($id);

        return [
            'name' => [
                'required', 
                $unique_name, 
                'max:255'
            ],
            'parent_id' => 'nullable|integer',
            'order' => 'nullable|integer',
            'display' => 'nullable|integer',
        ];
    }
  1. 在 authorize 方法內設定是否要有權限驗證, 可以直接回傳 ture 表示通過驗證(預設是 false)
    public function authorize()
    {
        return true;
    }
  1. 設定額外的驗證可以覆寫 withValidator 方法
    public function withValidator($validator)
    {
        $validator->after(function($validator){
            if( $price < $market_price ) {
                $validator->errors()->add('price', '建議售價需大於售價');
            }
        });
    }
  1. 其他設定

    • 設定是否再遇到第一次錯誤時就終止並回傳結果
        protected $stopOnFirstFailure = true;
    
    • 設定發生錯誤時要導向的頁面
        // 使用路徑設定
        protected $redirect = '/errorMessage';
    
        // 使用路由名稱設定
        protected $redirectRoute = 'errorMessage';
    
  2. Contorller 內取得驗證後的值

    // 取得所有通過驗證的值
    $validated = $request->validated();
    
    // 取回部分通過驗證的值
    $validated = $request->safe()->only(['name', 'email']);
    $validated = $request->safe()->except(['name', 'email']);
  1. 覆寫 messages 方法設定自訂錯誤訊息
    public function messages()
    {
        return [            
            'productImg.*.mimes' => '僅能上傳格視為 jpg,jpeg,png 圖片',
            'productImg.*.max' => '圖片最大尺寸為 2MB',
            'category_name_parent.string' => '全站類別名稱須為文字',
            'category_parent.integer' => '全站類別id必須為數字',
            'category_name_childen.string' => '全站子類別名稱須為文字',
            'category_childen.integer' => '全站子類別id必須為數字',
            'spec_parent_name.*.string' => '規格分類名稱須為文字',
            'spec_parent.*.integer' => '規格分類id須為數字',
            'spec_name_childen.*.string' => '規格子分類名稱須為文字',
            'spec_childen.*.integer' => '規格子分類id須為數字',
            'spec_reserve.*.integer' => '庫存必須為數字',
            'spec_reserve.*.min' => '庫存數須大於等於 :min',
            'spec_low_reserve.*.integer' => '最小警告值須為數字',
            'spec_low_reserve.*.min' => '最小警告值須大於等於 :min',
            'spec_volume.*.string' => '材積須為數字',
            'spec_volume.*.max' => '材積值長度最大為 :max',
            'spec_weight.*.string' => '重量須為文字',
            'spec_weight.*.max' => '重量最大長度須為 :max',
            'spec_order.*.integer' => '排序值須為數字',
        ];
    }
  1. 覆寫 attributes 方法設定回傳欄位名稱
    public function attributes()
    {
        return [
            'name' => '類別名稱',
            'parent_id' => '父階層',
            'order' => '排序',
            'display' => '是否顯示於前台選單'
        ];
    }
  1. 覆寫 prepareForValidation 方法設定在驗證前要做的事情, e.g. 調整輸入值
    protected function prepareForValidation()
    {
        $this->merge([
            'name' => trim($this->name),
        ]);
    }

三、Validator(驗證器)

  1. 可以在 Controller 使用 Validator::make 方法產稱驗證器
    • 第一個參數: 輸入值
    • 第二個參數: 驗證規則
    • 第三個參數: 自訂錯誤訊息
    • 第四個參數: 自訂欄位名稱
    $rules = [
        'name' => [
            'required', 
            Rule::unique('pj_data_type')->ignore($id), 
            'max:255'
        ],
        'icon' => 'nullable|string',
        'disabled' => 'nullable|boolean',
        'router_path' => 'nullable|string',
    ];
    
    $validator = Validator::make($input, $rules);
  1. 執行 fails 方法判斷驗證是否成功
    if($validator->fails()){
        // 若失敗要執行的動作, e.g. 返回上一頁並傳遞錯誤訊息與使用者輸入欄位值
        return back()->withErrors($validator)->withInput($input);
    }
  1. 使用 after() 方法設定額外的驗證
    $validator->after(function ($validator) {
        // ... 另外要驗證內容
    }
});

上一篇
Day30. Vue 整理
下一篇
Day 32. HTTP Tests
系列文
laravel+vue 學習32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言