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 key to 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],
        ];
    }
    

Where to Look First


Implementation Patterns

Validation Workflows

  1. Basic Validation:

    // Array syntax
    'phone' => 'phone:US,BE'
    
    // Rule object syntax
    new Phone()->country(['US', 'BE'])
    
  2. Dynamic Country Validation:

    // Auto-detect country from `phone_country` field
    'phone' => 'phone',
    'phone_country' => 'required_with:phone'
    
    // Custom country field
    'phone' => 'phone:custom_country_field',
    'custom_country_field' => 'required_with:phone'
    
  3. Type Constraints:

    // Whitelist mobile numbers
    'phone' => 'phone:mobile'
    
    // Blacklist fixed-line numbers
    'phone' => 'phone:!fixed_line'
    
  4. Lenient Validation:

    'phone' => 'phone:LENIENT' // Checks length only
    

Eloquent Integration

  1. Casting Phone Numbers:

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

    use Propaganistas\LaravelPhone\Casts\RawPhoneNumberCast;
    
    protected $casts = [
        'phone' => RawPhoneNumberCast::class.':country_field',
    ];
    
  3. Order of Attribute Assignment:

    // Correct: Set country before phone
    $user->phone_country = 'BE';
    $user->phone = '012 34 56 78';
    

Utility Class Usage

  1. Formatting:

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

    $phone->formatForCountry('US'); // "011 32 12 34 56 78"
    
  3. Comparison:

    $phone1 = phone('+3212345678');
    $phone2 = phone('012 34 56 78', 'BE');
    $phone1->equals($phone2); // true
    
  4. Type Checking:

    $phone->isOfType('mobile'); // true/false
    

Database Patterns

  1. E.164 Storage:

    // Model observer or accessor
    $user->phone_e164 = phone($user->phone, $user->phone_country)->formatE164();
    
  2. Search Optimization:

    // Observer for precomputing search fields
    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();
        }
    }
    
  3. Querying:

    User::where(function($query) use ($search) {
        $query->where('phone_normalized', 'LIKE', $normalizedSearch.'%')
              ->orWhere('phone_e164', 'LIKE', $e164Search.'%');
    });
    

Gotchas and Tips

Common Pitfalls

  1. Country Dependency:

    • Issue: Forgetting to set the country before casting or validating non-international numbers.
    • Fix: Always validate or cast with a country hint:
      // Validation
      'phone' => 'phone:BE'
      
      // Casting
      'phone' => E164PhoneNumberCast::class.':BE'
      
  2. Attribute Assignment Order:

    • Issue: Setting phone before phone_country with E164PhoneNumberCast.
    • Fix: Set country first:
      $user->phone_country = 'BE';
      $user->phone = '012 34 56 78'; // Now works
      
  3. Validation Strictness:

    • Issue: Using LENIENT mode without realizing it bypasses carrier pattern checks.
    • Fix: Prefer strict validation unless explicitly needed:
      // Avoid unless necessary
      'phone' => 'phone:LENIENT'
      
  4. Database Collation:

    • Issue: Storing phone numbers in a case-sensitive column (e.g., utf8mb4_bin).
    • Fix: Use case-insensitive collation for search fields:
      ALTER TABLE users MODIFY phone_e164 VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
      

Debugging Tips

  1. Validation Errors:

    • Use PhoneNumberUtil::isValidNumber() to debug:
      use libphonenumber\PhoneNumberUtil;
      $util = PhoneNumberUtil::getInstance();
      $util->isValidNumber($phoneNumber);
      
  2. Country Code Issues:

    • Verify ISO 3166-1 alpha-2 codes (e.g., US, not USA).
    • Check for typos in country hints:
      // Wrong: 'BE' vs 'be'
      'phone' => 'phone:be' // Fails silently
      
  3. Casting Edge Cases:

    • Ensure the cast parameter is correctly formatted:
      // Correct
      'phone' => E164PhoneNumberCast::class.':BE'
      
      // Incorrect (missing colon)
      'phone' => E164PhoneCast::class.BE // Throws error
      

Performance Considerations

  1. Avoid Over-Fetching:

    • Cache PhoneNumberUtil instance:
      $util = PhoneNumberUtil::getInstance(); // Expensive; reuse
      
  2. Batch Processing:

    • For bulk operations, pre-validate/cast outside the loop:
      $users = User::whereNull('phone_e164')->get();
      foreach ($users as $user) {
          $user->phone_e164 = phone($user->phone, $user->phone_country)->formatE164();
      }
      User::upsert($users->toArray());
      

Extension Points

  1. Custom Formatting:

    • Extend PhoneNumber class:
      class CustomPhoneNumber extends PhoneNumber
      {
          public function formatCustom()
          {
              return $this->formatNational().' ('.$this->getCountry().')';
          }
      }
      
  2. Validation Rules:

    • Create a custom rule:
      use Propaganistas\LaravelPhone\Rules\Phone;
      
      class CustomPhoneRule extends Phone
      {
          public function passes($attribute, $value)
          {
              if (!parent::passes($attribute, $value)) {
                  return false;
              }
              // Add custom logic
              return true;
          }
      }
      
  3. Database Observers:

    • Override default observer behavior:
      class PhoneObserver
      {
          public function saving(User $user)
          {
              if ($user->isDirty('phone')) {
                  $phone = phone($user->phone, $user->phone_country);
                  $user->phone_normalized = $this->normalize($phone->getNationalNumber());
                  $user->phone_e164 = $phone->formatE164();
              }
          }
      
          protected function normalize($number)
          {
              return preg_replace('/[^0-9]/', '', $number);
          }
      }
      

Configuration Quirks

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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony