propaganistas/laravel-phone
Add robust phone number validation, casting, and formatting to Laravel using Google’s libphonenumber (PHP port). Validate by country or dynamic country fields, cast model attributes to phone objects, format numbers consistently, and compare/evaluate phone metadata.
Installation:
composer require propaganistas/laravel-phone
Add translation for phone validation in resources/lang/{locale}/validation.php:
'phone' => 'The :attribute field must be a valid number.',
First Use Case: Validate a phone number in a form request:
use Propaganistas\LaravelPhone\Rules\Phone;
public function rules()
{
return [
'phone' => ['required', new Phone],
];
}
Quick Utility: Format a phone number in a Blade view:
{{ phone('+3212345678', 'BE', 'formatNational') }}
Basic Validation:
// In FormRequest or Controller
$request->validate([
'phone' => 'phone:US,BE',
]);
Dynamic Country Validation:
$request->validate([
'phone' => 'phone:custom_country_field',
'custom_country_field' => 'required',
]);
Type-Specific Validation:
$request->validate([
'phone' => 'phone:mobile', // Only mobile numbers
'landline' => 'phone:!mobile', // Exclude mobile numbers
]);
Attribute Casting:
use Propaganistas\LaravelPhone\Casts\E164PhoneNumberCast;
class User extends Model
{
protected $casts = [
'phone' => E164PhoneNumberCast::class.':BE',
];
}
$user->phone = '012 34 56 78'; // Automatically converts to E.164
$user->phone->formatNational(); // Access utility methods
Observer for Search Optimization:
class UserObserver
{
public function saving(User $user)
{
if ($user->isDirty('phone') && $user->phone) {
$phone = phone($user->phone, $user->phone_country ?? 'BE');
$user->phone_normalized = preg_replace('/[^0-9]/', '', $user->phone);
$user->phone_national = preg_replace('/[^0-9]/', '', $phone->formatNational());
$user->phone_e164 = $phone->formatE164();
}
}
}
Formatting for Display:
$phone = phone('+3212345678', 'BE');
$nationalFormat = $phone->formatNational(); // "012 34 56 78"
$internationalFormat = $phone->formatInternational(); // "+32 12 34 56 78"
Country-Specific Formatting:
$phone = phone('012 34 56 78', 'BE');
$formattedForNL = $phone->formatForCountry('NL'); // "00 32 12 34 56 78"
Comparison Logic:
$phone1 = phone('+3212345678');
$phone2 = phone('012 34 56 78', 'BE');
if ($phone1->equals($phone2)) {
// Numbers are equal
}
Order of Attribute Assignment:
E164PhoneNumberCast fails if phone_country is set after phone.$user->phone_country = 'BE';
$user->phone = '012 34 56 78'; // Works
Validation Without Country:
INTERNATIONAL:
'phone' => 'phone:INTERNATIONAL,BE' // Accepts any valid international number + Belgian numbers
Lenient Validation:
LENIENT) may accept invalid numbers.'phone' => ['phone:LENIENT', 'min:10'] // Ensure minimum length
PhoneNumber Object Inspection:
$phone = phone('+3212345678');
dd($phone->getType(), $phone->getCountry(), $phone->isValid());
Validation Error Messages:
AppServiceProvider:
Validator::extend('phone', function ($attribute, $value, $parameters, $validator) {
return Phone::make($value, $parameters)->passes();
});
Database Storage:
Custom Validation Rules:
use Propaganistas\LaravelPhone\Rules\Phone;
class CustomPhoneRule extends Phone
{
public function passes($attribute, $value)
{
if (!parent::passes($attribute, $value)) {
return false;
}
// Add custom logic (e.g., blacklist numbers)
return !in_array($value, ['+3212345678', '+3298765432']);
}
}
Override Default Formatting:
// In AppServiceProvider boot()
PhoneNumber::macro('customFormat', function () {
return '+'.substr($this->formatE164(), 1).' ('.$this->getCountry().')';
});
Handle Edge Cases:
nullable in casts:
'phone' => [E164PhoneNumberCast::class.':BE', 'nullable'],
$request->validate([
'country' => 'required|size:2',
'phone' => 'phone:'.$request->country,
]);
Avoid Repeated Parsing:
PhoneNumber objects if reused frequently:
private $cachedPhones = [];
public function getPhone($number, $country)
{
$key = $number.$country;
return $this->cachedPhones[$key] ?? $this->cachedPhones[$key] = phone($number, $country);
}
Database Indexes:
phone_e164 for uniqueness checks:
Schema::table('users', function (Blueprint $table) {
$table->string('phone_e164')->unique();
});
How can I help you explore Laravel packages today?