為你的 Laravel 驗證器加上多驗證場景

割了動脈喝脈動發表於2020-04-06

前言
在我們使用laravel框架的驗證器,有的時候需要對錶單等進行資料驗證,當然laravel也為我們提供了
Illuminate\Http\Request 物件提供的 validate 方法 以及FormRequestValidator

FormRequest通過新建檔案將我們的驗證部分單獨分開,來避免控制器臃腫。如果驗證失敗,就會生成一個讓使用者返回到先前的位置的重定向響應。這些錯誤也會被快閃記憶體到 Session 中,以便這些錯誤都可以在頁面中顯示出來。如果傳入的請求是 AJAX,會向使用者返回具有 422 狀態程式碼和驗證錯誤資訊的 JSON 資料的 HTTP 響應。如果是介面請求或ajax,那麼我們可能還需要將返回的json資料修改成我們想要的格式。
當我們實際開發中,可能一個模組需要有多個驗證場景,如果為每一個驗證場景都新建一個FormRequest不就太過繁瑣了。
那麼給laravel加上一個驗證場景通過一個驗證類一個模組或多個模組來適應不同的場景不就方便很多了。

開始
首先 我們封裝了一個基類 BaseValidate.php並將其放在 app\Validate下,當然你也可以放在其他地方,只要修改好名稱空間就好。

<?php
namespace App\Validate;

use Illuminate\Support\Facades\Validator;
/**
 * 擴充套件驗證器
 */
class BaseValidate {

    /**
     * 當前驗證規則
     * @var array
     */
    protected $rule = [];

    /**
     * 驗證提示資訊
     * @var array
     */
    protected $message = [];

    /**
     * 驗證場景定義
     * @var array
     */
    protected $scene = [];

    /**
     * 設定當前驗證場景
     * @var array
     */
    protected $currentScene = null;

    /**
     * 驗證失敗錯誤資訊
     * @var array
     */
    protected $error = [];

    /**
     * 場景需要驗證的規則
     * @var array
     */
    protected $only = [];


    /**
     * 設定驗證場景
     * @access public
     * @param  string  $name  場景名
     * @return $this
     */
    public function scene($name)
    {
        // 設定當前場景
        $this->currentScene = $name;

        return $this;
    }

    /**
     * 資料驗證
     * @access public
     * @param  array     $data  資料
     * @param  mixed     $rules  驗證規則
     * @param  array    $message 自定義驗證資訊
     * @param  string    $scene 驗證場景
     * @return bool
     */
    public function check($data, $rules = [], $message = [],$scene = '')
    {
        $this->error =[];
        if (empty($rules)) {
            //讀取驗證規則
            $rules = $this->rule;
        }
        if (empty($message)) {
            $message = $this->message;
        }

        //讀取場景
        if (!$this->getScene($scene)) {
            return false;
        }

        //如果場景需要驗證的規則不為空
        if (!empty($this->only)) {
            $new_rules = [];
            foreach ($this->only as $key => $value) {
                if (array_key_exists($value,$rules)) {
                    $new_rules[$value] = $rules[$value];
                }    
            }
            $rules = $new_rules;
        }
        // var_dump($rules);die;
        $validator = Validator::make($data,$rules,$message);
        //驗證失敗
        if ($validator->fails()) {
            $this->error = $validator->errors()->first();
            return false;
        }

        return !empty($this->error) ? false : true;
    }

    /**
     * 獲取資料驗證的場景
     * @access protected
     * @param  string $scene  驗證場景
     * @return void
     */
    protected function getScene($scene = '')
    {
        if (empty($scene)) {
            // 讀取指定場景
            $scene = $this->currentScene;
        }
        $this->only = [];

        if (empty($scene)) {
            return true;
        }

        if (!isset($this->scene[$scene])) {
            //指定場景未找到寫入error
            $this->error = "scene:".$scene.'is not found';
            return false;
        }
        // 如果設定了驗證適用場景
        $scene = $this->scene[$scene];
        if (is_string($scene)) {
            $scene = explode(',', $scene);
        }
        //將場景需要驗證的欄位填充入only
        $this->only = $scene;
        return true;
    }

    // 獲取錯誤資訊
    public function getError()
    {
        return $this->error;
    }



}

使用
接下來我們來驗證一個文章的提交資訊,首先我們新建一個文章驗證類ArticleValidate.php並填充一些內容

<?php
namespace App\Validate;

use App\Validate\BaseValidate;
/**
 * 文章驗證器
 */
class ArticleValidate extends BaseValidate {
    //驗證規則
    protected $rule =[
        'id'=>'required',
        'title' => 'required|max:255',
        'content' => 'required',
    ];
    //自定義驗證資訊
    protected $message = [
        'id.required'=>'缺少文章id',
        'title.required'=>'請輸入title',
        'title.max'=>'title長度不能大於 255',
        'content.required'=>'請輸入內容',
    ];

    //自定義場景
    protected $scene = [
        'add'=>"title,content",
        'edit'=> ['id','title','content'],
    ];
}

如上所示,在這個類中我們定義了驗證規則rule,自定義驗證資訊message,以及驗證場景scene

非場景驗證

我們只需要定義好規則

public function update(){

        $ArticleValidate = new ArticleValidate;

        $request_data = [
            'id'=>'1',
            'title'=>'我是文章的標題',
            'content'=>'我是文章的內容',
        ];

        if (!$ArticleValidate->check($request_data)) {
           var_dump($ArticleValidate->getError());
        }

    }

check 方法中總共有四個引數,第一個要驗證的資料,第二個驗證規則,第三個自定義錯誤資訊,第四個驗證場景,其中2,3,4非必傳。
如果驗證未通過我們呼叫getError()方法來輸出錯誤資訊,getError()暫不支援返回所有驗證錯誤資訊

場景驗證
我們需要提前在驗證類中定義好驗證場景
如下,支援使用字串或陣列,使用字串時,要驗證的欄位需用,隔開

//自定義場景
    protected $scene = [
        'add'=>"title,content",
        'edit'=> ['id','title','content'],
    ];

然後在我們的控制器進行資料驗證

public function add(){

        $ArticleValidate = new ArticleValidate;

        $request_data = [
            'title'=>'我是文章的標題',
            'content'=>'我是文章的內容',
        ];

        if (!$ArticleValidate->scene('add')->check($request_data)) {
           var_dump($ArticleValidate->getError());
        }

    }

控制器內驗證
當然我們也允許你不建立驗證類來驗證資料,

public function add(){

        $Validate = new BaseValidate;

        $request_data = [
            'title'=>'我是文章的標題',
            'content'=>'我是文章的內容',
        ];

        $rule =[
            'id'=>'required',
            'title' => 'required|max:255',
            'content' => 'required',
        ];
        //自定義驗證資訊
        $message = [
            'id.required'=>'缺少文章id',
            'title.required'=>'請輸入title',
            'title.max'=>'title長度不能大於 255',
            'content.required'=>'請輸入內容',
        ];

        if (!$Validate->check($request_data,$rule,$message)) {
           var_dump($Validate->getError());
        }

    }

通過驗證場景,既減少了控制器程式碼的臃腫,又減少了FormRequest檔案過多,還可以自定義json資料是不是方便多了呢,
參考文件
laravel表單驗證 :表單驗證《Laravel 5.5 中文文件》
thinkphp驗證場景 :https://www.kancloud.cn/manual/thinkphp5_1...

本文為楊攀遙原創文章,如若轉載,無需和我聯絡,但請註明出處[楊攀遙的部落格]:https://www.yangpanyao.com/archives/120.ht...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章