Building a custom validation rule
Once a check needs more than a builtin rule can express — like a password strength policy — it belongs in its own Rule class, not stuffed into a closure inside rules(). Here's one that requires an uppercase letter, a lowercase letter, a symbol and a minimum length, wired into a Form Request.
-
Generate the rule
Passing a namespaced name creates the class inside a matching subdirectory of
app/Rules— handy for grouping related rules, like keeping every auth-related rule underApp\Rules\Auth.php artisan make:rule Auth/SecurePasswordThat creates
app/Rules/Auth/SecurePassword.phpimplementing theRulecontract, withpasses()andmessage()stubbed out. -
Implement passes() and message()
passes()gets the attribute name and its value, and returns a boolean.message()supplies the error text used when it returnsfalse— this one requires at least one lowercase letter, one uppercase letter, one symbol, and 8 characters minimum.<?php namespace App\Rules\Auth; use Illuminate\Contracts\Validation\Rule; class SecurePassword implements Rule { public function passes($attribute, $value) { return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).{8,}$/', $value); } public function message() { return 'The password you entered does not meet the security requirements.'; } } -
Drop it into a Form Request's rules()
A custom rule instance slots into the array alongside builtin rules the same way a
Rule::in()orRule::unique()object does.use App\Rules\Auth\SecurePassword; public function rules(): array { return [ 'password' => ['required', 'string', 'confirmed', new SecurePassword()], ]; } -
Keep the class stateless and reusable
Because
SecurePassworddoesn't depend on the request it's validating, the same instance can be reused across every Form Request that collects a password — registration, password reset, account settings — without duplicating the regex anywhere.