【问题标题】:Laravel 5.5 - Validate Multiple Form Request - at the same timeLaravel 5.5 - 同时验证多个表单请求
【发布时间】:2018-06-30 10:51:31
【问题描述】:

这个问题已经被问到here 之前版本的 laravel 并且还没有回答。

我有一个html form,它使用三个不同的Form Request Validations 进行验证。我能够做到这一点。但是,问题是,表单验证是一一进行的。不是同时。

如果第一个表单请求引发验证错误,则表单将返回到view,因此不会评估其余两个表单,因此无法向用户显示正确的验证错误。

我想要的是:同时用三个表单验证请求rules验证表单

控制器:

public function store(TransportationRequest $request1, PurchaseRequest $request2, SaleRequest $request3)
    {
        //do actions here
    }

我尝试过一一继承表单请求,但未能成功。

编辑:

更具体地回答我的问题:

我确实为purchasetransporataionsale 设置了三个单独的表格,它们分别使用PurchaseRequestTransportationRequestSaleRequest 进行单独评估。

但有一个特殊情况,单个表单处理purchasetransporataionsale我想结合使用三个表单请求规则来验证表单,因为我不想再次编写相同的验证规则。

这个

注意:单独表格和合并表格中的字段相同。

谢谢..

【问题讨论】:

  • 为什么需要 3 个单独的请求?请求背后的想法是它映射到一个传入的 HTTP 请求,其中只有一个。话虽如此,您可以(我认为 - 自己没有尝试过)创建另一个请求对象,它接受您的 3 个请求作为其构造函数的参数。 Laravel 的 IoC 容器应该能够将每个请求项传递给构造函数,然后您可以使用每个请求实例来构建一组规则和消息等。
  • 我的问题是您如何设法同时发布 3 个表单,或者只是将单个表单分成 3 个部分的不同请求?原始问题的答案是您需要手动制作校准器并在每个校准器上运行passes() 方法,然后按照here 的描述收集错误
  • 您能否举例说明何时需要单独的公司请求类?您链接的问题对多个请求参数没有意义。我从来没有遇到过一个坚定的要求是不够的。
  • @jonathon,我也尝试过这种方式,但在将第一个请求传递给构造函数后它也会返回查看。我不熟悉 Laravel 的 IoC 容器,也无法在 docs(5.5) 中找到它。
  • @apokryfos 问题已更新。我想将验证逻辑分开以形成请求,这就是我不使用手动验证器的原因

标签: php laravel validation laravel-5.5 request-validation


【解决方案1】:

我将创建包含每个 FormRequest 规则的特征 - 购买、运输和销售。在其特定的 FormRequest 中使用特征,然后当您需要所有规则时,您可以在组合的 FormRequest 中使用所有三个特征,然后合并规则数组。

【讨论】:

  • rules() 方法的多个特征在同一个表单请求类中是used 时,您将有不明确的方法声明。
【解决方案2】:

当验证失败时,FormRequest 会引发 Illuminate\Validation\ValidationException 异常,该异常具有 redirectTo method,并从那里引发 Exception Handler performs the redirect

你可以通过在你的控制器中手动运行表单请求来实现你想要的行为,在 try/catch 块中捕获错误并在重定向之前组合错误包,或者如果你必须通过 Laravel 将它们注入到你的控制器,那么您需要添加自己的异常处理程序来捕获所有错误,将它们组合起来,然后在最终表单请求运行后重定向。

但是,值得注意的是,这两种方法都不是很好:它们很麻烦,并且会给您带来比它们解决的问题更多的问题。如果你想编写一个可维护的应用程序,你应该尽可能地坚持 Laravel 的做事方式。

存在表单请求来验证表单,因此,每个表单应该有一个表单请求,如果您希望根据不同的规则集编写表单请求,那么应该在表单请求中完成,例如:

  1. 为您的表单定义您的表单请求php artisan make:request StoreMultipleForm
  2. StoreMultipleForm 上的rules 方法获取其他每个表单请求的rules,然后将它们一起返回,例如:

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        $formRequests = [
          TransportationRequest::class,
          PurchaseRequest::class,
          SaleRequest::class
        ];
    
        $rules = [];
    
        foreach ($formRequests as $source) {
          $rules = array_merge(
            $rules,
            (new $source)->rules()
          );
        }
    
        return $rules;
    }
    
  3. 在您的控制器中使用新组合的表单请求,例如:

    public function store(StoreMultipleForm $request)
    {
        // Do actions here.
    }
    

这种方法的优点是它是独立的,它符合一个表单请求的期望,它不需要更改您正在组合的表单请求,如果您需要添加此表单独有的其他规则,您可以这样做而无需创建另一个表单请求。

【讨论】:

  • 您写了一个很好的答案,但为了保持完整,我认为您需要在每个答案上调用授权函数。
【解决方案3】:

如果我理解正确,您有 3 个表单,每个表单都有自己的表单请求来处理各自的验证。您还有另一个表单,它在其他地方组合了这 3 个表单,您不想通过重写这些验证规则来重复自己。

在这种情况下,我仍然建议使用单个表单请求,但尝试结合每个单独请求的规则。例如,您使用静态方法为 3 个单独的表单请求定义规则,并让每个单独的请求调用自己的静态方法来获取它们:

class TransportationRequest extends FormRequest
{
    public static function getRules()
    {
        return []; // Return rules for this request
    }

    public function rules()
    {
        return static::getRules();
    }
}

class PurchaseRequest extends FormRequest
{
    public static function getRules()
    {
        return []; // Return rules for this request
    }

    public function rules()
    {
        return static::getRules();
    }
}

class SaleRequest extends FormRequest
{
    public static function getRules()
    {
        return []; // Return rules for this request
    }

    public function rules()
    {
        return static::getRules();
    }
}

然后让您的合并请求合并所有三个集合:

class CombinedRequest extends FormRequest
{
    public function rules()
    {
        return array_merge(
            TransportationRequest::getRules(),
            SaleRequest::getRules(),
            PurchaseRequest::getRules()
        );
    }
}

然后您可以在控制器方法中使用单个 CombinedRequest。当然,如果您不喜欢静态方法方法,在您的组合请求 rules 方法中,您可以将每个单独的请求 new 并在每个请求上调用 rules 方法并合并结果。

class CombinedRequest extends FormRequest
{
    public function rules()
    {
        $transportation = (new TransportationRequest())->rules();
        $sale = (new SaleRequest())->rules();
        $purchase = (new PurchaseRequest())->rules();

        return array_merge(
            $transportation,
            $sales,
            $purchase
        );
    }
}

【讨论】:

    【解决方案4】:

    您可以连接所有规则并手动验证:

    $allRules = (new TransportationRequest)->rules() + (new PurchaseRequest)->rules() + (new SaleRequest)->rules();
    Validator::make($request->all(), $allRules)->validate();
    

    【讨论】:

      【解决方案5】:

      我知道这是一个很老的问题,但是我因为无法将表单请求链接在一起而感到恼火,所以我为此制作了一个作曲家包,所以你不必这样做。

      https://github.com/sharpie89/laravel-multiform-request

      【讨论】:

        【解决方案6】:

        我最近遇到了这个问题,并这样解决了:

        public function rules()
        {
            $request1 = RequestOne::createFrom($this);
            $request2 = RequestTwo::createFrom($this);
        
            return array_merge(
                $request1->rules(),
                $request2->rules()
            );
        }
        

        【讨论】:

          【解决方案7】:

          事实证明,如果您解决了请求,验证就会启动。
          需要注意的一点是,所有验证对象不会立即启动,但根据您的用例,这可能会更简单。

              public function store()
              {
                  // request()->replace([ some fields to be validated ]);
                  resolve(TransportationRequest::class);
                  resolve(PurchaseRequest::class);
                  resolve(SaleRequest::class);
                  // request is valid
              }
          

          【讨论】:

          • 它应该是一个可接受的答案,但可以通过在每个 resolve 和 @ 上添加 try{..} catch(Illuminate\Validation\ValidationException $ex){...} 来改进答案987654323@ 应替换为 app :)
          【解决方案8】:

          可以一个一个手动执行Request类:

          public function store()
          {
              $isValid = true;
              try{
                  app(TransportationRequest::class);
              } catch (Illuminate\Validation\ValidationException $ex){
                  $isValid = false ;
              }
              try{
                  app(PurchaseRequest::class);
              } catch (Illuminate\Validation\ValidationException $ex){
                  $isValid = false ;
              }
              try{
                  app(SaleRequest::class);
              } catch (Illuminate\Validation\ValidationException $ex){
                  $isValid = false ;
              }
              if (!$isValid){
                  throw $ex;
              }
          }
          

          如果其中一个验证失败,用户将被重定向回上一页并出现错误。

          【讨论】:

            猜你喜欢
            • 2018-09-15
            • 2018-09-13
            • 1970-01-01
            • 2018-06-16
            • 2018-06-26
            • 2015-11-25
            • 2016-09-02
            • 2017-12-04
            相关资源
            最近更新 更多