<?php namespace Illuminate\Foundation\Http; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Http\JsonResponse; use Illuminate\Routing\Redirector; use Illuminate\Container\Container; use Illuminate\Contracts\Validation\Validator; use Illuminate\Http\Exception\HttpResponseException; use Illuminate\Validation\ValidatesWhenResolvedTrait; use Illuminate\Contracts\Validation\ValidatesWhenResolved; // 是你 use Illuminate\Contracts\Validation\Factory as ValidationFactory; // 我们`app\Http\Requests\Request`便是继承于这个`FormRequest`类 class FormRequest extends Request implements ValidatesWhenResolved // 就是你 { use ValidatesWhenResolvedTrait; // 这个我们待会儿也要看看 // ...
FormRequest基类中的validate方法是由这个Illuminate\Validation\ValidatesWhenResolvedTrait实现的:
Illuminate\Validation\ValidatesWhenResolvedTrait:
<?php namespace Illuminate\Validation; use Illuminate\Contracts\Validation\ValidationException; use Illuminate\Contracts\Validation\UnauthorizedException; /** * Provides default implementation of ValidatesWhenResolved contract. */ trait ValidatesWhenResolvedTrait { /** * Validate the class instance. * * @return void */ public function validate() // 这里实现了`validate`方法 { $instance = $this->getValidatorInstance(); // 这里获取了`Validator`实例 if (! $this->passesAuthorization()) { $this->failedAuthorization(); // 这是调用了访问授权的失败处理 } elseif (! $instance->passes()) { $this->failedValidation($instance); // 这里调用了验证失败的处理,我们主要看这里 } } // ...
在validate里,如果验证失败了就会调用$this->failedValidation(),继续:
Illuminate\Foundation\Http\FormRequest:
<?php // ... /** * Handle a failed validation attempt. * * @param \Illuminate\Contracts\Validation\Validator $validator * @return mixed */ protected function failedValidation(Validator $validator) { throw new HttpResponseException($this->response( // 这里抛出了传说中的异常 $this->formatErrors($validator) )); }
终于看到异常了!可是这个异常在另一个地方被处理了:
Illuminate\Routing\Route:
<?php // ... /** * Run the route action and return the response. * * @param \Illuminate\Http\Request $request * @return mixed */ public function run(Request $request) { $this->container = $this->container ?: new Container; try { if (! is_string($this->action['uses'])) { return $this->runCallable($request); } if ($this->customDispatcherIsBound()) { return $this->runWithCustomDispatcher($request); } return $this->runController($request); } catch (HttpResponseException $e) { // 就是这里 return $e->getResponse(); // 这里直接返回了Response给客户端 } } // ...
至此,整个思路已然清晰,不过我们还是看看这里生成的HttpResponseException异常中的Response是怎么生成的:
Illuminate\Foundation\Http\FormRequest:
<?php // ... // 132行: if ($this->ajax() || $this->wantsJson()) { // 对AJAX请求的处理 return new JsonResponse($errors, 422); } return $this->redirector->to($this->getRedirectUrl()) // 对普通表单提交的处理 ->withInput($this->except($this->dontFlash)) ->withErrors($errors, $this->errorBag); // ...
相信你都看明白了。
如何实现自定义错误处理,这里提供两个思路,都需要重写app\Http\Requests\Request的failedValidation:
抛出一个新异常,继承HttpResponseException异常,重新实现getResponse方法,这个异常类我们可以放到app/Exceptions/下便于管理,错误返回依然交给Laravel;
抛出一个我们自定义的异常,在app\Exceptions\handler中处理。
具体实现这里就不写啦(参阅Laravel文档中关于错误处理部分,中文文档传送门),如果你有别的方法或者想法可以在评论中和我交流。
补充
如果你的Controller使用Illuminate\Foundation\Validation\ValidatesRequests这个Trait的validate方法进行验证,同样的,这里验证失败也会抛出Illuminate\Http\Exception\HttpResponseException异常,可以参考上面的解决方案进行处理。
您可能感兴趣的文章: