美文网首页工作生活
Laravel 使用 FormRequest 自定义表单验证类,

Laravel 使用 FormRequest 自定义表单验证类,

作者: 噫那里有条咸鱼 | 来源:发表于2019-07-01 15:38 被阅读0次

需求:在我们的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 ----------------------------------------------------------

相关文章

网友评论

    本文标题:Laravel 使用 FormRequest 自定义表单验证类,

    本文链接:https://www.haomeiwen.com/subject/fwvgcctx.html