A closure rule copied into eleven form requests, with two of the copies subtly out of date.
final class ValidVatNumber implements ValidationRule
{
public function __construct(private VatLookup $lookup) {}
public function validate(string $attr, mixed $value, Closure $fail): void
{
if (! $this->lookup->isValid($value)) {
$fail('The :attribute is not a valid VAT number.');
}
}
}
// resolved from the container, so it can have dependencies
'vat_number' => ['required', app(ValidVatNumber::class)],
The interface is a small improvement over the previous one — a single validate method with a failure closure rather than a passes-and-message pair — and the real gain is that a rule with a dependency is now ordinary. The eleven copies were closures precisely because making a rule class used to mean either a static call or a service locator, and both were unpleasant enough that copying won.