У меня есть форма, которая имеет входной «массив», который при отправке проверяется с помощью Laravel’s Validator.
Проверка работает, как и ожидалось, применяя правило к каждому элементу массива и соответственно возвращая MessageBag с ошибками.
Проблема: MessageBag не ссылается на связанный индекс массива.
Есть ли способ (помимо определения правила для каждого возможного индекса массива) сделать так, чтобы Laravel ссылался на связанный индекс входного массива?
Образец HTML
<input name="something[]" type="text" />
<input name="something[]" type="text" />
<input name="something[]" type="text" />
...
Образец валидатора
Validator::make
(
Input::all(),
array
(
"something" => array("required", "exists:somewhere")
)
);
Образец MessageBag после проверки (нет ссылки на индекс входного массива)
object(Illuminate\Support\MessageBag)#150 (2)
{
["messages":protected]=> array(6)
{
["something"]=> array(1)
{
[0]=> string(26) "Some error message"}
}
...
}
Я не смог найти какой-либо способ сделать это, используя стандартную функциональность ядра Laravel, поэтому в итоге я расширил Validator
класс для реализации решения.
Код ниже документирован для лучшего понимания этого решения.
созданный app/libraries/MyApp/Validation
каталоги для проведения новых классов
расширенный \Illuminate\Validation\Validator
согласно этой статье (метод «Разрешить из класса»): Расширение валидатора Laravel 4
Override Validator#passes()
namespace MyApp\Validation;
use \Illuminate\Validation\Validator;
class ArrayAwareValidator extends Validator
{
//Override Validator#passes() method
public function passes()
{
//For each validation rule...
foreach ($this->rules as $attribute => $rules)
{
//Get the value to be validated by this rule
$values = $this->getValue($attribute);
//If the value is an array, we got an HTML input array in our hands
if(is_array($values))
{
//Iterate through the values of this array...
for($i=0; $i<count($values); $i++)
{
//...and create a specific validation rule for this array index
$this->rules[$attribute.".".$i] = $rules;
}
//Delete original rule
unset($this->rules[$attribute]);
}
}
//Let Validator do the rest of the work
return parent::passes();
}
}
Это приводит к следующему MessageBag
object(Illuminate\Support\MessageBag)#151 (2)
{
["messages":protected]=> array(2)
{
["something.0"]=>
array(1)
{
[0]=> string(26) "Some error message"}
["something.1"]=>
array(1)
{
[0]=> string(26) "Some error message"}
}
...
}
На стороне клиента, используя JavaScript, я разделяю имя из индекса (например, «что-то.1» на «что-то» и «1»), а затем использую эту информацию для определения правильного ввода формы. Я использую Ajax для отправки формы, поэтому вам может потребоваться использовать другой подход здесь.
Замечания: Это прагматичное решение, которое хорошо подходит для моей проблемы. Как видите, индекс массива передается вместе с именем входа в той же строке. Возможно, вы захотите расширить что-то еще, чтобы сделать Validator
вернуть объект или массив с именем и индексом как отдельные вещи.
Ваш валидатор должен быть таким:
Validator::make
(
Input::all(),
array
(
'something' => 'required,unique:somewhere'
));