在`Laravel`中,每一个请求都会被封装为一个`Request`对象,`Form Request`对象就是包含了额外验证逻辑(以及访问权限控制)的自定义`Request`类。 本文分析了FormRequest异常的处理流程并提出了自定义处理FormRequest验证失败的思路。
所有示例基于Laravel 5.1.39 (LTS)
今天天气不错,我们来说说表单验证。
Controller中做表单验证
有的同学把表单验证逻辑写在Controller中,例如这个对用户提交评论内容的验证:
<?php // ... use Validator; class CommentController { public function postStoreComment(Request $request) { $validator = Validator::make($request->all(), [ 'comment' => 'required', // 只是实例,就写个简单的规则,你的网站要是这么写欢迎在评论里贴网址 ]); if ($validator->fails()) { return redirect() ->back() ->withErrors($validator) ->withInput(); } }
这样写的话,表单验证和业务逻辑挤在一起,我们的Controller中就会有太多的代码,而且重复的验证规则基本也是复制粘贴。
我们可以利用Form Request来封装表单验证代码,从而精简Controller中的代码逻辑,使其专注于业务。而独立出去的表单验证逻辑甚至可以复用到其它请求中,例如修改评论。
什么是Form Request
在Laravel中,每一个请求都会被封装为一个Request对象,Form Request对象就是包含了额外验证逻辑(以及访问权限控制)的自定义Request类。
如何使用Form Request做表单验证
Laravel提供了生成Form Request的Artisan命令:
<code>$ php artisan make:request StoreCommentRequest</code>
于是就生成了app/Http/Requests/StoreCommentRequest.php,让我们来分析一下内容:
<?php namespace App\Http\Requests; use App\Http\Requests\Request; // 可以看到,这个基类是在我们的项目中的,这意味着我们可以修改它 class StoreCommentRequest extends Request { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() // 这个方法可以用来控制访问权限,例如禁止未付费用户评论… { return false; // 注意!这里默认是false,记得改成true } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() // 这个方法返回验证规则数组,也就是Validator的验证规则 { return [ // ]; } }
那么很容易,我们除了让authorize方法返回true之外,还得让rules方法返回我们的验证规则:
<?php // ... public function rules() { return [ ]; } // ...
接着修改我们的Controller:
<?php // ... // 之前:public function postStoreComment(Request $request) public function postStoreComment(\App\Http\Requests\StoreCommentRequest $request) { // ... } // ...
这样Laravel便会自动调用StoreCommentRequest进行表单验证了。
异常处理
如果表单验证失败,Laravel会重定向到之前的页面,并且将错误写到Session中,如果是AJAX请求,则会返回一段HTTP状态为422的JSON数据,类似这样:
<code>{comment: ["The comment field is required."]}</code>
这里就不细说提示信息怎么修改了,如果有人想看相关教程,可以留言。
我们主要来说说怎么定制错误处理。
通常来说,Laravel中的错误都是异常(Exception),我们都可以在app\Exceptions\handler.php中进行统一处理。Form Request确实也抛出了一个Illuminate\Http\Exception\HttpResponseException异常,但这个异常是在路由逻辑中就被特殊处理了。
首先我们来看看Form Request是如何被执行的:
Illuminate\Validation\ValidationServiceProvider:
<?php namespace Illuminate\Validation; use Illuminate\Support\ServiceProvider; use Illuminate\Contracts\Validation\ValidatesWhenResolved; class ValidationServiceProvider extends ServiceProvider { /** * Register the service provider. * * @return void */ public function register() { $this->registerValidationResolverHook(); // 看我看我看我 $this->registerPresenceVerifier(); $this->registerValidationFactory(); } /** * Register the "ValidatesWhenResolved" container hook. * * @return void */ protected function registerValidationResolverHook() // 对,就是我 { // 这里可以看到对`ValidatesWhenResolved`的实现做了一个监听 $this->app->afterResolving(function (ValidatesWhenResolved $resolved) { $resolved->validate(); // 然后调用了它的`validate`方法进行验证 }); } // ...
你猜对了,Form Request就实现了这个Illuminate\Contracts\Validation\ValidatesWhenResolved接口: