laravel在中间件进行参数校验

laravel有自己的几种参数校验实现,下面是我自己封装的,参照aop思想将参数校验集合到中间件中的实现过程。

1创建验证器基类
# ./app/Validator/BaseValidator.php
namespace App\Validator;

use App\Exceptions\DevException;
use Illuminate\Http\Request;

abstract class BaseValidator
{
    /**
     * 当前访问路由
     * @var
     */
    protected $uri;

    /**
     * 验证器规则,key=>value,key为访问的路由,value为参数对应规则
     * @var array
     */
    protected $rules = [];

    protected $message = [];

    protected $attributes = [];

    protected $customRules = [];

    protected $request = null;

    public function __construct(string $uri, Request $request) {
        $this->uri = $uri;
        $this->request = $request;
        $this->makeCustomRules($this->request);
    }

    /**
     * 自定义规则在此地方注册
     * @param $request
     */
    abstract protected function makeCustomRules($request): void ;

    /**
     * 通过自定义规则名称获取验证函数
     * @param string $rule
     * @return callable
     * @throws DevException
     */
    protected function getCustomRules(string $rule): callable {
        if (!isset($this->customRules[$rule])) {
            throw new DevException(['msg' => "验证器自定义规则错误"]);
        }
        return $this->customRules[$rule];
    }

    /**
     * 设置自定义的验证规则
     * @param string $rule 规则名称
     * @param callable $ruleCall 规则验证回调函数
     * @throws DevException
     */
    protected function setCustomRules(string $rule, callable $ruleCall): void {
        if (isset($this->customRules[$rule])) {
            throw new DevException(['msg' => "验证器自定义规则重复了"]);
        }
        $this->customRules[$rule] = $ruleCall;
    }

    /**
     * 通用自定义规则:检查添加的某个字段是否已存在
     * @param $model
     * @param string $name
     * @throws DevException
     */
    protected function checkAddRepeat($model, $name="name") {
        $strName = ucwords($name);//将首字母字段转为大写,可以根据业务更换为转为驼峰命名
        $this->setCustomRules("checkAdd{$strName}Repeat", function ($attribute, $value, $fail)
        use ($model, $name) {
            if ($model::getOne([$name => $value])) {
                $fail($value.' 已存在。');
            }
        });
    }

    /**
     * 通用自定义规则:检查编辑的某个字段是否已存在
     * @param $model
     * @param string $name
     * @throws DevException
     */
    protected function checkEditRepeat($model, $name="name") {
        $request = $this->request;
        $strName = ucwords($name);//将首字母字段转为大写,可以根据业务更换为转为驼峰命名
        $this->setCustomRules("checkEdit{$strName}Repeat", function ($attribute, $value, $fail)
        use ($model, $name, $request) {
           	//根据字段+ID组合判断,可以根据具体业务修改
            if ($model::getOne([$name => $value, "id" => ["<>", $request->id]])) {
                $fail($value.' 已存在。');
            }
        });
    }

    /**
     * 获取规则
     * @return array
     */
    public function getRules() : array {
        if (isset($this->rules[$this->uri])) {
            return $this->rules[$this->uri];
        }
        return [];
    }

    /**
     * 获取自定义验证提示
     * @return array
     */
    public function getMessage() : array {
        return $this->message;
    }

    /**
     * 获取自定义属性描述
     * @return array
     */
    public function getCustomAttributes() : array {
        return $this->attributes;
    }
}
2根据业务场景创建具体实现验证器
# ./app/Validator/AdminValidator.php
namespace App\Validator;

use App\Models\Admin;
use Illuminate\Http\Request;

class AdminValidator extends BaseValidator
{
	protected $attributes = [
        'name' => '用户名',
        'password' => '密码',
        'description' => '描述',
        'selectRoles' => '绑定角色',
    ];

   protected $message = [
   		'required' => ':attribute 为必填项',
   ];
   
    public function __construct(string $uri, Request $request)
    {
        parent::__construct($uri, $request);
        
        //rules数组key值匹配到路由URL将直接生效验证
        $this->rules = [
            //获取管理员列表
            "admin/admins/getAdmins" => [
                'page' => 'required|Integer|min:1',
                'pageSize' => 'required|Integer|min:1',
            ],

            //添加管理员
            "admin/admins/add" => [
                'name' => [
                    'required',
                    'max:255',
                    $this->getCustomRules("checkAddNameRepeat")
                ],
                'description' => "required|String|min:6",
            ],

            //编辑管理员
            "admin/admins/edit" => [
                'name' => [
                    'required',
                    'max:255',
                    $this->getCustomRules("checkEditNameRepeat")
                ],
                'description' => "required|String|min:6",
            ],

            //删除管理员
            "admin/admins/del" => [
                'id' => [
                    "required",
                    'Integer',
                    'min:1',
                    $this->getCustomRules("checkIsSuper"),
                ]
            ],
        ];
    }

    /**
     * 自定义规则
     * @param $request
     * @throws \App\Exceptions\DevException
     */
    protected function makeCustomRules($request): void
    {
        //检查添加名称是否存在
        $this->checkAddRepeat(Admin::class);

        //检查编辑的名称是否存在
        $this->checkEditRepeat(Admin::class);

        //检查删除的角色是否为超级管理员
        $this->setCustomRules("checkIsSuper", function ($attribute, $value, $fail) {
            if ($value === 1) {
                $fail('该用户为超级管理权限,不能删除!');
            }
        });
    }
}
3创建中间件
# ./app/Http/Middleware/ParamsValidation.php
namespace App\Http\Middleware;

use App\Exceptions\DevException;
use App\Exceptions\ValidationException;
use Closure;
use Illuminate\Support\Facades\Validator;

class ParamsValidation
{
    /**
     * 校验前端传递参数是否合法
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @param $Rules String 验证器对象名,AuthValidator验证器则传递Auth字段
     * @return mixed
     * @throws DevException
     * @throws ValidationException
     */
    public function handle($request, Closure $next, $Rules)
    {
    	//验证器实现类
        $RulesClass = "\App\Validator\\{$Rules}Validator";
        if (!class_exists($RulesClass)) {
            throw new DevException();
        }
        $rules = new $RulesClass($request->route()->uri, $request);
        $validator = Validator::make(
            $request->input(),
            $rules->getRules(),
            $rules->getMessage(),
            $rules->getCustomAttributes()
        );
        if ($validator->fails()) {
            $messages = $validator->getMessageBag()->getMessages();
            $message = current($messages);
            if (is_array($messages)) {
                $message = current($message);
            }
            throw new ValidationException([
                'msg' => $message
            ]);
        }
        return $next($request);
    }
}
4注册中间件
# ./app/Http/Kernel.php
protected $routeMiddleware = [
    ...
    //表单参数验证
    'validator'    => \App\Http\Middleware\ParamsValidation::class,
];
5路由绑定验证器
# ./routes/web.php
// Admin 模块
Route::middleware('api.auth')->namespace('Admin')->prefix('admin')->group(function () {

   	//中间件validator传递参数Admin,标识匹配验证器./app/Validator/AdminValidator.php
    Route::middleware('validator:Admin')->prefix('/admins')->group(function () {
        // 获取管理员列表
        Route::get('getAdmins', 'AdminController@getAdmins');

        //添加管理员
        Route::post('add', 'AdminController@add');

        //编辑管理员
        Route::put('edit', 'AdminController@edit');

        //删除管理员
        Route::delete('del', 'AdminController@del');
    });
});

6参考项目

ReactAdmin-Laravel

你可能感兴趣的:(laravel在中间件进行参数校验)