Home > database >  Laravel Validation based on the value of nested array
Laravel Validation based on the value of nested array

Time:01-24

I have read a couple of Stack overflow questions about nested array but I want something a step further. Lets say something like the code below:

I have a validator snippet where the request takes an array. Based on what I understood, on xxx.*.yyy, it will find all array of xxx with yyy as key and validate them . However, what if I want to validate the image_id and image_path based on the value of type?

Note: type, title, image_id and image_path are all on the same level.

The array that I want to validate is like this:

[contents] => Array
    (
        [0] => Array
            (
                [type] => not_image
                [title] => title
            )

        [1] => Array
            (
                [type] => image
                [image_id] => 13
                [image_path] => some_image_string
            )
        )
    )

while my validator is this:

$v = Validator::make($request->all(), [
    'contents.*.type' => ['string', 'required', Rule::in(['image', 'not_image']),],
    'contents.*.image_id' => ['required', 'integer'],
    'contents.*.image_path' => ['required', 'string', 'min:2', 'max:500'],
]);

Only validated image_id and image_page if type is image where image_id and image_path would only be validated if type is validated. I know that the code is missing that one ingredient to do what I want. If you have other ideas on how to do this, that would also be great.

CodePudding user response:

Your last code is not valid, you are saying type => string, required, rule::in, image_id => [rules], that is not valid, that post you are following is just badly indented...

There is a specific section in the documentation that talks and shows about this...

The rule you have to use is exclude_if, the documentation states:

You may occasionally wish to not validate a given field if another field has a given value. You may accomplish this using the exclude_if validation rule. In this example, the appointment_date and doctor_name fields will not be validated if the has_appointment field has a value of false

And the example they give is:

use Illuminate\Support\Facades\Validator;
 
$validator = Validator::make($data, [
    'has_appointment' => 'required|boolean',
    'appointment_date' => 'exclude_if:has_appointment,false|required|date',
    'doctor_name' => 'exclude_if:has_appointment,false|required|string',
]);

As you can see, if the has_appointment is false (exclude_if:has_appointment,false), then appointment_date and doctor_name will not be validated.

In your case, it should be like:

Validator::make(
    $request->all(),
    [
        'contents.*.type' => ['string', 'required', Rule::in(['image', 'not_image'])],
        'contents.*.image_id' => ['exclude_unless:contents.*.type,image', 'required', 'integer'],
        'contents.*.image_path' => ['exclude_unless:contents.*.type,image', 'required', 'string', 'min:2', 'max:500'],
        'contents.*.title' => ['exclude_unless:contents.*.type,not_image', 'required', 'string'],
    ]
);

What that validator is going to do is:

  • Only when contents.*.type = image, then image_id, and image_path are going to be validated
  • Only when contents.*.type = non_image, then title is going to be validated

See that I have used the opposite of exclude_if, that is exclude_unless. So we are saying exclude_unless:contents.*.type,image => If contents.*.type IS image, then use whatever rules I have after this, else completely ignore this field.


You can write it using exclude_if and it would be like this:

Validator::make(
    $request->all(),
    [
        'contents.*.type' => ['string', 'required', Rule::in(['image', 'not_image'])],
        'contents.*.image_id' => ['exclude_if:contents.*.type,non_image', 'required', 'integer'],
        'contents.*.image_path' => ['exclude_if:contents.*.type,non_image', 'required', 'string', 'min:2', 'max:500'],
        'contents.*.title' => ['exclude_if:contents.*.type,image', 'required', 'string'],
    ]
);

The difference (appart from exclude_if instead of exclude_unless) is that now you are ONLY excluding if image or non_image, but using exclude_unless is saying: Only validate if image (or non_image), so if you have 3 types instead of 2 (image and non_image), exclude_if will not work, because you can't specify more than 1 value.


Another quick tip is: just use $request->validate() instead of Validator::make:

$request->validate([
    'contents.*.type' => ['string', 'required', Rule::in(['image', 'not_image'])],
    'contents.*.image_id' => ['exclude_unless:contents.*.type,image', 'required', 'integer'],
    'contents.*.image_path' => ['exclude_unless:contents.*.type,image', 'required', 'string', 'min:2', 'max:500'],
    'contents.*.title' => ['exclude_unless:contents.*.type,not_image', 'required', 'string'],
]);
  • Related