Validation of array form fields in laravel 4 error
laravel, laravel-4
Solution
Here's the solution I use:
Usage
Simply transform your usual rules by prefixing `each`. For example:
'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.
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`.
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`.
Custom Rules
This method supports any of your custom rules out of the box.
Implementation
1. Extend the validator class
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
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.
Problem
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. 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?