背景

Laravel 提供的主动表单验证申请类,通常一个 class 是利用到一个 Action 上的,虽说能够利用到多个 Action 上,但验证参数很少说齐全一样,粒度太细了,如果一个 Controller 有 10 个 Action 那就得对应创立10个验证规定类,会导致文件太多,所以能够封装一下 Request ,把粒度由 Action 变成 Controller 级别得粒度,这样一个 Controller 就只用创立一个表单申请类了, 实现成果如下,后果都统一:

原有验证形式

创立验证规定

app/Http/Requests

├── Requests│   ├── DeleteBlog.php│   ├── StoreBlog.php│   └── UpdateBlog.php

为了不便展现,放在了一个文件内

namespace App\Http\Requests;use Illuminate\Foundation\Http\FormRequest;class StoreBlogRequest extends FormRequest {    public function rules() {        return [            'title'   => 'required|max:100',            'content' => 'required|max:1000'        ];    }        public function messages() {return []; }}class UpdateBlogRequest extends FormRequest {    public function rules() {        return [            'id'      => 'required|integer',            'title'   => 'required|max:100',            'content' => 'required|max:1000'        ];    }        public function messages() {return []; }}class DeleteBlogRequest extends FormRequest {    public function rules() {        return [            'id' => 'required|integer',        ];    }        public function messages() {return []; }}

应用验证规定

app/Http/Comtrollers/PostController

namespace App\Http\Controllers;use App\Http\Requests\DeleteBlogRequest;use App\Http\Requests\StoreBlogRequest;use App\Http\Requests\UpdateBlogRequest;class PostsController{    public function store(StoreBlogRequest $request) { /*...*/ }    public function update(UpdateBlogRequest $request) { /*...*/ }    public function delete(DeleteBlogRequest $request) { /*...*/ }}

问题

3 个接口别离对应 StoreBlogRequest UpdateBlogRequest DeleteBlogRequest ,30个接口得对应30个 XxxRequest 文件太多。

封装

想法是一个 Controller 对应一个 RequestRequest 辨认须要的返回的 Rules

达到的成果

class BlogController extends Controller{    // BlogRequest 主动验证 store 规定    public function store(BlogRequest $request) { /*...*/ }    // BlogRequest 主动验证 update 规定    public function update(BlogRequest $request) { /*...*/ }    // BlogRequest 主动验证 delete 规定    public function delete(BlogRequest $request) { /*...*/ }}

实现办法

namespace App\Http\Requests;class BlogRequest extends FormRequest{    public function rules() {        // 获取申请对应的ActionMethod(); e.g. store/update/delete        $actionMethod = $this->route()->getActionMethod();        if (!method_exists($this, $actionMethod)) {            return [];        }        // e.g. $this->>store();        return $this->$actionMethod();    }    public function store() {        return [            'title'   => 'required|max:100',            'content' => 'required|max:1000'        ];    }    public function delete() {        return [            'id' => 'required|integer',        ];    }}

这样就能够通过定义一个Request 规定对应一个 Controller

但问题紧接着也来了,如果要定义自定义 message authorize 怎么实现呢?

依据下面的实现形式,能够形象出一个 BaseRequest 去继承 FormRequest 重写对应的办法,而后自定义的 Request 再继承 BaseRequest 专一定义验证规定即可

BaseRequest

class BaseRequest extends FormRequest {    public function authorize(): bool {        $actionMethod = $this->route()->getActionMethod() . 'Authorize';        if (!method_exists($this, $actionMethod)) {            return true;        }        return $this->$actionMethod();    }    public function rules(): array {        $actionMethod = $this->route()->getActionMethod() . 'Rules';        if (!method_exists($this, $actionMethod)) {            return [];        }        return $this->$actionMethod();    }    public function messages(): array {        $actionMethod = $this->route()->getActionMethod() . 'Messages';        if (!method_exists($this, $actionMethod)) {            return [];        }        return $this->$actionMethod();    }}

能够看到,在 BaseRequest 中,办法以 ActionMethod + 规定 实现

BlogRequest

class BlogRequest extends BaseRequest {    public function storeRules() {        return ['title' => 'required|max:100', 'content' => 'required|max:1000'];    }    public function storeMessages() {        return ['title.required' => '题目不能为空', 'content.required' => '内容不能为空'];    }    public function updateRules() {        return ['id' => 'required|integer', 'title' => 'max:100', 'content' => 'max:1000'];    }    public function deleteRules() {        return ['id' => 'required|integer',];    }    public function deleteAuthorize() {        return false;    }}

BolgController

class BlogController extends Controller{    // BlogRequest 主动验证 store 规定    public function store(BlogRequest $request) { /*...*/ }        // BlogRequest 主动验证 update 规定    public function update(BlogRequest $request) {        return response()->json([            'status'  => 200,            'message' => 'success',        ],200, [], JSON_UNESCAPED_UNICODE);    }        // BlogRequest 主动验证 delete 规定    public function delete(BlogRequest $request) { /*...*/ }}

启动服务验证: php artisan serve

$ curl -s -d 'title=test' -X POST '127.0.0.1:8000/api/blog/after/store' | jq .{  "status": 400,  "message": "内容不能为空"}$ curl -s -d 'id=1' -X POST '127.0.0.1:8000/api/blog/after/update' | jq .{  "status": 200,  "message": "success"}$ curl -s -d 'id=1' -X POST '127.0.0.1:8000/api/blog/after/delete' | jq .{  "status": 403,  "message": "您没有权限拜访" // 为什么信息是这个,上面会说到。}

当然,你还能够在 BaseReqeust 中定义谬误返回格局等

/** 参数验证失败返回解决 */protected function failedValidation(Validator $validator): HttpResponseException{    $actionMethod = $this->route()->getActionMethod() . 'FailedValidation';    // 应用自定义谬误格局,但通常不会在具体规定类外面重写,因为谬误格局应该要保持一致    // 或者须要与内部零碎交互之类非凡状况就就能够重写此办法    if (method_exists($this, $actionMethod)) {        $this->$actionMethod();    }    // 默认谬误格局    $err = $validator->errors()->first();    throw new HttpResponseException(response()->json([        'status'  => 400,        'message' => $err,    ], 400, [], JSON_UNESCAPED_UNICODE));}

申请受权验证未通过时

/** 申请受权验证未通过时(authorize办法 return false; 未通过时) */protected function failedAuthorization(){    $actionMethod = $this->route()->getActionMethod() . 'FailedAuthorization';    if (method_exists($this, $actionMethod)) {        return $this->$actionMethod();    }    throw new HttpResponseException(response()->json([        'status'  => 403,        'message' => '您没有权限拜访',    ], 403, [], JSON_UNESCAPED_UNICODE));}

总结

  1. 这样就能够实现一个 Controller 对应一个 Request 了,不过有利有弊,缩小了文件数量的同时带来的就是批改对应规定的时候须要找到对应的规定。
  2. failedValidationfailedAuthorization 对立返回谬误格局也能够通过判断他们 Exception 来实现,因为它们别离抛出的异样是 ValidationExceptionAuthorizationException
  3. 文档只能看简略的应用办法,遇到问题得多去下层看看源码,找到些另辟蹊径的解决办法。

Code

./app/Http/Controllers├── Controllers│   ├── AfterBlogController.php│   ├── BeforeBlogController.php│   ├── ..../app/Http/Requests├── Requests│   ├── BaseRequest.php│   ├── BlogRequest.php│   ├── DeleteBlogRequest.php│   ├── StoreBlogRequest.php│   └── UpdateBlogRequest.php

Route

$ php artisan route:list | grep "blog"POST | api/blog/after/delete POST | api/blog/after/store  POST | api/blog/after/update POST | api/blog/before/deletePOST | api/blog/before/store POST | api/blog/before/update

github.com

https://github.com/zxr615/rewrite-pay-module/tree/main/app/Http/Controllers