Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Phone Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. 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.',
    
  2. First Use Case: Validate a phone number in a form request:

    use Propaganistas\LaravelPhone\Rules\Phone;
    
    public function rules()
    {
        return [
            'phone' => ['required', new Phone],
        ];
    }
    
  3. Quick Utility: Format a phone number in a Blade view:

    {{ phone('+3212345678', 'BE', 'formatNational') }}
    

Implementation Patterns

Validation Workflows

  1. Basic Validation:

    // In FormRequest or Controller
    $request->validate([
        'phone' => 'phone:US,BE',
    ]);
    
  2. Dynamic Country Validation:

    $request->validate([
        'phone' => 'phone:custom_country_field',
        'custom_country_field' => 'required',
    ]);
    
  3. Type-Specific Validation:

    $request->validate([
        'phone' => 'phone:mobile', // Only mobile numbers
        'landline' => 'phone:!mobile', // Exclude mobile numbers
    ]);
    

Model Integration

  1. Attribute Casting:

    use Propaganistas\LaravelPhone\Casts\E164PhoneNumberCast;
    
    class User extends Model
    {
        protected $casts = [
            'phone' => E164PhoneNumberCast::class.':BE',
        ];
    }
    
    • Usage:
      $user->phone = '012 34 56 78'; // Automatically converts to E.164
      $user->phone->formatNational(); // Access utility methods
      
  2. 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();
            }
        }
    }
    

Utility Class Patterns

  1. Formatting for Display:

    $phone = phone('+3212345678', 'BE');
    $nationalFormat = $phone->formatNational(); // "012 34 56 78"
    $internationalFormat = $phone->formatInternational(); // "+32 12 34 56 78"
    
  2. Country-Specific Formatting:

    $phone = phone('012 34 56 78', 'BE');
    $formattedForNL = $phone->formatForCountry('NL'); // "00 32 12 34 56 78"
    
  3. Comparison Logic:

    $phone1 = phone('+3212345678');
    $phone2 = phone('012 34 56 78', 'BE');
    
    if ($phone1->equals($phone2)) {
        // Numbers are equal
    }
    

Gotchas and Tips

Common Pitfalls

  1. Order of Attribute Assignment:

    • Issue: E164PhoneNumberCast fails if phone_country is set after phone.
    • Fix: Set country before phone:
      $user->phone_country = 'BE';
      $user->phone = '012 34 56 78'; // Works
      
  2. Validation Without Country:

    • Issue: Validation fails if country is not specified for raw numbers.
    • Fix: Always provide a country or use INTERNATIONAL:
      'phone' => 'phone:INTERNATIONAL,BE' // Accepts any valid international number + Belgian numbers
      
  3. Lenient Validation:

    • Issue: Lenient validation (LENIENT) may accept invalid numbers.
    • Fix: Use sparingly and combine with other rules:
      'phone' => ['phone:LENIENT', 'min:10'] // Ensure minimum length
      

Debugging Tips

  1. PhoneNumber Object Inspection:

    $phone = phone('+3212345678');
    dd($phone->getType(), $phone->getCountry(), $phone->isValid());
    
  2. Validation Error Messages:

    • Customize in AppServiceProvider:
      Validator::extend('phone', function ($attribute, $value, $parameters, $validator) {
          return Phone::make($value, $parameters)->passes();
      });
      
  3. Database Storage:

    • Raw vs E.164: Choose based on needs:
      • Raw: Preserves user input (e.g., for display).
      • E.164: Ensures uniqueness and global compatibility.

Extension Points

  1. 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']);
        }
    }
    
  2. Override Default Formatting:

    // In AppServiceProvider boot()
    PhoneNumber::macro('customFormat', function () {
        return '+'.substr($this->formatE164(), 1).' ('.$this->getCountry().')';
    });
    
  3. Handle Edge Cases:

    • Null/Empty Values: Use nullable in casts:
      'phone' => [E164PhoneNumberCast::class.':BE', 'nullable'],
      
    • Invalid Countries: Validate country codes before phone validation:
      $request->validate([
          'country' => 'required|size:2',
          'phone' => 'phone:'.$request->country,
      ]);
      

Performance Considerations

  1. Avoid Repeated Parsing:

    • Cache 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);
      }
      
  2. Database Indexes:

    • Index phone_e164 for uniqueness checks:
      Schema::table('users', function (Blueprint $table) {
          $table->string('phone_e164')->unique();
      });
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope