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 Google libphonenumber-powered phone number validation and utilities to Laravel. Validate numbers by country (static list or matching a companion country field), cast attributes, format and compare numbers, and access phone metadata using a simple PhoneNumber class.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require propaganistas/laravel-phone
    

    Add translation for validation.php in each language file:

    'phone' => 'The :attribute field must be a valid number.',
    
  2. First Use Case: Validate a phone number in a form request:

    use Illuminate\Validation\Rule;
    
    $request->validate([
        'phone' => ['required', 'phone:US,BE'],
    ]);
    

Key Starting Points

  • Validation: Use phone rule in Laravel's validation array or Propaganistas\LaravelPhone\Rules\Phone class.
  • Utility Class: Wrap phone numbers with Propaganistas\LaravelPhone\PhoneNumber for formatting and parsing.
  • Casts: Use RawPhoneNumberCast or E164PhoneNumberCast for Eloquent model attributes.

Implementation Patterns

Validation Workflows

  1. Basic Validation:

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

    Automatically detects country from phone_country field.

  2. Country-Specific Validation:

    $request->validate([
        'phone' => 'phone:US,FR',
    ]);
    
  3. Dynamic Country Validation:

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

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

Eloquent Model Integration

  1. Casting Attributes:

    use Propaganistas\LaravelPhone\Casts\E164PhoneNumberCast;
    
    class User extends Model
    {
        protected $casts = [
            'phone' => E164PhoneNumberCast::class.':BE',
        ];
    }
    
  2. Handling Raw Input:

    use Propaganistas\LaravelPhone\Casts\RawPhoneNumberCast;
    
    class User extends Model
    {
        protected $casts = [
            'phone' => RawPhoneNumberCast::class.':country_field',
        ];
    }
    

Utility Class Usage

  1. Formatting:

    $phone = new PhoneNumber('012 34 56 78', 'BE');
    $formatted = $phone->formatNational(); // "012 34 56 78"
    
  2. Country-Specific Formatting:

    $phone = new PhoneNumber('012 34 56 78', 'BE');
    $formattedForUS = $phone->formatForCountry('US'); // "+011 32 12 34 56 78"
    
  3. Equality Checks:

    $phone1 = new PhoneNumber('+3212345678');
    $phone2 = new PhoneNumber('012 34 56 78', 'BE');
    $phone1->equals($phone2); // true
    

Database Patterns

  1. E.164 Storage:

    // Model
    protected $casts = [
        'phone' => E164PhoneNumberCast::class,
    ];
    
    // Usage
    $user->phone = '012 34 56 78'; // Automatically converts to E.164
    
  2. Raw Input Storage:

    // Model
    protected $casts = [
        'phone' => RawPhoneNumberCast::class.':BE',
    ];
    
    // Usage
    $user->phone = '012 34 56 78'; // Stores raw input
    
  3. Search Optimization:

    // Observer
    public function saving(User $user)
    {
        if ($user->isDirty('phone')) {
            $phone = phone($user->phone, $user->phone_country);
            $user->phone_normalized = preg_replace('/[^0-9]/', '', $user->phone);
            $user->phone_national = preg_replace('/[^0-9]/', '', $phone->formatNational());
            $user->phone_e164 = $phone->formatE164();
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Country Attribute Timing:

    • For E164PhoneNumberCast, set the country attribute before the phone number to avoid exceptions:
      // Wrong
      $user->phone = '012 34 56 78';
      $user->phone_country = 'BE';
      
      // Correct
      $user->phone_country = 'BE';
      $user->phone = '012 34 56 78';
      
  2. Validation Without Country:

    • If no country is specified, validation defaults to lenient mode (checks length only). Ensure explicit country constraints for strict validation.
  3. Database Uniqueness:

    • E.164 format ensures global uniqueness, but raw input may not. Use E164PhoneNumberCast for unique constraints.
  4. Type Conflicts:

    • Whitelisting and blacklisting types cannot be used simultaneously. Choose one approach.

Debugging Tips

  1. Validation Errors:

    • Use ->after() to log validation failures:
      $request->validate(['phone' => 'phone:US']);
      $request->after(function ($request) {
          if ($request->failed()) {
              \Log::error('Phone validation failed:', $request->errors());
          }
      });
      
  2. PhoneNumber Object Inspection:

    • Cast to string to debug:
      $phone = new PhoneNumber('invalid', 'BE');
      (string) $phone; // Returns E.164 or empty string
      
  3. Country Code Validation:

    • Ensure country codes are ISO 3166-1 alpha-2 compliant (e.g., US, BE). Invalid codes may cause silent failures.

Extension Points

  1. Custom Validation Rules:

    • Extend Propaganistas\LaravelPhone\Rules\Phone for custom logic:
      use Propaganistas\LaravelPhone\Rules\Phone as BasePhone;
      
      class CustomPhone extends BasePhone
      {
          public function passes($attribute, $value)
          {
              if (!parent::passes($attribute, $value)) {
                  return false;
              }
              // Add custom logic
              return true;
          }
      }
      
  2. Custom Formatting:

    • Override PhoneNumber methods for project-specific formats:
      class CustomPhoneNumber extends PhoneNumber
      {
          public function formatCustom()
          {
              return '(' . substr($this->getNationalNumber(), 0, 3) . ') ' .
                     substr($this->getNationalNumber(), 3, 3) . '-' .
                     substr($this->getNationalNumber(), 6);
          }
      }
      
  3. Database Observers:

    • Extend the observer example for additional search variants or preprocessing:
      class PhoneObserver
      {
          public function saving(Model $model)
          {
              if ($model->isDirty('phone')) {
                  $phone = phone($model->phone, $model->phone_country ?? 'BE');
                  $model->phone_hash = hash('sha256', $phone->formatE164());
              }
          }
      }
      

Performance Considerations

  1. Caching PhoneNumber Objects:

    • Cache frequently used PhoneNumber instances to avoid reprocessing:
      $cacheKey = 'phone_' . md5($phoneString . $country);
      $phone = Cache::remember($cacheKey, now()->addHours(1), function () use ($phoneString, $country) {
          return new PhoneNumber($phoneString, $country);
      });
      
  2. Validation Optimization:

    • Reuse validator instances for bulk validation:
      $validator = Validator::make($data, ['phone' => 'phone:US']);
      if ($validator->fails()) {
          // Handle errors
      }
      
  3. Database Indexing:

    • Index searchable phone variants (phone_normalized, phone_e164) for faster queries:
      Schema::table('users', function (Blueprint $table) {
          $table->index('phone_normalized');
          $table->index('phone_e164');
      });
      
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport