Search code examples
laravellaravel-validationlaravel-request

Indicate the incorrect key in Laravel's array rule validation error message


I am doing FormRequest validation. I am using the array rule to ensure that only specified keys are allowed in the validated array. For example:

$rules = [
  'example' => ['array:something,another'],
];

However, if this rule encounters an array key that isn't in that whitelist the error message I get isn't very descriptive:

The :attribute field must be an array.

This message doesn't reference the incorrect array key at all, making it hard for the end user to work out what they did wrong.

Can I improve this error message such that it highlights the fact that an incorrect key has been passed? Something like a custom validation message of:

The :key key is not valid for the :attribute field.

I would have thought that this has been asked before but my Google-fu clearly isn't strong today! Thanks.


Solution

  • A better solution is a custom validation rule that behaves like the normal array rule, but gives a more sensible error message.

    Use it like:

    use App\Rules\ArrayWith;
    
    $rules = [new ArrayWith('something,another')];
    

    And the rule itself would look like:

    namespace App\Rules;
    
    use Closure;
    use Illuminate\Contracts\Validation\ValidationRule;
    
    class ArrayWith implements ValidationRule
    {
        public array $keys;
    
        public function __construct(string $keys)
        {
            $this->keys = explode(',', $keys);
        }
    
        public function validate(string $attribute, mixed $value, Closure $fail): void
        {
            if (!is_array($value)) {
                $fail('The '.$attribute.' field must be an array.');
            }
            foreach (array_keys($value) as $key) {
                if (!in_array($key, $this->keys)) {
                    $fail('The '.$key.' key is not valid for the '.$attribute.' field.');
                }
            }
        }
    }
    

    It still feels astonishing that this isn't the default behaviour, to be honest.