13

I have the following input form structure upon submission :

array:6 [▼
  "_method" => "PATCH"
  "_token" => "h7hb0yLzdYaFY0I4e1I7CQK7Niq9EqgXFTlramn9"
  "candidate" => array:4 [▶]
  "languages" => array:3 [▼
    0 => "ga"
    1 => "no"
    2 => "sk"
  ]
  "availabilities" => array:2 [▼
    "z" => array:1 [▶]
    2 => array:3 [▶]
  ]
  "experiences" => array:3 [▶]
]

I am trying to validate the 'availabilities' array keys to make sure they correspond to existing id's in the database:

'availabilities' => 'required|integer|exists:days_of_week,id',

If I use this rule it targets the main array, but the exists key is passing validation even when I use the browser console to change the id to something like 'z'. It fails on the integer rule because it retrieves an array as well. How does one validate array keys?

The following example uses a similar form structure. But it does not cover how the employee id could be validated. I saw people add an 'id' key along with 'name' and 'age' for example and to have a rule against that 'id' field, but it is cumbersome.

Patrick.SE
  • 4,444
  • 5
  • 34
  • 44

3 Answers3

11

If you have control over the input data structure, I suggest to modify it to the following:

  [
  ...,
  "availabilities" => [
    {
      "id": "z",
      "data" : [0 => "foo"]
    },
    {
      "id": 2,
      "data" : [0 => "bar"]
    }
  ]

]

Then adjust your validation rules, to validate against your database for example

public function rules {
    return [
        'availabilities' => 'filled',
        'availabilities.*.id' => 'required|integer|exists:days_of_week,id',
        'availabilities.*.data' => 'required|array'
        // etc...
    ];
}
9

You can do this by adding a custom validator. See also: https://laravel.com/docs/5.2/validation#custom-validation-rules.

For example:

\Validator::extend('integer_keys', function($attribute, $value, $parameters, $validator) {
    return is_array($value) && count(array_filter(array_keys($value), 'is_string')) === 0;
});

You can then check the input with:

'availabilities' => 'required|array|integer_keys',

Found the array check here: How to check if PHP array is associative or sequential?

Community
  • 1
  • 1
Jurriën Dokter
  • 116
  • 1
  • 8
  • 3
    As of Laravel 5.5. you can also add such rule directly as a closure: https://laravel.com/docs/5.6/validation#using-closures – Amade Apr 12 '18 at 08:29
4

@Jurriën Dokter 's answer is a work around and uses PHP functions not Laravel rules, It works but if you really want to benefit from Laravel validation rules you have to tweak the validation request a little bit. Here's how:
Make a custom request:

php artisan make:request NameOfRequest  

Place the following function in the request:

protected function prepareForValidation()
{
    $this->merge([
        'availabilities_ids' => array_keys($this->get('availabilities'))
    ]);
}

In the rules:

    public function rules()
    {
        return [
            // place your other rules here .. 
            'availabilities'       => 'required|array|min:1',
            'availabilities.*'     => 'array',
            'availabilities_ids'      => 'exists:App\Models\Availability,id'
        ];
    }

This way you get the benefit of using Laravel's native validation rules through modifying the request params before validation.
See this link to know more about prepareForValidation https://laravel.com/docs/8.x/validation#prepare-input-for-validation

Emad Saeed
  • 106
  • 7