思考
我發(fā)現(xiàn)大多數(shù)的Laravel用戶會將驗證規(guī)則寫在Controller下,但這會有一個問題,使代碼雜亂且無法復(fù)用相同的規(guī)則。在CRUD為主的項目中,我們會發(fā)現(xiàn)好多字段以及它們的驗證規(guī)則是相同的,我們一般會化身為CV工程師,再復(fù)制一份,那么為什么不加一層驗證層?
伴隨這個問題,然后去看了別的開源項目的代碼,發(fā)現(xiàn)TP用戶的驗證會放在一個單獨的類中,并且有驗證場景來支持他們復(fù)用規(guī)則,于是我尋找Laravel中有沒有對應(yīng)的解決方案,然后發(fā)現(xiàn)了微擎的一個驗證器w7/engine-validate,接下里的文章就依賴此擴展來講如何增加一個驗證層
安裝
composer require w7/engine-validate
介紹
首先此驗證器也是基于illuminate/validation的,關(guān)于它的詳細說明可以直接查看它的文檔,這里就不過多說明了。
使用
首先我們建立一個和控制器相對應(yīng)的驗證層
app ├── Http │ ├── Controllers │ │ └── UserController.php │ └── Validate │ └── UserValidate.php
驗證器
驗證器代碼:
class UserValidate extends Validate{ protected $rule = [ 'user' => 'required|email', 'pass' => 'required|alpha_num' ]; protected $message = [ 'user.required' => '賬號不可為空', 'pass.required' => '密碼不可為空', ]; protected $customAttributes = [ 'user' => '賬號', 'pass' => '密碼', ]; }
控制器代碼:
class UserController extends BaseController{ use AuthorizesRequests, DispatchesJobs, ValidatesRequests; public function login(Request $request) { $data = UserValidate::make()->check($request->all()); } }
這個時候,如果值不符合要求,會拋出一個ValidateException異常,我們可以選擇手動捕獲,也可以選擇在異常捕獲類里面做一個全局的處理:
public function render($request, Throwable $e) { if ($e instanceof ValidateException) { return response()->json([ 'code' => -1, 'message' => $e->getMessage() ]); } return parent::render($request, $e); }
這樣我們就不需要再控制器里面管理任何的驗證異常了。
此時,控制器中的$data一定是符合我們需求的數(shù)據(jù),然后可以緊接著做對應(yīng)的業(yè)務(wù)處理
驗證場景
這個時候,如果我們的UserController控制器中又添加了一個register方法,在以上兩個字段的需求同時增加了name,應(yīng)該如何處理呢?
我們可以使用類的$scene屬性來指定某一場景下需要驗證的字段
驗證器代碼修改如下:
class UserValidate extends Validate{ protected $rule = [ 'user' => 'required|email', 'pass' => 'required|alpha_num', 'name' => 'required|alpha' ]; protected $message = [ 'user.required' => '賬號不可為空', 'pass.required' => '密碼不可為空', ]; protected $customAttributes = [ 'user' => '賬號', 'pass' => '密碼', 'name' => '用戶名稱', ]; protected $scene = [ 'login' => ['user', 'pass'], 'register' => ['user', 'pass', 'name'] ]; }
此時:login場景對應(yīng)的驗證user和pass字段,而register場景對應(yīng)的驗證user,pass,name字段
控制器代碼修改如下:
class UserController extends BaseController{ use AuthorizesRequests, DispatchesJobs, ValidatesRequests; public function login(Request $request) { $data = UserValidate::make()->scene('login')->check($request->all()); } public function register(Request $request) { $data = UserValidate::make()->scene('register')->check($request->all()); } }
使用驗證器的scene方法來指定當前需要驗證的場景名稱
驗證中間件
默認我們一個控制器對應(yīng)一個驗證器,一個方法對應(yīng)一個場景名稱,基于此特點,我們可以編寫一些更為簡易的方法來解決驗證,我們可以編寫一個中間件來解決此問題,點擊查看文檔說明,中間件完整命名空間為:Itwmw\Validate\Middleware\Laravel\ValidateMiddleware
中間件設(shè)置
首先我們需要為他指定控制器和驗證器的對應(yīng)關(guān)系,在app/Providers目錄下新建一個ValidateServiceProvider.php文件,寫入如下代碼:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Itwmw\Validate\Middleware\ValidateMiddlewareConfig; class ValidateServiceProvider extends ServiceProvider{ public function register() { ValidateMiddlewareConfig::instance() ->setAutoValidatePath('App\\Http\\Controllers\\', 'App\\Http\\Validate\\'); } }
其中setAutoValidatePath
為指定控制器和驗證器的對應(yīng)關(guān)系,可以設(shè)定多個,不限制數(shù)量,然后我們將ValidateServiceProvider
注冊一下,在config/app.php
文件中找到providers
,在其中添加App\Providers\ValidateServiceProvider::class
注意:不可以放在Illuminate\Validation\ValidationServiceProvider::class之前
使用中間件
這個時候,我們可以將中間件注冊為全局中間件,也可以不注冊,注冊方法:中間件《Laravel 7 中文文檔》
定義路由:
Route::middleware(ValidateMiddleware::class)->group(function () { Route::any('/login', [\App\Http\Controllers\UserController::class, 'login']); Route::any('/register', [\App\Http\Controllers\UserController::class, 'register']); });
控制器代碼修改如下:
class UserController extends BaseController{ use AuthorizesRequests, DispatchesJobs, ValidatesRequests; public function login(Request $request) { $data = get_validate_data($request); } public function register(Request $request) { $data = get_validate_data($request); } }
這個時候,我們就不需要手動指定驗證器已經(jīng)場景名了,中間件會自動處理對應(yīng)的驗證規(guī)則,我們只需要使用get_validate_data方法來接收值即可。
結(jié)尾
此文章只寫了這個擴展的一些基本用法,還有更多的功能,需要大家自己看看文檔,來完成自己合適的驗證層。