【问题标题】:Laravel 6 - Best way to reuse existing request validators within others request validatorsLaravel 6 - 在其他请求验证器中重用现有请求验证器的最佳方法
【发布时间】:2020-05-02 10:34:23
【问题描述】:

假设有两个 Laravel API 资源 BookAuthor,每个资源都有一些验证 store 请求的规则。

然后,还有第三个 API 资源,API 使用者可以在其中发布特定内容以及 BookAuthor。也就是说store请求必须接受一个Book对象,一个Author对象,以及第三个FooBar对象:

// sample POST body
{
  "book": {...book object...},
  "author": {...author object...},
  "foobar": {...foobar object...}
}

FooBarRequest 验证rules() 中,重用BookRequest::rules()AuthorRequest::rules() 是有意义的,但它不起作用:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class FooBarRequest extends FormRequest
{
    public function rules()
    {
        $bookRules = BookRequest::$validationRules;
        $authorRules = AuthorRequest::$validationRules;

        return [
            'book' => $bookRules,
            'authorRules' => $authorRules,
            'foobar' => 'required|...some rules...'
        ];
    }
}

也许使用 Laravel 的 custom rules,但它没有太大帮助,因为 passes 方法必须返回一个布尔值(即我们应该为每个属性重新编写所有验证逻辑)。

有没有优雅/官方的方式来做到这一点?

【问题讨论】:

    标签: laravel validation laravel-formrequest


    【解决方案1】:

    booktitle 属性将属于 Validating Nested Array Input 规则。

    例如,如果您有:

    $bookRules = ['title' => 'required', 'body' => 'text'];
    $authorRules = ['name' => 'required'];
    

    你希望规则是这样的:

    [
        'book.title' => 'required',
        'book.body' => 'text',
        'author.name' => 'required',
        'foobar' => 'required|...some rules...',
    ];
    

    假设 BookRequest::$validationRulesAuthorRequest::$validationRules 已经返回您想要的,您需要执行以下操作才能到达那里:

    <?php
    
    namespace App\Http\Requests;
    
    use Illuminate\Foundation\Http\FormRequest;
    
    class FooBarRequest extends FormRequest
    {
        public function rules()
        {
            $bookRules = BookRequest::$validationRules;
            $authorRules = AuthorRequest::$validationRules;
    
            return array_merge(
                $this->getNestedArrayRules($bookRules, 'book'),
                $this->getNestedArrayRules($authorRules, 'author'),
                ['foobar' => 'required|...some rules...']
            );
        }
    
        protected function getNestedArrayRules($rules, $key) {
            return array_combine(
                array_map(fn ($attribute) =>  "$key.$attribute", array_keys($rules)), 
                $rules
            );
        }
    }
    

    【讨论】:

      【解决方案2】:

      Laracasts:查看这个答案

      如果你想在多个地方使用相同的验证规则,也许可以使用一个特征,然后在多个表单请求中使用它。所以对于书籍规则:

      <?php
      
      namespace App\Traits;
      
      trait BookValidationTrait
      {
          protected function bookRules ()
          {
              return [
                  'book_input_1' => 'your rules here',
                  'book_input_2' => 'your rules here',
                  ...
              ]
          }
      }
      

      那么对于作者规则:

      <?php
      
      namespace App\Traits;
      
      trait AuthorValidationTrait
      {
          protected function authorRules ()
          {
              return [
                  'author_input_1' => 'your rules here',
                  'author_input_2' => 'your rules here',
                  ...
              ]
          }
      }
      

      然后在你的书单请求类中:

      <?php
      
      namespace App\Http\Requests;
      
      use Illuminate\Foundation\Http\FormRequest;
      use App\Traits\BookValidationTrait;
      
      class BookRequest extends FormRequest
      {
          use BookValidationTrait;
      
          public function rules()
          {
              return $this->bookRules();
          }
      }
      

      在您的作者表单请求类中:

      <?php
      
      namespace App\Http\Requests;
      
      use Illuminate\Foundation\Http\FormRequest;
      use App\Traits\AuthorValidationTrait;
      
      class AuthorRequest extends FormRequest
      {
          use AuthorValidationTrait;
      
          public function rules()
          {
              return $this->authorRules();
          }
      }
      

      最后,在您的 FooBar 表单请求类中:

      <?php
      
      namespace App\Http\Requests;
      
      use Illuminate\Foundation\Http\FormRequest;
      use App\Traits\BookValidationTrait;
      use App\Traits\AuthorValidationTrait;
      
      class FooBarRequest extends FormRequest
      {
          use BookValidationTrait, AuthorValidationTrait;
      
          public function rules()
          {
              return array_merge(
                  $this->bookRules(),
                  $this->authorRules(),
                  [
                      'foobar_input_1' => 'your rules here',
                      'foobar_input_2' => 'your rules here',
                      ...
                  ]
              );
          }
      }
      

      我还没有测试过这个,但它看起来可以工作。

      【讨论】:

      • 合并规则不起作用,因为FooBarRequest 将收到每个实体的带有属性的有效负载。问题确实是如何在请求正文的嵌套属性中重用bookRulesauthorRules
      猜你喜欢
      • 2019-08-06
      • 2015-09-07
      • 2023-03-22
      • 2018-10-18
      • 2017-11-21
      • 2020-01-13
      • 2017-10-20
      • 2020-11-12
      • 2017-10-01
      相关资源
      最近更新 更多