共计 5593 个字符,预计需要花费 14 分钟才能阅读完成。
背景
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
对应一个Request
,Request
辨认须要的返回的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));
}
总结
- 这样就能够实现一个
Controller
对应一个Request
了,不过有利有弊,缩小了文件数量的同时带来的就是批改对应规定的时候须要找到对应的规定。 failedValidation
和failedAuthorization
对立返回谬误格局也能够通过判断他们Exception
来实现,因为它们别离抛出的异样是ValidationException
和AuthorizationException
。- 文档只能看简略的应用办法,遇到问题得多去下层看看源码,找到些另辟蹊径的解决办法。
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/delete
POST | api/blog/before/store
POST | api/blog/before/update
github.com
https://github.com/zxr615/rewrite-pay-module/tree/main/app/Http/Controllers