Проверка полей формы массива в ошибке 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
происходит от 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 не хватает для правил размера: он не упоминает, что он может считать элементы массива. Это означает, что вам разрешено использовать правила size
, min
, max
и between
для подсчета элементов массива.
Ответ 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);
}
}
Ответ 3
каждый()
Это не в документах, но в ветке 4.2 может быть простое решение вокруг строки 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 уровней, вы можете просто объединить два подхода, вызвав each()
и передать ему магическое правило из других ответов.
-
each()
принимает только один атрибут, а не массив атрибутов как sometimes()
, но добавление этой функции в each()
не будет значительным изменением функции each()
- просто проведите через результаты $attribute
и array_merge()
$data
и array_get()
. Кто-то может сделать запрос на захват хозяином, если он считает это желательным, и он еще не выполнен, и мы можем увидеть, превращает ли он его в будущую сборку.
Ответ 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;
}
Ответ 5
Теперь существуют правила проверки массива, если это помогает кому-либо. Похоже, что они еще не записаны в документах.
https://github.com/laravel/laravel/commit/6a2ad475cfb21d12936cbbb544d8a136fc73be97