Validation of array form fields in laravel 4 error

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.

Leave a Comment