在Laravel 5中使用表单请求验证时如何添加自定义验证规则

时间:2015-03-01 12:48:46

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

我正在使用表单请求验证方法来验证laravel 5中的请求。我想用表单请求验证方法添加我自己的验证规则。我的请求类如下所示。我想添加自定义验证numeric_array和字段项。

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

我的cusotom功能如下所示

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

如何在laravel5中使用此验证方法进行表单请求验证?

9 个答案:

答案 0 :(得分:41)

像你一样使用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验证规则

答案 1 :(得分:38)

虽然上述答案是正确的,但在很多情况下,您可能只想为某个表单请求创建自定义验证。您可以利用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 :(得分:19)

接受的答案适用于全局验证规则,但很多时候您将验证某些特定于表单的条件。以下是我在这些情况下推荐的内容(这似乎与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!'
        ];
    }
}

答案 3 :(得分:5)

您需要覆盖getValidatorInstance课程中的Request方法,例如:

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;
}

答案 4 :(得分:3)

您不需要扩展验证程序来验证数组项,您可以使用&#34; *&#34;验证数组的每个项目。正如你所看到的那样 Array Validation

use strict;
use warnings 'all';

use List::Util 'uniq';

my $file = 'log.txt';
open my $fh, $file or die "Couldn't open file: [$!]\n";

my @data;
{
    my %item;

    while ( <$fh> ) {
        chomp;

        if ( eof or /\-{2,}/ ) {
            push @data, { %item } if keys %item;
            %item = ();
        }
        else {
            my ( $key, $value ) = split /\s*:\s*/;
            next unless $value;
            $item{$key} = $value;
            $item{jira} = $key if grep { $key eq $_ } qw/ JIRA DEV QA /;
        }
    }
}

my %data;
{
    for my $item ( @data ) {
        my ($prog, $jira) = @{$item}{qw/ Program jira /};
        push @{ $data{$prog}{$jira} }, $item->{$jira};
    }
}

for my $prog ( sort keys %data ) {

    printf "PROGRAM:   %s\n", $prog;
    print "Change IDs:\n";

    my $n = 1;
    for my $jira ( qw/ JIRA QA DEV / ) {

        next unless my $codes = $data{$prog}{$jira};

        printf "%d.%s\n", $n++, $jira;

        my $l = 'a';
        printf "    %s.%s\n", $l++, $_ for sort(uniq(@$codes));
    }

    print "\n";
}

答案 5 :(得分:3)

自定义规则对象

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

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]
];

答案 6 :(得分:1)

除了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'));
        });
    }
}

答案 7 :(得分:0)

对我来说,工作的解决方案给了我们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加载此服务提供程序,在config / app.php中添加到providers数组,并

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

现在我们可以在函数规则

的请求中使用此验证
public function rules()
{
  return [
    'fDesde'     => 'date',
    'fHasta'     => 'date|after_or_equal:fDesde'
 ];
}

或在Validator中: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//这里详细解释。谢谢他们。

答案 8 :(得分:-1)

此页面上的所有答案将为您解决问题,但是...但是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工匠make:Rule OlympicYear

Laravel生成文件 app / Rules / OlympicYear.php 。更改该文件,使其看起来像这样:

命名空间App \ Rules;

使用照亮\合同\验证\规则;

奥林匹克年实施规则 {

/**
 * 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