How to Validate Country-Specific Phone Numbers in Laravel Using Laravel-Validate

Yes, the milwad-dev/laravel-validate package validates country-specific phone numbers by mapping ISO-3166-2 country codes to dedicated regex validators via a configurable callback dispatcher.

The milwad-dev/laravel-validate package extends Laravel's validation system with robust support for international phone formats. It ships with 20+ predefined country validators and allows you to validate country-specific phone numbers using either rule objects or string-based validation syntax.

How Country-Specific Phone Validation Works

The package implements a multi-layered architecture that routes validation logic through a central dispatcher to country-specific regex validators.

The Entry Point: ValidPhoneNumber Rule

The ValidPhoneNumber rule class, located in src/Rules/ValidPhoneNumber.php, serves as the primary interface. It accepts an optional ISO-3166-2 country code via its constructor to trigger country-specific validation.

use Milwad\LaravelValidate\Rules\ValidPhoneNumber;
use Milwad\LaravelValidate\Utils\Country;

// Validates against Iran's phone format
new ValidPhoneNumber(Country::IRAN);

When instantiated without arguments, the rule validates generic phone number formats. When passed a country code, it delegates validation to a specialized handler.

The Dispatcher: CountryPhoneCallback

The CountryPhoneCallback class in src/Utils/CountryPhoneCallback.php manages the mapping between country codes and their validators. The callPhoneValidator method routes incoming values to the appropriate validator class based on a static registry populated at boot time.

// From CountryPhoneCallback.php (lines 30-38)
public static function callPhoneValidator(string $countryCode, $value): bool
{
    if (isset(static::$validators[$countryCode])) {
        return (new static::$validators[$countryCode])->validate($value);
    }
    
    throw new \BadMethodCallException("Validator method for '$countryCode' does not exist.");
}

Service Provider Registration

During the boot() method of src/LaravelValidateServiceProvider.php, the package reads the phone-country configuration array and registers each mapping via CountryPhoneCallback::addValidator. This occurs automatically when the service provider loads.

// From LaravelValidateServiceProvider.php (lines 63-67)
$phoneCountries = config('laravel-validate.phone-country', []);
foreach ($phoneCountries as $code => $validator) {
    CountryPhoneCallback::addValidator($code, $validator);
}

Country-Specific Validator Classes

Each supported country implements the CountryPhoneValidator interface and contains a tailored regular expression. For example, src/Utils/CountryPhoneValidator/SEPhoneValidator.php validates Swedish numbers using this pattern:

public function validate($value): bool
{
    return preg_match('/^(?:\+46|0) ?(?:[1-9]\d{1,2}-?\d{2}(?:\s?\d{2}){2}|7\d{2}-?\d{2}(?:\s?\d{2}){2})$/', $value);
}

Practical Implementation: Validating Phone Numbers by Country

You can implement country-specific validation using several approaches depending on your configuration and requirements.

Basic Usage with the Rule Class

Instantiate the ValidPhoneNumber rule directly in your validation logic, passing the appropriate country constant or string code.

$request->validate([
    // Generic validation (any format)
    'phone' => ['required', new ValidPhoneNumber],
    
    // Iran-specific validation
    'mobile_ir' => ['required', new ValidPhoneNumber(Country::IRAN)],
    
    // Germany-specific using string code
    'phone_de' => ['required', new ValidPhoneNumber('DE')],
]);

String-Based Validation with Container Mode

Enable container-based validation by setting using_container to true in config/laravel-validate.php. This allows you to use Laravel's string-based validation syntax with colon-separated parameters.

// config/laravel-validate.php
'using_container' => true,

// In your controller:
$request->validate([
    'phone_ir' => 'required|valid_phone_number:IR',
    'phone_se' => 'required|valid_phone_number:SE',
]);

Adding Custom Country Validators

Extend the package to support countries not included in the default 20+ country set by implementing the CountryPhoneValidator interface.

Step 1: Create your validator class.

<?php
// src/Utils/CountryPhoneValidator/BRPhoneValidator.php
namespace Milwad\LaravelValidate\Utils\CountryPhoneValidator;

class BRPhoneValidator implements CountryPhoneValidator
{
    public function validate($value): bool
    {
        // Brazil mobile format: +55 XX 9XXXX-XXXX
        return preg_match('/^\+55 ?\d{2} ?9?\d{4}-?\d{4}$/', $value);
    }
}

Step 2: Register the mapping in config/laravel-validate.php.

'phone-country' => [
    'BR' => \Milwad\LaravelValidate\Utils\CountryPhoneValidator\BRPhoneValidator::class,
],

Step 3: Validate using your custom country code.

$request->validate([
    'phone_br' => ['required', new ValidPhoneNumber('BR')],
]);

Handling Missing Country Validators

If you attempt to validate against a country code that has no registered validator, the CountryPhoneCallback throws a BadMethodCallException with a descriptive message indicating which validator is missing.

use Milwad\LaravelValidate\Rules\ValidPhoneNumber;

try {
    $request->validate([
        'phone' => ['required', new ValidPhoneNumber('AZ')], // Azerbaijan not registered
    ]);
} catch (\BadMethodCallException $e) {
    // Output: "Validator method for 'AZ' does not exist."
}

Summary

  • ValidPhoneNumber accepts optional ISO-3166-2 country codes (e.g., IR, DE, SE) via its constructor to trigger country-specific validation.
  • CountryPhoneCallback dispatches validation requests to registered country validators using a static registry populated from the phone-country config.
  • LaravelValidateServiceProvider automatically registers all country validators during the boot phase by iterating over the configuration mappings.
  • The package ships with 20+ predefined country validators, each implementing the CountryPhoneValidator interface with tailored regex patterns.
  • You can extend validation coverage by creating custom validator classes and registering them in the configuration array.
  • Attempting to validate an unregistered country code throws a BadMethodCallException rather than failing silently.

Frequently Asked Questions

Which countries are supported out-of-the-box?

The package includes validators for over 20 countries including Iran (IR), Germany (DE), Sweden (SE), France (FR), and the United Kingdom (GB). The complete list is defined in the phone-country array within config/laravel-validate.php, which maps ISO-3166-2 codes to their respective validator classes in the src/Utils/CountryPhoneValidator/ directory.

Can I validate phone numbers using string country codes instead of enums?

Yes. While the package provides a Country enum for convenience, the ValidPhoneNumber constructor accepts plain strings. You can pass 'IR', 'DE', or any valid ISO-3166-2 code directly. When using container mode with using_container enabled, you must use string codes in the validation rule parameters (e.g., valid_phone_number:IR).

What happens if I use a country code without a registered validator?

The CountryPhoneCallback::callPhoneValidator method throws a BadMethodCallException with the message "Validator method for '{code}' does not exist." This ensures that validation failures due to missing country support are explicit rather than defaulting to false negatives.

How do I add support for a country that isn't included by default?

Create a class implementing the CountryPhoneValidator interface with a validate($value): bool method containing your country's regex pattern. Place this class in your preferred namespace, then add the mapping to the phone-country array in config/laravel-validate.php using the ISO-3166-2 code as the key. The service provider will automatically register it on the next request.

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 →