需求:在我们的laravel5.7
项目中,已经对错误返回做了一层封装,后来发现验证这一块越来越臃肿,所以需要单独的表单验证类来进行处理,就先到了使用FormRequest
,但是使用FormRequest后的错误异常被框架直接抛出处理了,最后的重点就落在重写错误返回了。
解决思路:既然框架捕捉了对应的异常,那么我们就在框架捕捉之前,抛出自己的异常,并做格式处理后返回。
参考:这篇文章给予了思路 https://www.jianshu.com/p/658f979abfb7
- 首先我们之前的错误返回封装
传入对应的规则,然后调用Validator::make
验证,有错误就抛出对应的异常,然后在Exceptions
中做对应处理以及错误提示国际化
/**
* 验证输入信息
* @param $rules
* @return bool
* @throws SfoException
*/
public function validateInput($rules)
{
$requests = $this->request->all();
$validator = Validator::make($requests, $rules);
if ($validator->fails()) {
throw new SfoException(40013, ['params' => $validator->messages()->first()]);
} else {
$this->validated = array_intersect_key($requests, $rules);
return false;
}
}
关于FormRequest如何处理异常的,参考文章这一块写得不错,就直接引用过来了,懒得再写:
作者: 该叶无法找到
链接:https://www.jianshu.com/p/658f979abfb7
来源:简书
通常来说,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接口:
<?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)
));
}
终于看到异常了!可是这个异常在另一个地方被处理了:
好了既然知道异常来源了,那么剩下来的就好办了:
1、重写failedValidation
方法
我是在app\http\Requests
下创建了NewFormRequest
类并重写failedValidation
方法,抛出我需要的异常:
<?php
/**
* Created by PhpStorm.
* User: 有梦想的咸鱼
* Date: 2019/7/1
* Time: 14:38
*/
namespace App\Http\Requests;
use App\Exceptions\SfoException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\ValidatesWhenResolved;
use Illuminate\Contracts\Validation\Validator;
/**
* 本类重写了 FormRequest 类的错误返回,原继承FormRequest,创建的独立表单验证类将继承本类
* Class NewFormRequest
* @package App\Http\Requests
*/
class NewFormRequest extends FormRequest implements ValidatesWhenResolved
{
/**
* 重写框架的 FormRequest 类的 failedValidation 方法
* @param Validator $validator
* @throws SfoException
*/
protected function failedValidation(Validator $validator)
{
throw new SfoException(40013, ['params' => $validator->messages()->first()]);
}
}
2、生成自定义表单验证类继承于刚才写的NewFormRequest
类
php artisan make:request CreateContractRequest
执行后会在app/Http/Requests/
生成CreateContractRequest.php
:
<?php
namespace App\Modules\Business\Requests;
use App\Http\Requests\NewFormRequest;
use App\Modules\Core\Http\Controllers\ValidateDataRule;
class CreateContractRequest extends NewFormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//签订人邮箱
'signer_email' => 'nullable|string|max:100|email',
//签订时间
'sign_time' => 'required|date_format:Y-m-d'
。。。。省略50行
];
}
}
3、修改新的调用方式
- 项目原来的调用方式:
//创建合同
public function createContract(Request $request)
{
$rules = [
//签订人邮箱
'signer_email' => 'nullable|string|max:100|email',
//签订时间
'sign_time' => 'required|date_format:Y-m-d'
// 。。。。省略50行
];
if ($error = $this->validateInput($rules)) {
return $error;
}
$input = $this->validated;
......
}
- 返回的错误:
{
"error_code": 40013,
"error_desc": "签订时间格式错误",
"tag": "operator7"
}
- 新的调用方式:通过依赖注入
CreateContractRequest
//创建合同
public function createContract(CreateContractRequest $request)
{
$input = $request->validated();
......
}
ps:新的错误验证调用就只有一行了,但因为重写了异常处理,抛出了和以前的一样的异常,所以返回的错误还是和以前一样。
- 如果不重写
failedValidation
,就采用新的调用方式,抛出的错误如下:
{
"message": "The given data was invalid.",
"errors": {
"signer_email": [
"签订人邮箱字段必须填写"
],
"sign_time": [
"签订时间字段必须填写"
],
}
}
------------------------------------------------ END ----------------------------------------------------------
网友评论