laravel 验证laravel 4 中的数组表单字段错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18161785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Validation of array form fields in laravel 4 error
提问by Archimidis M
How can we validate form fields that are arrays? Take a look at the following code
我们如何验证作为数组的表单字段?看看下面的代码
UserPhone Model:
用户手机型号:
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);
}
}
the $validation
comes from a BaseModel which extends Eloquent.
对$validation
来自延伸洋洋洒洒一BaseModel。
In my view:
在我看来:
<?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
Everything is working fine and I get all the phone numbers I want in the Update Form, but I cannot update the model because the validation fails with the message "Phonenumber must be a number".
一切正常,我在更新表单中获得了我想要的所有电话号码,但我无法更新模型,因为验证失败并显示消息“电话号码必须是数字”。
I know that there is not a simple solution for validating array form fields and I tried to extend the validator class but with no success.
我知道验证数组表单字段没有简单的解决方案,我尝试扩展验证器类但没有成功。
How can I validate this kind of fields?
如何验证此类字段?
回答by Lazlo
Here's the solution I use:
这是我使用的解决方案:
Usage
用法
Simply transform your usual rules by prefixing each
. For example:
只需通过前缀来转换您通常的规则each
。例如:
'names' => 'required|array|each:exists,users,name'
Note that the each
rule assumes your field is an array, so don't forget to use the array
rule before as shown here.
请注意,该each
规则假定您的字段是一个数组,所以不要忘记使用array
之前的规则,如下所示。
Error Messages
错误信息
Error messages will be automatically calculated by the singular form (using Laravel's str_singular()
helper) of your field. In the previous example, the attribute is name
.
错误消息将通过str_singular()
您的字段的单数形式(使用 Laravel 的助手)自动计算。在前面的示例中,属性是name
。
Nested Arrays
嵌套数组
This method works out of the box with nested arrays of any depth in dot notation. For example, this works:
此方法开箱即用,适用于点表示法中任何深度的嵌套数组。例如,这有效:
'members.names' => 'required|array|each:exists,users,name'
Again, the attribute used for error messages here will be name
.
同样,此处用于错误消息的属性将为name
.
Custom Rules
自定义规则
This method supports any of your custom rules out of the box.
此方法支持您开箱即用的任何自定义规则。
Implementation
执行
1. Extend the validator class
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. Register your validator extension
2. 注册您的验证器扩展
Anywhere in your usual bootstrap locations, add the following code:
在您通常的引导程序位置的任何位置,添加以下代码:
Validator::resolver(function($translator, $data, $rules, $messages)
{
return new ExtendedValidator($translator, $data, $rules, $messages);
});
And that's it! Enjoy!
就是这样!享受!
Bonus: Size rules with arrays
奖励:数组的大小规则
As a comment pointed out, there's seems to be no easy way to validate array sizes. However, the Laravel documentation is lacking for size rules: it doesn't mention that it can count array elements. This means you're actually allowed to use size
, min
, max
and between
rules to count array elements.
正如评论指出的那样,似乎没有简单的方法来验证数组大小。然而,Laravel 文档缺乏大小规则:它没有提到它可以计算数组元素。这意味着你实际上允许使用size
,min
,max
和between
规则来计算数组元素。
回答by Ronald Hulshof
It works best to extend the Validator class and re-use the existing Validator functions:
最好扩展 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);
}
}
回答by skovacs1
each()
每个()
It's not in the docs, but the 4.2 branch may have a simple solution around line 220.
它不在文档中,但 4.2 分支可能在第 220 行附近有一个简单的解决方案。
Just like the sometimes($attribute, $rules, callable $callback)
function, there is now an each($attribute, $rules)
function.
就像sometimes($attribute, $rules, callable $callback)
函数一样,现在有一个each($attribute, $rules)
函数。
To use it, the code would be something simpler than a sometimes()
call:
要使用它,代码将比sometimes()
调用更简单:
$v->each('array_attribute',array('rule','anotherRule')); //$v is your validator
Caveats
注意事项
sometimes()
andeach()
don't seem to be easily chainable with each otherso if you want to do specifically conditioned rules on array values, you're better off with the magic solutions in other answers for now.each()
only goes one level deepwhich isn't that different from other solutions. The nice thing about the magic solutions is that they will go 0 or 1 level deep as needed by calling the base rules as appropriate so I suppose if you wanted to go 1 to 2 levels deep, you could simply merge the two approaches by callingeach()
and passing it a magic rule from the other answers.each()
only takes one attribute, not an array of attributes assometimes()
does, but adding this feature toeach()
wouldn't be a massive change to theeach()
function - just loop through the$attribute
andarray_merge()
$data
and thearray_get()
result. Someone can make it a pull request on master if they see it as desirable and it hasn't already been done and we can see if it makes it into a future build.
sometimes()
并且each()
似乎不容易相互链接,因此如果您想对数组值执行特定条件的规则,那么现在最好使用其他答案中的神奇解决方案。each()
只深入一层,与其他解决方案没有什么不同。神奇解决方案的好处在于,它们将根据需要通过调用基本规则深入 0 或 1 级,所以我想如果您想深入 1 到 2 级,您可以通过调用each()
和从其他答案中传递一个神奇的规则。each()
只需要一个 attribute,而不是像sometimes()
这样的一组属性,但是添加这个特性each()
不会对each()
函数造成巨大的改变——只需循环遍历$attribute
andarray_merge()
$data
和array_get()
结果。如果有人认为它是可取的并且尚未完成,则可以将其作为对 master 的拉取请求,我们可以看看它是否会进入未来的构建。
回答by Sebastiaan Luca
Here's an update to the code of Ronald, because my custom rules wouldn't work with the array extension. Tested with Laravel 4.1, default rules, extended rules, …
这是对 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;
}
回答by Gravy
There are now array validation rules in case this helps anybody. It doesn't appear that these have been written up in the docs yet.
现在有数组验证规则,以防这对任何人都有帮助。这些似乎还没有写在文档中。
https://github.com/laravel/laravel/commit/6a2ad475cfb21d12936cbbb544d8a136fc73be97
https://github.com/laravel/laravel/commit/6a2ad475cfb21d12936cbbb544d8a136fc73be97