How to Use the ValidPhoneNumber Rule in Laravel: Complete Guide

The ValidPhoneNumber rule validates both generic international phone numbers and country‑specific formats by delegating to specialized validators or falling back to a flexible regex pattern.

The ValidPhoneNumber rule from the milwad-dev/laravel-validate package provides a robust, extensible solution for phone validation in Laravel applications. Whether you need to accept international numbers or enforce strict national formats, this rule adapts through a pluggable architecture driven by configuration.

Basic Usage Patterns

Generic Phone Validation (No Country)

To accept any well‑formed international number, instantiate the rule without arguments. According to the source code in src/Rules/ValidPhoneNumber.php, the passes() method applies a generic regex when no country code is supplied.

use Milwad\LaravelValidate\Rules\ValidPhoneNumber;

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

The fallback regex /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/ accommodates optional plus signs, parentheses, spaces, dots, and dashes.

Country‑Specific Validation

To enforce exact formats for a specific nation, pass a country code to the constructor. Use constants from Milwad\LaravelValidate\Utils\Country or raw strings like 'IR' or 'EN'.

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

// Using the Country constant
$request->validate([
    'phone' => ['required', new ValidPhoneNumber(Country::IRAN)],
]);

// Using a raw country code
$request->validate([
    'phone' => ['required', new ValidPhoneNumber('EN')],
]);

Architecture and Validation Flow

Core Components

The validation system relies on a delegation pattern with several key classes:

The Validation Process

When validation is triggered, the following sequence executes inside src/Rules/ValidPhoneNumber.php:

  1. If a country code is provided, the rule calls CountryPhoneCallback::callPhoneValidator($code, $value).
  2. The callback instantiates the appropriate validator class that was registered by the service provider.
  3. The country validator runs its validate() method against the phone number.
  4. If no country code is supplied, the rule applies the generic regex directly.
  5. If an unsupported country code is passed, a BadMethodCallException is thrown, as covered in tests/Rules/ValidPhoneNumberTest.php under test_if_phone_number_validate_method_is_not_exists.

Advanced Configuration

Enabling Container‑Based Shortcut Syntax

To use string‑based validation rules instead of object instantiation, enable the container integration. Set 'using_container' => true in config/laravel-validate.php. The LaravelValidateServiceProvider then registers the valid_phone_number alias.

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

// Usage in validation
$request->validate([
    'phone' => 'required|valid_phone_number:IR',
]);

Extending with Custom Countries

Add support for additional nations by creating a class implementing the CountryPhoneValidator interface and registering it in the configuration:

// config/laravel-validate.php
'phone-country' => [
    'IR' => \Milwad\LaravelValidate\Utils\CountryPhoneValidator\IRPhoneValidator::class,
    'EN' => \Milwad\LaravelValidate\Utils\CountryPhoneValidator\ENPhoneValidator::class,
    'JP' => \App\Validators\JapanPhoneValidator::class, // Your custom implementation
],

Programmatic Validation Examples

Using the Validator Facade

For dynamic validation outside of form requests, use the Validator facade directly with the rule:

use Illuminate\Support\Facades\Validator;
use Milwad\LaravelValidate\Rules\ValidPhoneNumber;
use Milwad\LaravelValidate\Utils\Country;

$data = ['phone' => '+447975777666'];
$rules = ['phone' => ['required', new ValidPhoneNumber(Country::ENGLAND)]];
$passes = Validator::make($data, $rules)->passes(); // Returns true

Summary

  • The ValidPhoneNumber rule supports both flexible generic validation and strict country‑specific format enforcement.
  • Pass a country code (e.g., Country::IRAN or 'EN') to validate against national patterns, or omit it for international numbers.
  • The architecture delegates validation to specialized classes via CountryPhoneCallback, which resolves validators registered by LaravelValidateServiceProvider.
  • Enable string syntax (valid_phone_number:IR) by setting using_container to true in config/laravel-validate.php.
  • Country mappings are configured in the phone-country array, allowing easy extension with custom validators.

Frequently Asked Questions

Can I use ValidPhoneNumber without specifying a country?

Yes. When you instantiate new ValidPhoneNumber without arguments, the rule validates against a generic regex that accepts most international formats, including optional plus signs, parentheses, and various separators.

What happens if I pass an unsupported country code?

The system throws a BadMethodCallException. This behavior is explicitly tested in tests/Rules/ValidPhoneNumberTest.php. Always ensure the country code exists in the phone-country configuration mapping before using it.

How do I add support for a new country?

Create a class implementing the CountryPhoneValidator interface with a validate($value): bool method containing your regex logic. Register this class in config/laravel-validate.php under the phone-country array. The LaravelValidateServiceProvider automatically registers it during the boot phase.

Is there a performance difference between generic and country-specific validation?

Country-specific validation involves an additional lookup through CountryPhoneCallback and instantiation of a specific validator class, but the overhead is negligible for typical HTTP requests. Generic validation is marginally faster as it applies a single regex directly in ValidPhoneNumber::passes().

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 →