How to Extend laravel-validate with New Custom Rules: A Complete Guide

You can extend laravel-validate by creating a PHP class in src/Rules that implements Illuminate\Contracts\Validation\Rule, then optionally enabling container-based registration in config/laravel-validate.php to reference the rule by its snake-case filename.

The milwad-dev/laravel-validate package provides a robust collection of reusable validation rules for Laravel applications. When you need domain-specific validation logic that the built-in rules don't cover, you can extend laravel-validate with new custom rules following the package's established conventions. This guide demonstrates the exact implementation patterns used in src/Rules/ValidStrongPassword.php and the registration mechanism found in LaravelValidateServiceProvider.

Creating a Custom Rule Class

All validation rules in laravel-validate reside in the src/Rules directory. To add your own, create a new PHP class that implements Illuminate\Contracts\Validation\Rule and defines two required methods: passes($attribute, $value) and message().

Rule Class Structure

The passes method receives the attribute name and value, returning true for valid input. The message method returns a translation key for the error message. Here is a complete example following the package's pattern:

<?php

namespace Milwad\LaravelValidate\Rules;

use Illuminate\Contracts\Validation\Rule;

class ValidEvenNumber implements Rule
{
    /**
     * Determine if the validation rule passes.
     */
    public function passes($attribute, $value): bool
    {
        return is_int($value) && $value % 2 === 0;
    }

    /**
     * Get the validation error message.
     */
    public function message(): string
    {
        return __('validate.even-number');
    }
}

Store this file at src/Rules/ValidEvenNumber.php. The class name uses PascalCase while the filename uses snake-case when referenced as a string later.

Enabling Container-Based Registration

By default, laravel-validate can automatically register every rule class found in src/Rules using Laravel's service container. This allows you to reference rules by their snake-case filename rather than instantiating objects.

Enable this feature in config/laravel-validate.php:

'using_container' => true,

When LaravelValidateServiceProvider boots, it scans the src/Rules directory and registers each rule automatically (see lines 75-88 in the source). If you modify this config, run php artisan config:cache or republish the config using:

php artisan vendor:publish --tag=laravel-validate-config

Using Your Custom Rule

Laravel-validate supports two syntaxes for applying custom rules, depending on whether you enabled container registration.

Method 1: Object Instantiation (Always Available)

Regardless of the using_container setting, you can instantiate the rule class directly in your validation arrays:

use Milwad\LaravelValidate\Rules\ValidEvenNumber;

$request->validate([
    'quantity' => ['required', new ValidEvenNumber],
]);

Method 2: String Syntax (Requires Container Registration)

When using_container is enabled, reference the rule by its snake-case filename:

$request->validate([
    'quantity' => 'required|valid_even_number',
]);

Both approaches integrate seamlessly with Laravel's validator and work in Form Request classes.

Adding Translation Files

Custom rules should return translation keys from the message() method to support localization. Create or edit language files in resources/lang/<locale>/validate.php:

return [
    'even-number' => 'The :attribute must be an even number.',
];

To publish the package's existing language files for reference, use the provider's publish tags:

php artisan vendor:publish --tag=validate-lang-en

Manually Registering Rules (Advanced Alternative)

If you prefer not to rely on the container-based auto-discovery in LaravelValidateServiceProvider, you can manually extend Laravel's validator in your own service provider's boot method:

use Illuminate\Support\Facades\Validator;
use Milwad\LaravelValidate\Rules\ValidEvenNumber;

Validator::extend('valid_even_number', function ($attribute, $value, $parameters, $validator) {
    return (new ValidEvenNumber)->passes($attribute, $value);
});

This approach bypasses the using_container configuration entirely while still leveraging your custom rule logic.

Summary

  • Create rule classes in src/Rules implementing Illuminate\Contracts\Validation\Rule with passes() and message() methods
  • Enable 'using_container' => true in config/laravel-validate.php to use snake-case string references
  • Validate using either new ValidEvenNumber (object) or 'valid_even_number' (string)
  • Store translations in resources/lang/<locale>/validate.php using keys returned by message()
  • Reference src/Rules/ValidStrongPassword.php for the package's canonical implementation pattern

Frequently Asked Questions

Do I need to enable container registration to use custom rules?

No. Container registration is optional. You can always instantiate your rule class directly with new ValidEvenNumber in validation arrays. The using_container setting only enables the convenience of using snake-case strings like 'valid_even_number' in validation rules.

What naming convention should I follow for rule classes?

Follow the package's established pattern: use PascalCase for class names (e.g., ValidEvenNumber) and store the file in src/Rules/ with a matching name. When using string-based validation, Laravel converts the filename to snake-case automatically (e.g., valid_even_number).

Can I use these custom rules in Form Request classes?

Yes. Both object instantiation and string syntax work inside Form Request classes. Simply import your rule class or use the string identifier in the rules() method, exactly as you would in controller-based validation.

Where should I place custom rules if I'm contributing back to the package?

Place contribution candidates directly in src/Rules/ following the structure of existing rules like ValidStrongPassword.php. Ensure your class implements the Rule contract and includes appropriate translation keys in the package's language files under resources/lang/.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →