Weave 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

Phone Number Bundle Laravel Package

mpetrini/phone-number-bundle

A Symfony bundle for parsing, validating, and formatting international phone numbers using Google's libphonenumber library. Provides Twig filters, form types, and validator constraints, plus a service for phone number handling in your Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install.

    composer require mpetrini/phone-number-bundle
    

    This pulls in giggsey/libphonenumber-for-php (the PHP port of Google's libphonenumber) as a transitive dependency — that package, not this bundle, does the actual parsing/formatting.

  2. Register the bundle.

    • Symfony 4: add to config/bundles.php:
      return [
          // ...
          Mpetrini\PhoneNumberBundle\PhoneNumberBundle::class => ['all' => true],
      ];
      
    • Symfony 2/3: $bundles[] = new Mpetrini\PhoneNumberBundle\PhoneNumberBundle(); in AppKernel.php. Confirm the exact namespace in the README — this is a fork of misd/phone-number-bundle, and forks sometimes keep the original Misd\ namespace.
  3. First use case — normalize an inbound phone number. The bundle's real value is wiring libphonenumber\PhoneNumberUtil into the container, so you inject it instead of calling PhoneNumberUtil::getInstance() yourself:

    use libphonenumber\PhoneNumberFormat;
    use libphonenumber\PhoneNumberUtil;
    
    final class PhoneNormalizer
    {
        public function __construct(private PhoneNumberUtil $util) {}
    
        public function e164(string $raw, string $region = 'US'): string
        {
            $number = $this->util->parse($raw, $region);
    
            return $this->util->format($number, PhoneNumberFormat::E164);
        }
    }
    

    If autowiring works, PhoneNumberUtil is registered directly; otherwise use the classic alias libphonenumber.phone_number_util.

  4. Where to look first.

    • The bundle's README.md and Resources/config/*.xml for the service IDs it actually registers.
    • bin/console debug:container libphonenumber to see what aliases exist in your install.
    • The upstream giggsey/libphonenumber-for-php docs and its online demo for parsing/formatting behaviour — the bundle itself is a thin wrapper, so almost all real knowledge lives upstream.

Implementation Patterns

  • Store E.164 strings, not PhoneNumber objects. Parse on input, format to PhoneNumberFormat::E164, persist the string. It is stable, has no spaces, and sorts/indexes cleanly. Re-parse on display.
  • Validator constraint. The bundle ships a PhoneNumber constraint so validation is declarative:
    use Mpetrini\PhoneNumberBundle\Validator\Constraints\PhoneNumber;
    
    class Contact
    {
        #[PhoneNumber(defaultRegion: 'US', type: 'mobile')]
        private string $phone;
    }
    
    It accepts both a string (parsed using defaultRegion) and a libphonenumber\PhoneNumber object, and options cover type (fixed_line, mobile, etc.), defaultRegion, and message.
  • Form type. Use PhoneNumberType and let the bundled data transformer handle parsing:
    $builder->add('phone', PhoneNumberType::class, [
        'default_region' => 'US',
        'widget' => PhoneNumberType::WIDGET_SINGLE_TEXT, // or WIDGET_COUNTRY_CHOICE
    ]);
    
    WIDGET_COUNTRY_CHOICE gives users a country dropdown and is a common first integration point for signup/checkout forms.
  • Twig filters. For display-only formatting:
    {{ contact.phone|phone_number_format('INTERNATIONAL') }}
    {{ contact.phone|phone_number_format('NATIONAL') }}
    
    The bundle also exposes geocoder/carrier filters — use them sparingly (see Gotchas).
  • Service layer around the util. Wrap parsing in a single PhoneNormalizer / PhoneFormatter service with methods like normalize(), display(), isMobile(). Keeps controllers thin, gives you one place to catch NumberParseException, and makes it trivial to swap the library later.
  • Comparison / dedupe. Normalize both sides to E.164 before comparing. Never compare raw user input — (202) 555-0143, 202.555.0143, and +12025550143 must be stored identically.
  • Custom validation with business rules. isValidNumber() is stricter than isPossibleNumber(). For lenient UX, validate isPossibleNumber() in the form (fast, catches obvious typos) and run isValidNumber() in a service/command for the final check.

Gotchas and Tips

  • This is a low-activity fork. Zero stars, zero dependents, last release 2020, and Symfony 2–4 era. It is effectively misd/phone-number-bundle repackaged. For new projects prefer misd/phone-number-bundle (more eyes, maintained-ish) or depend on giggsey/libphonenumber-for-php directly and register a single PhoneNumberUtil service yourself — that removes an abandoned layer for ~10 lines of config.
  • parse() throws. Always expect libphonenumber\NumberParseException (INVALID_COUNTRY_CODE, NOT_A_NUMBER, TOO_SHORT_AFTER_IDD, …). Wrap calls in try/catch or route through your normalizer service.
  • Region is required for national numbers. parse('202-555-0143', null) throws — the parser can't infer the country without a +. Only pass null when the input is guaranteed to start with a dial code.
  • Region = ISO 3166-1 alpha-2. Use US, GB, DE — never dial codes like 1 or 44. A very common bug.
  • Format ≠ validate. format() will happily format garbage that parsed. Call isValidNumber() (or isPossibleNumber() for lenient checks) separately.
  • Twig filters throw on null/invalid. Guard with {% if contact.phone is not null %} or register a null-safe wrapper; otherwise a null column can 500 a list page.
  • Singleton under the hood. PhoneNumberUtil::getInstance() is a singleton — inject the service, don't call getInstance() yourself, or you defeat the point of the bundle.
  • Metadata footprint. libphonenumber ships region metadata in the multi-megabyte range. On a tight container/memory budget, check giggsey/libphonenumber-for-php's build options for lighter metadata; also avoid eagerly constructing the geocoder/carrier mappers when you only need formatting.
  • Form type input type. PhoneNumberType maps to a libphonenumber\PhoneNumber object by default. If your entity stores strings, either add the bundle's data transformer or use the validator constraint on a string property instead of the form type — mixing the two is a frequent source of "Expected PhoneNumber, got string" errors.
  • Symfony 5/6 compatibility. The bundle predates modern Symfony. If composer update fails on constraints, either widen the constraint with a fork in your own repo or fall back to the direct-library approach. Test bundle registration on your Symfony version before committing.
  • Discovering services. Aliases differ between forks. Run bin/console debug:container --show-private libphonenumber to enumerate them before guessing service IDs in YAML.
  • Extension points. Bundle overrides are minimal, but you can decorate libphonenumber\PhoneNumberUtil or override the form type/validator templates in templates/bundles/PhoneNumberBundle/ (if the fork published templates). The safest extension point is your own normalizer service wrapping the util.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect