验证laravel 4错误中的数组表单字段

Posted

技术标签:

【中文标题】验证laravel 4错误中的数组表单字段【英文标题】:Validation of array form fields in laravel 4 error 【发布时间】:2013-08-12 06:38:31 【问题描述】:

我们如何验证数组形式的表单字段?看看下面的代码

用户电话型号:

 public static $rules= array(
    'phonenumber'=>'required|numeric',
    'isPrimary'=>'in:0,1'
)
...........

用户控制器:

$validation = UserPhone::validate(Input::only('phonenumber')));


    if($validation->passes())
      
         $allInputs = Input::only('phonenumber','tid');
         $loopSize = sizeOf($allInputs);

         for($i=0;$i<$loopSize;$i++)
         

         $phone = UserPhone::find($allInputs['tid'][$i]);
         $phone->phonenumber = $allInputs['phonenumber'][$i];
         $phone->save();

        

     return Redirect::to('myprofile')->with('message','Update OK');

  
  else
  
     return Redirect::to('editPhone')->withErrors($validation);

   


$validation 来自扩展 Eloquent 的 BaseModel。

在我看来:

 <?php $counter=1; ?>
          @foreach($phones as $thephone)

           <section class="col col-12">
              <label class="label">Phone Number $counter++</label>
              <label class="input">
              <i class="icon-append icon-phone"></i>
                 Form::text('phonenumber[]',$thephone->phonenumber)
                 Form::hidden('tid[]',$thephone->id)
              </label>
            </section>
          @endforeach

一切正常,我在更新表单中获得了我想要的所有电话号码,但我无法更新模型,因为验证失败并显示“电话号码必须是数字”消息。

我知道验证数组表单字段没有简单的解决方案,我尝试扩展验证器类但没有成功。

如何验证此类字段?

【问题讨论】:

【参考方案1】:

这是我使用的解决方案:

用法

只需添加前缀each 即可转换您常用的规则。例如:

'names' => 'required|array|each:exists,users,name'

请注意,each 规则假定您的字段是一个数组,因此请不要忘记在此处使用之前的 array 规则。

错误信息

错误消息将由您的字段的单数形式(使用 Laravel 的 str_singular() 助手)自动计算。在前面的例子中,属性是name

嵌套数组

此方法开箱即用,适用于点表示法中任意深度的嵌套数组。例如,这有效:

'members.names' => 'required|array|each:exists,users,name'

同样,这里用于错误消息的属性将是name

自定义规则

此方法支持您开箱即用的任何自定义规则。

实施

1。扩展验证器类

class ExtendedValidator extends Illuminate\Validation\Validator 

    public function validateEach($attribute, $value, $parameters)
    
        // Transform the each rule
        // For example, `each:exists,users,name` becomes `exists:users,name`
        $ruleName = array_shift($parameters);
        $rule = $ruleName.(count($parameters) > 0 ? ':'.implode(',', $parameters) : '');

        foreach ($value as $arrayKey => $arrayValue)
        
            $this->validate($attribute.'.'.$arrayKey, $rule);
        

        // Always return true, since the errors occur for individual elements.
        return true;
    

    protected function getAttribute($attribute)
    
        // Get the second to last segment in singular form for arrays.
        // For example, `group.names.0` becomes `name`.
        if (str_contains($attribute, '.'))
        
            $segments = explode('.', $attribute);

            $attribute = str_singular($segments[count($segments) - 2]);
        

        return parent::getAttribute($attribute);
    

2。注册您的验证器扩展

在您通常的引导程序位置的任何位置,添加以下代码:

Validator::resolver(function($translator, $data, $rules, $messages)

    return new ExtendedValidator($translator, $data, $rules, $messages);
);

就是这样!享受吧!

奖励:数组的大小规则

正如评论指出的那样,似乎没有简单的方法来验证数组大小。但是,Laravel 文档缺少大小规则:它没有提到它可以计算数组元素。这意味着您实际上可以使用sizeminmaxbetween 规则来计算数组元素。

【讨论】:

谢谢。但是当我运行 $validator = \Validator::make(Input::all(), ['names' =&gt; 'required|array|each:exists,users,username']); 时。即使我不填写任何内容,它也总是返回 true。 解决方法是使用required|array|min:1|each...。我更新了我的答案以提及为什么会这样。 为什么会发生:我同意您的情况可能看起来很奇怪,但这是正常行为。您正在传递一个数组对象(PHP 类型 array()),而不是 null,因此该字段不为空(required 传递)。你的对象是一个数组,所以array 通过。最后,数组中没有元素,所以each 不执行任何验证并通过。 我在哪个文件夹中创建它?【参考方案2】:

最好扩展 Validator 类并重用现有的 Validator 函数:

Validator::resolver(function($translator, $data, $rules, $messages)


    return new Validation($translator, $data, $rules, $messages);

);

class Validation extends Illuminate\Validation\Validator 

    /**
     * Magically adds validation methods. Normally the Laravel Validation methods
     * only support single values to be validated like 'numeric', 'alpha', etc.
     * Here we copy those methods to work also for arrays, so we can validate
     * if a value is OR an array contains only 'numeric', 'alpha', etc. values.
     *
     * $rules = array(
     *     'row_id' => 'required|integerOrArray', // "row_id" must be an integer OR an array containing only integer values
     *     'type'   => 'inOrArray:foo,bar' // "type" must be 'foo' or 'bar' OR an array containing nothing but those values
     * );
     *
     * @param string $method Name of the validation to perform e.g. 'numeric', 'alpha', etc.
     * @param array $parameters Contains the value to be validated, as well as additional validation information e.g. min:?, max:?, etc.
     */
    public function __call($method, $parameters)
    

        // Convert method name to its non-array counterpart (e.g. validateNumericArray converts to validateNumeric)
        if (substr($method, -7) === 'OrArray')
            $method = substr($method, 0, -7);

        // Call original method when we are dealing with a single value only, instead of an array
        if (! is_array($parameters[1]))
            return call_user_func_array(array($this, $method), $parameters);

        $success = true;
        foreach ($parameters[1] as $value) 
            $parameters[1] = $value;
            $success &= call_user_func_array(array($this, $method), $parameters);
        

        return $success;

    

    /**
     * All ...OrArray validation functions can use their non-array error message counterparts
     *
     * @param mixed $attribute The value under validation
     * @param string $rule Validation rule
     */
    protected function getMessage($attribute, $rule)
    

        if (substr($rule, -7) === 'OrArray')
            $rule = substr($rule, 0, -7);

        return parent::getMessage($attribute, $rule);

    

【讨论】:

谢谢你的回答!我会试试的! 我收到一条消息:未定义的偏移量:1 在行:if (!is_array($parameters[1]))【参考方案3】:

每个()

文档中没有,但是4.2分支可能有一个简单的解决方案around line 220。

就像sometimes($attribute, $rules, callable $callback) 函数一样,现在有一个each($attribute, $rules) 函数。

要使用它,代码会比sometimes() 调用更简单:

$v->each('array_attribute',array('rule','anotherRule')); //$v is your validator

注意事项

sometimes()each() 似乎不容易相互链接因此,如果您想对数组值执行特定条件规则,最好使用其他答案中的魔术解决方案暂时。 each() 只深入一级,这与其他解决方案没有什么不同。魔术解决方案的好处是它们会根据需要通过调用基本规则来达到 0 或 1 级深度,所以我想如果你想深入 1 到 2 级,你可以简单地通过调用 @ 合并这两种方法987654329@ 并从其他答案中传递一条神奇的规则。 each() 只接受一个属性,而不是像 sometimes() 那样的一组属性,但是将此功能添加到 each() 不会对 each() 函数产生巨大的变化 - 只是循环通过$attributearray_merge() $dataarray_get() 结果。如果有人认为它是可取的并且尚未完成,则可以向 master 提出拉取请求,我们可以看看它是否会成为未来的构建。

【讨论】:

另外,在过去,为了在任何版本的 laravel 中普遍处理这个问题,我经常只是通过在输入上运行一些循环来将我的输入清理为不是数组我想要的东西,在我去的时候添加到我的验证规则数组中。一个特别的优点是,当数组键在验证器的错误消息中没有有意义的输出(多选)时,您可以根据该键的值插入更有意义的内容,从而导致更容易理解的错误。 只是一个注释。在每个你应该使用数组作为规则参数,否则它不会工作 @Parhs 确实如此。已更正。【参考方案4】:

这是 Ronald 代码的更新,因为我的自定义规则不适用于数组扩展。使用 Laravel 4.1 测试,默认规则,扩展规则,......

public function __call($method, $parameters) 
    $isArrayRule = FALSE;
    if(substr($method, -5) === 'Array') 
        $method = substr($method, 0, -5);
        $isArrayRule = TRUE;
    

    //
    $rule = snake_case(substr($method, 8));

    // Default or custom rule
    if(!$isArrayRule) 
        // And we have a default value (not an array)
        if(!is_array($parameters[1])) 
            // Try getting the custom validation rule
            if(isset($this->extensions[$rule])) 
                return $this->callExtension($rule, $parameters);
            

            // None found
            throw new \BadMethodCallException("Method [$method] does not exist.");
         // Array given for default rule; cannot be!
        else return FALSE;
    

    // Array rules
    $success = TRUE;
    foreach($parameters[1] as $value) 
        $parameters[1] = $value;

        // Default rule exists, use it
        if(is_callable("parent::$method")) 
            $success &= call_user_func_array(array($this, $method), $parameters);
         else 
            // Try a custom rule
            if(isset($this->extensions[$rule])) 
                $success &= $this->callExtension($rule, $parameters);
            

            // No custom rule found
            throw new \BadMethodCallException("Method [$method] does not exist.");
        
    

    // Did any of them (array rules) fail?
    return $success;

【讨论】:

在 Laravel 4.1 上验证功能。比我的尝试写得更好,哈哈。【参考方案5】:

现在有数组验证规则,以防万一这有助于任何人。这些似乎还没有写在文档中。

https://github.com/laravel/laravel/commit/6a2ad475cfb21d12936cbbb544d8a136fc73be97

【讨论】:

这些仅涵盖非常具体的情况,但您是正确的。其他答案提供了一套更全面的“神奇”功能。 似乎只适用于 Laravel 5 @Volatil3 - 考虑到 L5 是今年才推出的,而我几乎在 1 年前就回答了这个问题 - 只有 L5 的情况如何?请参阅链接中的标签:v5.0.22 v5.0.16 v5.0.1 v5.0.0 v4.2.11 v4.2.0 v4.1.27 v4.1.18 v4.1.0 v4.0.9 v4.0.8 v4.0.7 v4.0.6 @Gravy 原谅。是的,你是对的。那么像'availability_date[]' =&gt; 'array|required', 这样设置规则会起作用吗? @Gravy 另外,我也需要编写自定义验证器吗?

以上是关于验证laravel 4错误中的数组表单字段的主要内容,如果未能解决你的问题,请参考以下文章

Laravel:重复字段(和字段组):表单模型绑定

如何在 laravel 表单验证错误消息中给出自定义字段名称

即使没有表单字段,Laravel 也会显示验证错误?

如果值存在于另一个字段数组中,Laravel 验证规则

如果字段是输入类型文件,laravel 中的 required_if 验证不会给出错误

怎么把laravel的表单验证信息改成中文