【问题标题】:How add Custom Validation Rules when using Form Request Validation in Laravel 5在 Laravel 5 中使用表单请求验证时如何添加自定义验证规则
【发布时间】:2015-05-01 20:32:39
【问题描述】:

我在 laravel 5 中使用表单请求验证方法来验证请求。我想用表单请求验证方法添加我自己的验证规则。我的请求类在下面给出。我想添加带有字段项的自定义验证 numeric_array。

  protected $rules = [
      'shipping_country' => ['max:60'],
      'items' => ['array|numericarray']
];

我的自定义函数如下所示

 Validator::extend('numericarray', function($attribute, $value, $parameters) {
            foreach ($value as $v) {
                if (!is_int($v)) {
                    return false;
                }
            }
            return true;
        });

如何在 laravel5 中将此验证方法与表单请求验证一起使用?

【问题讨论】:

    标签: php laravel laravel-5 custom-validators laravel-validation


    【解决方案1】:

    虽然上述答案是正确的,但在很多情况下,您可能只想为某个表单请求创建自定义验证。您可以利用 laravel FormRequest 并使用依赖注入来扩展验证工厂。我认为这个解决方案比创建服务提供者要简单得多。

    这是如何做到的。

    use Illuminate\Validation\Factory as ValidationFactory;
    
    class UpdateMyUserRequest extends FormRequest {
    
        public function __construct(ValidationFactory $validationFactory)
        {
    
            $validationFactory->extend(
                'foo',
                function ($attribute, $value, $parameters) {
                    return 'foo' === $value;
                },
                'Sorry, it failed foo validation!'
            );
    
        }
    
        public function rules()
        {
            return [
                'username' => 'foo',
            ];
        }
    }
    

    【讨论】:

      【解决方案2】:

      像您一样使用Validator::extend() 实际上非常好,您只需将其放入Service Provider 中,如下所示:

      <?php namespace App\Providers;
      
      use Illuminate\Support\ServiceProvider;
      
      class ValidatorServiceProvider extends ServiceProvider {
      
          public function boot()
          {
              $this->app['validator']->extend('numericarray', function ($attribute, $value, $parameters)
              {
                  foreach ($value as $v) {
                      if (!is_int($v)) {
                          return false;
                      }
                  }
                  return true;
              });
          }
      
          public function register()
          {
              //
          }
      }
      

      然后通过将提供者添加到config/app.php中的列表来注册提供者:

      'providers' => [
          // Other Service Providers
      
          'App\Providers\ValidatorServiceProvider',
      ],
      

      您现在可以在任何地方使用numericarray 验证规则

      【讨论】:

      • 如何让自定义错误消息在这里工作?简单地在模型中添加一个 $messages 数组似乎并不能解决问题。
      • @Dubby 在您的 Request 类中,您可以添加一个新方法 messages() 并返回自定义消息数组。例如:return ['field_name.custom_validator_name' => '你的错误信息'];
      【解决方案3】:

      接受的答案适用于全局验证规则,但很多时候您将验证特定于表单的某些条件。以下是我在这些情况下的建议(这似乎是来自line 75 of FormRequest.php 的 Laravel 源代码):

      将验证器方法添加到您的请求将扩展的父请求:

      <?php namespace App\Http\Requests;
      
      use Illuminate\Foundation\Http\FormRequest;
      use Validator;
      
      abstract class Request extends FormRequest {
      
          public function validator(){
      
              $v = Validator::make($this->input(), $this->rules(), $this->messages(), $this->attributes());
      
              if(method_exists($this, 'moreValidation')){
                  $this->moreValidation($v);
              }
      
              return $v;
          }
      }
      

      现在您的所有具体请求将如下所示:

      <?php namespace App\Http\Requests;
      
      use App\Http\Requests\Request;
      
      class ShipRequest extends Request {
      
          public function rules()
          {
              return [
                  'shipping_country' => 'max:60',
                  'items' => 'array'
              ];
          }
      
          // Here we can do more with the validation instance...
          public function moreValidation($validator){
      
              // Use an "after validation hook" (see laravel docs)
              $validator->after(function($validator)
              {
                  // Check to see if valid numeric array
                  foreach ($this->input('items') as $item) {
                      if (!is_int($item)) {
                          $validator->errors()->add('items', 'Items should all be numeric');
                          break;
                      }
                  }
              });
          }
      
          // Bonus: I also like to take care of any custom messages here
          public function messages(){
              return [
                  'shipping_country.max' => 'Whoa! Easy there on shipping char. count!'
              ];
          }
      }
      

      【讨论】:

      【解决方案4】:

      除了Adrian Gunawan's solution,现在也可以这样处理:

      namespace App\Http\Requests;
      
      use Illuminate\Foundation\Http\FormRequest;
      
      class StoreBlogPost extends FormRequest
      {
          public function rules()
          {
              return [
                  'title' => ['required', 'not_lorem_ipsum'],
              ];
          }
      
          public function withValidator($validator)
          {
              $validator->addExtension('not_lorem_ipsum', function ($attribute, $value, $parameters, $validator) {
                  return $value != 'lorem ipsum';
              });
      
              $validator->addReplacer('not_lorem_ipsum', function ($message, $attribute, $rule, $parameters, $validator) {
                  return __("The :attribute can't be lorem ipsum.", compact('attribute'));
              });
          }
      }
      
      

      【讨论】:

      • 无论如何,这不起作用
      【解决方案5】:

      自定义规则对象

      一种方法是使用Custom Rule Object,这样您就可以根据需要定义任意数量的规则,而无需在提供者和控制器/服务中进行更改以设置新规则。

      php artisan make:rule NumericArray
      

      在 NumericArray.php 中

      namespace App\Rules;
      class NumericArray implements Rule
      {
         public function passes($attribute, $value)
         {
           foreach ($value as $v) {
             if (!is_int($v)) {
               return false;
             }
           }
           return true;
         }
      
      
        public function message()
        {
           return 'error message...';
        }
      }
      

      然后在Form请求中有

      use App\Rules\NumericArray;
      .
      .
      protected $rules = [
            'shipping_country' => ['max:60'],
            'items' => ['array', new NumericArray]
      ];
      

      【讨论】:

      • 当我将它与 JS 验证 (github.com/proengsoft/laravel-jsvalidation) 一起使用时,我收到错误消息:trim() 期望参数 1 是字符串,给定对象。我通过在 NumericArray 类中添加“公共函数 __toString(){return 'NumericArray ';}”解决了这个问题。 github.com/mpociot/laravel-apidoc-generator/issues/247
      • 调用new NumericArray时,有没有办法传递一个额外的参数?例如,我有一个自定义规则对象,现在它检查一个模型(地址),但我想将模型作为参数传递:public function passes($attribute, $value) { return !is_null(\App\Address::whereUuid($value)-&gt;where('user_id', request()-&gt;user()-&gt;id)-&gt;first()); }
      • @kyleRidolfo 也许您可以在初始化传递您的模型时定义构造函数,如item =&gt; [new NumericArray($model)] 和规则类NumericArray 在构造函数中读取它并初始化您可以在passes 方法中使用的类属性:private $classProperty; public function __construct($model) { $this-&gt;classProperty = $model; }
      • @GaneshKarki 啊是的,这很有道理,不知道我在想什么! :) 谢谢!
      【解决方案6】:

      您需要在 Request 类中覆盖 getValidatorInstance 方法,例如这样:

      protected function getValidatorInstance()
      {
          $validator = parent::getValidatorInstance();
          $validator->addImplicitExtension('numericarray', function($attribute, $value, $parameters) {
              foreach ($value as $v) {
                  if (!is_int($v)) {
                      return false;
                  }
              }
              return true;
          });
      
          return $validator;
      }
      

      【讨论】:

      • 你真的需要这样做吗?据我所知,在服务提供商中使用 Validator::extend() 应该足以使规则在全球范围内可用。
      • 能否请您发布示例代码以在服务提供商中使用。我通过阅读 laravel 文档一无所获:(
      • @ShihabudheenMuhammed 这是good example from the laracasts forum
      • @lukasgeiter 我创建但我收到错误消息是方法 [validatePasscheck] 不存在。我该如何解决?
      • 这个答案比创建一个完整的服务提供商要好 WAYYYYYYYYYYY,尤其是当您只需要使用一次规则时。
      【解决方案7】:

      您不需要扩展验证器来验证数组项,您可以使用“*”验证数组的每个项,如您在 Array Validation

      protected $rules = [
            'shipping_country' => ['max:60'],
            'items' => ['array'],
            'items.*' => 'integer'
      ];
      

      【讨论】:

      • 虽然这个答案中没有回答OP的实际标题问题。对于 OP 的实际情况,这个答案是一个更好的解决方案。
      【解决方案8】:

      对我来说,解决方案可以为我们提供 lukasgeiter,但不同的是,我们为 laravel 5.2 创建了一个带有自定义验证的类,就像这样。* 下一个示例是为一个日期范围添加验证,其中第二个日期必须等于或大于第一个日期

      在 app/Providers 中创建 ValidatorExtended.php

      <?php
      namespace App\Providers;
      use Illuminate\Validation\Validator as IlluminateValidator;
      
      class ValidatorExtended extends IlluminateValidator {
      
      private $_custom_messages = array(
       "after_or_equal" => ":attribute debe ser una fecha posterior o igual a 
       :date.",
      );
      
      public function __construct( $translator, $data, $rules, $messages = array(),      
      $customAttributes = array() ) {
        parent::__construct( $translator, $data, $rules, $messages, 
        $customAttributes );
        $this->_set_custom_stuff();
      }
      
      protected function _set_custom_stuff() {
         //setup our custom error messages
        $this->setCustomMessages( $this->_custom_messages );
      }
      
      /**
       * La fecha final debe ser mayor o igual a la fecha inicial
       *
       * after_or_equal
       */
      protected function validateAfterOrEqual( $attribute, $value, $parameters, 
      $validator) {
         return strtotime($validator->getData()[$parameters[0]]) <= 
        strtotime($value);
      }
      
      }   //end of class
      

      好的。现在让我们创建服务提供者。在 app/Providers 中创建 ValidationExtensionServiceProvider.php,我们编写代码

      <?php
      namespace App\Providers;
      
      use Illuminate\Support\ServiceProvider;
      use Validator;
      
      class ValidationExtensionServiceProvider extends ServiceProvider {
      
      public function register() {}
      
      public function boot() {
        $this->app->validator->resolver( function( $translator, $data, $rules, 
        $messages = array(), $customAttributes = array() ) {
          return new ValidatorExtended( $translator, $data, $rules, $messages, 
          $customAttributes );
      } );
      }
      
      }   //end of class
      

      现在我们告诉 Laravel 加载这个 Service Provider,在 config/app.php 的末尾添加 providers 数组,然后

      //Servicio para extender validaciones
      App\Providers\ValidationExtensionServiceProvider::class,
      

      现在我们可以在函数规则中的请求中使用此验证

      public function rules()
      {
        return [
          'fDesde'     => 'date',
          'fHasta'     => 'date|after_or_equal:fDesde'
       ];
      }
      

      或在验证器中:make

      $validator = Validator::make($request->all(), [
          'fDesde'     => 'date',
          'fHasta'     => 'date|after_or_equal:fDesde'
      ], $messages);
      

      您必须注意,进行验证的方法的名称具有前缀 validate 并且采用驼峰式风格的 validateAfterOrEqual 但是当您使用验证规则时,每个大写字母都将替换为下划线和小写字母。

      所有这些我都从https://www.sitepoint.com/data-validation-laravel-right-way-custom-validators//这里详细解释。感谢他们。

      【讨论】:

        【解决方案9】:

        此页面上的所有答案都会解决您的问题,但是...但是 Laravel 约定的唯一正确方法是来自 Ganesh Karki 的解决方案

        一个例子:

        让我们以填写夏季奥运会赛事的表格为例——比如年份和城市。首先创建一个表单。

        <form action="/olimpicyear" method="post">
          Year:<br>
          <input type="text" name="year" value=""><br>
          City:<br>
          <input type="text" name="city" value=""><br><br>
          <input type="submit" value="Submit">
        </form> 
        

        现在,让我们创建一个验证规则,您只能输入奥运会年份。这些是条件

        1. 游戏始于 1896 年
        2. 年份不能大于当前年份
        3. 数字应除以 4

        让我们运行一个命令:

        php artisan make:rule OlympicYear

        Laravel 生成一个文件 app/Rules/OlympicYear.php。将该文件更改为如下所示:

        命名空间应用\规则;

        使用 Illuminate\Contracts\Validation\Rule;

        类OlympicYear实现规则 {

        /**
         * Determine if the validation rule passes.
         *
         * @param  string  $attribute
         * @param  mixed  $value
         * @return bool
         */
        public function passes($attribute, $value)
        {
            // Set condition that should be filled
            return $value >= 1896 && $value <= date('Y') && $value % 4 == 0;
        }
        
        /**
         * Get the validation error message.
         *
         * @return string
         */
        public function message()
        {
            // Set custom error message.
            return ':attribute should be a year of Olympic Games';
        }
        

        }

        最后,我们如何使用这个类?在控制器的 store() 方法中,我们有这样的代码:

        public function store(Request $request)
        {
            $this->validate($request, ['year' => new OlympicYear]);
        }
        

        如果您想通过 Laravel 约定创建验证,请按照以下链接中的教程进行操作。这很容易而且解释得很好。这对我帮助很大。原始教程的链接在这里Tutorial link

        猜你喜欢
        • 2017-12-06
        • 2018-06-03
        • 2017-12-01
        • 2014-04-22
        • 2015-01-26
        • 1970-01-01
        • 2015-08-05
        • 2018-05-18
        • 1970-01-01
        相关资源
        最近更新 更多