Search code examples
phplaravelvalidationcomparison

Laravel validator compare one value to another only if both are present


I'm using Laravel version v8.29.0

I am using the Laravel validator to validate values passed in from an HTTP request. In the request, I have an array of objects, each object has a min and a max value.

Right now I have this validation in place to make sure that the min value is less than the max value as well as that the max value is greater than the min value:

$this->validate($request, [    
    'someObject.*.someOtherObject.yetAnotherObject.min' => 'nullable|numeric|lte:someObject.*.someOtherObject.yetAnotherObject.max',
    'someObject.*.someOtherObject.yetAnotherObject.max' => 'nullable|numeric|gte:someObject.*.someOtherObject.yetAnotherObject.min',
]);

This works just fine if both values are passed in, but for my application it is allowed for just one or the other or neither to be passed in.

If I only pass in the max value then I get an error message that says the max value needs to be greater than the min value even though the min value was not passed in.

Same thing for the min value, if I only pass in the min value then I get an error message that says the min value must be less than the max value.

My question is what syntax changes do I need to make to the code above to allow one or the other, neither or both values for min and max to be passed in and only validate the min and max in regards to each other if they are both passed in?


Solution

  • I don't think there's a built in way to conditionally use the lte and gte depending on if the other value is present.

    What you could do is use the array syntax and a Closure instead:

    $this->validate($request, [
        'someObject.*.someOtherObject.yetAnotherObject.min' => [
            'nullable',
            'numeric',
            function ($attribute, $value, $fail) use ($request) {
                $max = $request->input(str_replace('min', 'max', $attribute));
                if (isset($value, $max) && $value > $max) {
                    $fail(__('validation.lte.numeric', ['value' => $max]));
                }
            },
        ],
        'someObject.*.someOtherObject.yetAnotherObject.max' => [
            'nullable',
            'numeric',
            function ($attribute, $value, $fail) use ($request) {
                $min = $request->input(str_replace('max', 'min', $attribute));
                if (isset($value, $min) && $value < $min) {
                    $fail(__('validation.gte.numeric', ['value' => $min]));
                }
            },
        ],
    ]);
    

    In the above, I'm also using __() (translate) helper function to get the default error message that Laravel would have returned.