基於不破壞框架原本用法、方便、簡單的原則,實現路由場景驗證和控制器場景驗證。
建立 app\Http\Requests\SceneValidator.php
trait
<?php
namespace App\Http\Requests;
trait SceneValidator
{
//場景
protected $scene = null;
//是否自動驗證
protected $autoValidate = true;
protected $onlyRule=[];
/**
* 覆蓋 ValidatesWhenResolvedTrait 下 validateResolved 自動驗證
*/
public function validateResolved()
{
if(method_exists($this,'autoValidate')){
$this->autoValidate = $this->container->call([$this, 'autoValidate']);
}
if ($this->autoValidate) {
$this->handleValidate();
}
}
/**
* 複製 ValidatesWhenResolvedTrait -> validateResolved 自動驗證
*/
protected function handleValidate()
{
$this->prepareForValidation();
if (! $this->passesAuthorization()) {
$this->failedAuthorization();
}
$instance = $this->getValidatorInstance();
if ($instance->fails()) {
$this->failedValidation($instance);
}
}
/**
* 定義 getValidatorInstance 下 validator 驗證器
* @param $factory
* @return mixed
*/
public function validator($factory)
{
return $factory->make($this->validationData(), $this->getRules(), $this->messages(), $this->attributes());
}
/**
* 驗證方法(關閉自動驗證時控制器呼叫)
* @param string $scene 場景名稱 或 驗證規則
*/
public function validate($scene)
{
if(!$this->autoValidate){
if(is_array($scene)){
$this->onlyRule = $scene;
}else{
$this->scene = $scene;
}
$this->handleValidate();
}
}
/**
* 獲取 rules
* @return array
*/
protected function getRules()
{
return $this->handleScene($this->container->call([$this, 'rules']));
}
/**
* 場景驗證
* @param array $rule
* @return array
*/
protected function handleScene(array $rule)
{
if($this->onlyRule){
return $this->handleRule($this->onlyRule,$rule);
}
$sceneName = $this->getSceneName();
if($sceneName && method_exists($this,'scene')){
$scene = $this->container->call([$this, 'scene']);
if(array_key_exists($sceneName,$scene)) {
return $this->handleRule($scene[$sceneName],$rule);
}
}
return $rule;
}
/**
* 處理Rule
* @param $sceneRule
* @param $rule
* @return array
*/
private function handleRule(array $sceneRule,array $rule)
{
$rules = [];
foreach ($sceneRule as $key => $value) {
if (is_numeric($key) && array_key_exists($value,$rule)) {
$rules[$value] = $rule[$value];
} else {
$rules[$key] = $value;
}
}
return $rules;
}
/**
* 獲取場景名稱
*
* @return string
*/
protected function getSceneName()
{
return is_null($this->scene) ? $this->route()->getAction('_scene') : $this->scene;
}
}
在 app\Providers\AppServiceProvider.php
boot 方法裡面新增
use Illuminate\Routing\Route;
//Route 路由自定義scene(場景方法)
Route::macro('scene',function ($scene=null){
$action = Route::getAction();
$action['_scene'] = $scene;
Route::setAction($action);
});
該自定義方法用於路由場景驗證,在 Route->action
增加一個 _scene
屬性;用法跟 路由別名 name
一樣:
Route::post('add','UserController@add')->scene('add');
Tip:如果不需要路由場景驗證,則不用新增。
在驗證類內裡 use SceneValidator
;
例如下面 UserRequest 驗證類
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
use SceneValidator;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|unique:users',
'email' => 'required|email|unique:users',
];
}
/**
* 場景規則
* @return array
*/
public function scene()
{
return [
//add 場景
'add' => [
'name' , //複用 rules() 下 name 規則
'email' => 'email|unique:users' //重置規則
],
//edit場景
'edit' => ['name'],
];
}
}
在驗證類裡面新增scene
方法
/**
* 場景規則
* @return array
*/
public function scene()
{
// 格式 ['場景名' => [規則]]
return [
//add 場景
'add' => [
'name', //複用 rules() 下 name 規則
'email' => 'email|unique:users' //重置規則
],
//edit場景
'edit' => ['name'],
];
}
在驗證類裡面新增 autoValidate
方法來控制自動驗證; true:開啟 | false:關閉
預設開啟。
/**
* 設定是否自動驗證
* @return bool
*/
public function autoValidate(){
return false; //關閉
}
可以根據不同需求開啟和關閉靈活控制;比如某些場景下關閉
public function autoValidate(){
$sceneName = $this->getSceneName();
if(in_array($sceneName,['add'])){ //add 場景下關閉自動驗證
return false;
}
}
Route::post('create','UserController@create');
Route::post('add','TestController@add')->scene('add');
Tip:控制器場景驗證需要 關閉自動驗證 ,通過
validate('場景名')
來調起驗證;優先順序: 控制器場景驗證 > 路由場景驗證
public function add(UserRequest $request){
$request->validate('add');
}
支援全部驗證 、獨立驗證規則
//全部驗證 rules()下規則
$request->validate();
// 獨立傳驗證規則
$request->validate( [
'name', //複用 rules() 下 name 規則
'email' => 'email|unique:users' //重置規則
]);
一直沒有找到自己理想的場景驗證,於是整理了這套場景驗證,供參考;
如有更好的場景驗證,求分享學習下;
由於第一次寫有不足的地方,請各位諒解!