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

时间:2013-08-10 12:16:55

标签: laravel laravel-4

我们如何验证作为数组的表单字段?看一下下面的代码

UserPhone型号:

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

UserController中:

$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

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

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

如何验证此类字段?

5 个答案:

答案 0 :(得分:25)

以下是我使用的解决方案:

用法

通过在each前加上简单地转换您的常规规则。例如:

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

请注意,each规则假定您的字段是数组,因此请不要忘记使用array规则,如此处所示。

错误消息

错误消息将通过您的字段的单数形式(使用Laravel&#39; 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规则来计算数组元素。

答案 1 :(得分:9)

最好扩展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);

    }
}

答案 2 :(得分:6)

各()

它不在文档中,但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级,你可以简单地通过调用{来合并这两种方法{1}}并从其他答案中传递一个魔法规则。
  • each()只接受一个属性,而不是each()所属的属性数组,但将此功能添加到sometimes()不会是一个巨大的变化到each()函数 - 只需遍历each()$attribute array_merge()以及$data结果。有人可以把它作为主要的拉取请求,如果他们认为它是可取的并且还没有完成,我们可以看看它是否会成为未来的版本。

答案 3 :(得分:1)

这是对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;
}

答案 4 :(得分:1)

现在有阵列验证规则可以帮助任何人。似乎这些文档尚未写入文档中。

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