logo
podcast Podcast
get help Get Unstuck

Wrapping up our discussion on custom validation rules

The end of a three-part series

Joel Clermont
Joel Clermont
2025-04-30

Today will conclude a three-part series on registering a custom class-based rule with a simple string-based rule name. If you haven't read part one with the solution or part two describing how rules are resolved, I recommend you do that first.

The fundamental reason this whole discussion got started was because the older Rule interface has been deprecated in favor of the newer ValidationRule interface.

But here is where it gets a little bizarre: Even if you're dutifully using the newer interface, Laravel is translating it back into the older interface before calling it.

Check out this chunk of code in the ValidationRuleParser class:

if ($rule instanceof InvokableRule || $rule instanceof ValidationRule) {
    $rule = InvokableValidationRule::make($rule);
}

Notice how our newer ValidationRule gets converted into an InvokableValidationRule? That class implements the older Rule interface, which is why we can call the passes() method on it from our service provider extension.

Also notice inside InvokableValidationRule::passes(), it builds out that $fail callback for you:

$this->invokable->{$method}($attribute, $value, function ($attribute, $message = null) {
    $this->failed = true;

    return $this->pendingPotentiallyTranslatedString($attribute, $message);
});

I considered just using that same code, but it felt too brittle to copy/paste that $fail definition into my app service provider.

Honestly though, it also feels a little weird that Laravel is converting the newer interface back into the older one anyway. I imagine at some future point when the older interface is completely removed, this will all get refactored, and my solution back in part one will need to adjust as well.

But for now, this is the solution that works. And it gave us an excuse to dig deeper into Laravel source code and get familiar with how validation rules work.

Here to help,

Joel

P.S. Join the Mastering Laravel Community and you too can ask questions which may send me off on a deep dive into the Laravel source code.

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼
email
No spam. Only real-world advice you can use.