Sofia's avatar
Level 6

Can validation be stopped on specific failures?

I know that there's the $stopOnFirstFailure flag that will stop validation when the first validation error occurs, but I'm looking for the ability to stop validation when specific attribute validation fails.

It's not bail which will stop validating the remaining rules on that attribute, not the remaining attributes.

For example: The following fields get submitted:

  • type
  • name
  • email
  • phone

I want to stop validating if type fails validation (name, email, and phone can't be validated because they have custom rules that rely on the value of 'type'), but if type passes and name fails, for example, I want to keep going with email and phone to capture all validation errors.

Does anyone know what the appropriate way to do this is? I feel like there's some rule that I'm missing or misunderstanding that will accomplish this easily.

0 likes
9 replies
s4muel's avatar

i would tinker around with the withValidator method (https://laravel.com/docs/8.x/validation#adding-after-hooks-to-form-requests) and try to move the validation rules for the 'dependent' values (name, email, phone) up there.

public function withValidator($validator)
{
    $validator->after(function ($validator) {
        if (!$validator->failed()) {
            Validator::make($this->input(), [
                'name' => ['required'],
                'email' => ['required'],
                'phone' => ['required'],
            ])->validate();
		}
    });
}
Sofia's avatar
Level 6

Thanks @s4muel.

So with this approach, I'd have to have all of the attributes that I want to fail instantly configured in the initial rules, then follow up with any additional (non-instant failing) fields in the after hook?

I suppose I can also attach a sometimes rule to each non-instantly failing attribute to conditionally validate.

The form i'm working with is a lot more complex than the example, so I was hoping that there would be something more straight forward that I can do to mark certain attributes to fail validation right away vs. having to manage conditional validation.

s4muel's avatar

correct. put the "instant-failing" validation rules in the "first run" and move the rest to the withValidator's after hook. just let me know if you managed to get it to work 🤞.

i dont think the sometimes will work in this case, because sometimes should skip the validation only if the field is missing completely.

Sofia's avatar
Level 6

Sorry, I meant the sometimes function called in the same withValidator method.

$validator->sometimes(['name', 'email', 'phone'], 'required', function ($input) {
    return $input->type !== null;
});

I think both are valid, but that approach is going to overcomplicate the validator. There's already a fair bit of complexity in the rules and I was really just hoping for something simple like:

$rules = [
	'type' => ['required', .... , 'stop'], 
	'name' => [...],
    'email' => [...],
    'phone' => [...]
]
1 like
Sofia's avatar
Level 6

I mentioned in the question that this is not the flag that I'm looking for.

hamedsbt's avatar

I'm using this approach:

protected function validateCaptcha(Validator $validator): void {
    if ($this->stopOnFirstFailure && $validator->errors()->count()) {
        return;
    }
}
DaemonKeen's avatar

I've came across the same issue and solved it by creating a custom validation rule

that I've attached to the upcoming field with the field we want to stop on as parameter. Now when validator encounter the StopOnFailure it will look into the error bag for the 'driver' and throw exception.

return [
            'driver' => ['required', Rule::enum(ServiceDriver::class)],
            'name' => [new StopOnFailure('driver'), 'required', 'string', 'max:255']
];

I think this solution works but it isn't optimal. It bypasses Laravel's standard error collection and jumps straight to the response which can lead to issues.

Snapey's avatar

I would have two sets of rules, and instigate the validator twice,

Please or to participate in this conversation.