客製化 Laravel-Validation 的一些小技巧

客製化 Laravel-Validation 的一些小技巧

客製化 Laravel-Validation 的一些小技巧

這篇其實算是筆記類的文章,官網對於客製化Validation已經有很多的著墨了,這邊要筆記的內容主要是Extension這一塊。

前陣子有一個需求是這樣的:需要驗證是否為資料庫內Unique雙欄位的唯一值。舉例來說:一個店家,可以對應到一個客人的email資訊(這邊應該要用正規劃處理store_id-user_id,例子不太好不過就先將就一下吧~)所以對一個店家而言不能有重複的email, 但是如果是在別的店家可以有該email,如果在Laravel的Migration schma內應該會長這樣

Schema::create('store_info', function (Blueprint $table) {
//...
$table->integer('store_id');
$table->string('email');
$table->unique(['store_id', 'email']);
//...
}

在官網的資料裡面,如果是唯一值可以用unique

unique:table,column,except,idColumn

但是因為我是關聯到另一個值,所以不適用。

後來上網找到一個套件:felixkiss/uniquewith-validator,正當筆者興高采烈的按了 star之類下載來用,發現奇怪怎麼沒用!!??後來找了很久不知道是哪裡設定錯了…後來還是決定自己來刻一個好了。(筆者的狀況此例有點像)。

實作

首先是Extension官網建議放在Service Provider內。不過筆者個人是建議放在Request內,基於兩個原因。

  1. 把該Extension放在使用的地方,比較一目了然的知道要如何用。(當然前提是這個Extension只在一個地方使用)

  2. 剛好Request提供了prepareForValidationmessages方法來處理幫助我們處理validation,這根本就是設計好的嘛(誤)

所以假設我們的input 是['email' => 'abc@gmail.com'],並且做一個validation叫做unique_with_email。我們這邊需要先知道extend長什麼樣子

Validator::extend('YOUR_VALIDATION_NAME', function($attribute, $value, $parameters, $validator){
    
})
  • YOUR_VALIDATION_NAME:就是validation本身的名稱,此例為(unique_with_store)

  • $attribute:這個驗證輸入的Key(Attribute)值,此例為email

  • $value:傳入的值,此例為abc@gmail.com

  • $parameters:這邊在validation 後面可以加一些參數,可以用陣列方式取得,例如unique_with_store:1,我們就可以用$parameters[0]取得1。

  • $validator:這邊不會用到,先略過。

message內可以定義若是驗證失敗回傳的內容,其中可以用:attribute取得$attribute, :values取得$value

所以在Request內

<?php

namespace App\Http\Requests\Store;

use Illuminate\Http\Request;

class EmailStoreRequest extends Request;
{
    public function prepareForValidation()
    {
        $storeId = Store::find($id);//這邊僅舉例找到store_id
        $exit = \Validator::extend('unique_with_store', function ($attribute, $value, $parameters, $validator) use ($storeId){
            $exist = \DB::table('store')->where('store_id', $storeId)
                                ->where($attribute, $value)//email, abc@gmail.com
                                ->where('id', '!=', $parameters[0])//本身重複沒有關係。
                                ->count();
            return $exist === 0;
        });
    }

    public function rules()
    {
        $id = $this->id;
        return [
            'id' => 'required|int',
            'email' => "required|string|unique_with_store:$id",
        ];
    }

    public function attributes()
    {
        return [
            'id' => '店家編號',
            'email' => '客人email',
        ];
    }

    public function messages()
    {
        return [
            'unique_with_store' => ' :attribute 應該要是唯一值' //若錯誤會出現 email應該要是唯一值
        ];
    }
}