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_ifvalidation rule. In this example, theappointment_dateanddoctor_namefields will not be validated if thehas_appointmentfield has a value offalse
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, thenimage_id, andimage_pathare going to be validated - Only when
contents.*.type = non_image, thentitleis 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'],
]);
