commerceguys/addressing
Addressing library for handling international postal addresses. Provides country and subdivision data, address formats, validation, and formatting utilities. Useful for commerce, shipping, and any app that needs correct, locale-aware addresses worldwide.
Installation
composer require commerceguys/addressing
Add to composer.json if using a monorepo or strict dependencies.
First Use Case: Parsing an Address
use CommerceGuys\Addressing\Address;
use CommerceGuys\Addressing\AddressFormatter;
use CommerceGuys\Addressing\AddressParser;
use CommerceGuys\Addressing\Country\CountryRepository;
// Initialize dependencies
$countryRepository = new CountryRepository();
$addressParser = new AddressParser($countryRepository);
$addressFormatter = new AddressFormatter($countryRepository);
// Parse a raw address string
$address = $addressParser->parse('1600 Amphitheatre Parkway, Mountain View, CA 94043, USA');
Where to Look First
vendor/commerceguys/addressing/src/Resources/cldr directory is intact.CountryRepository for supported countries and validation rules.// Parse with strict validation (throws exceptions on errors)
$address = $addressParser->parseStrict('Invalid Address', 'US');
// Parse with relaxed validation (returns partial data)
$address = $addressParser->parse('123 Main St', 'US');
// Format for a specific locale (e.g., 'en_US')
$formatted = $addressFormatter->format($address, 'en_US');
// Customize formatting rules
$formatter = new AddressFormatter($countryRepository, [
'default' => AddressFormatter::STYLE_FULL,
'US' => AddressFormatter::STYLE_POSTAL,
]);
// Get all subdivisions for a country (e.g., US states)
$subdivisions = $countryRepository->getCountry('US')->getSubdivisions();
// Parse a subdivision code
$subdivision = $countryRepository->getSubdivision('US-CA');
// Parse address from request input
$rawAddress = request()->input('address');
$address = $addressParser->parse($rawAddress, request()->input('country_code'));
// Validate parsed address
$validator = Validator::make(['address' => $address], [
'address' => ['required', 'address:US'], // Custom rule for validation
]);
// Load a specific locale (e.g., German)
$countryRepository->loadCountry('DE', 'de_DE');
// Format address in German
$formattedDE = $addressFormatter->format($address, 'de_DE');
// Extend Address class for custom fields (e.g., 'apartment')
class CustomAddress extends Address {
public $apartment;
}
// Parse with custom fields
$address = $addressParser->parse('1600 Amphitheatre Parkway #100, Mountain View, CA 94043, USA', 'US');
$address->apartment = '100'; // Manually set if not parsed
// config/app.php
'providers' => [
App\Providers\AddressingServiceProvider::class,
],
// app/Providers/AddressingServiceProvider.php
public function register() {
$this->app->singleton(CountryRepository::class, function ($app) {
$repository = new CountryRepository();
$repository->loadCountry('US', 'en_US'); // Preload common countries
return $repository;
});
}
// app/Models/User.php
protected $casts = [
'address' => AddressCast::class, // Custom cast for Address objects
];
// Format address for API responses
return response()->json([
'address' => $addressFormatter->format($user->address, 'en_US'),
]);
CLDR Data Loading
vendor/commerceguys/addressing/src/Resources/cldr is not modified or deleted. Reinstall the package if needed.$repository->loadCountry('US', 'en_US');
$repository->loadCountry('DE', 'de_DE');
Strict vs. Relaxed Parsing
parseStrict() throws exceptions for invalid addresses, while parse() returns partial data. Misusing these can lead to silent failures.parseStrict() in critical paths (e.g., billing) and parse() for user-friendly forms.Subdivision Codes
US-CA) are case-sensitive and must match CLDR data exactly.$subdivisionCode = strtoupper(request()->input('state'));
Locale Fallbacks
AddressFormatter:
$formatter = new AddressFormatter($countryRepository, [], 'en_US');
Performance with Large Datasets
CountryRepository instance and preload frequently used countries.Custom Fields in Parsing
apartment) won’t be parsed automatically.if (preg_match('/#(\d+)/', $rawAddress, $matches)) {
$address->apartment = $matches[1];
}
Validate CLDR Data
// Check if a country is loaded
if (!$countryRepository->hasCountry('US')) {
$countryRepository->loadCountry('US', 'en_US');
}
Inspect Parsed Addresses
// Dump parsed address components
dd($address->getPostalCode(), $address->getAdministrativeArea());
Handle Unknown Countries
try {
$address = $addressParser->parseStrict($rawAddress, 'XX'); // 'XX' = unknown
} catch (UnknownCountryException $e) {
// Fallback logic
}
Logging Parsing Issues
try {
$address = $addressParser->parseStrict($rawAddress, 'US');
} catch (AddressParseException $e) {
Log::warning('Address parsing failed', [
'raw_address' => $rawAddress,
'error' => $e->getMessage(),
]);
}
Custom Address Formatter Styles
Extend AddressFormatter to add new formatting styles:
class CustomFormatter extends AddressFormatter {
public const STYLE_CUSTOM = 'custom';
protected function getStyleRules($style) {
$rules = parent::getStyleRules($style);
if ($style === self::STYLE_CUSTOM) {
$rules = ['line1', 'line2', 'postal_code'];
}
return $rules;
}
}
Custom Validation Rules Create a Laravel validation rule for addresses:
// app/Rules/ValidAddress.php
public function passes($attribute, $value) {
$address = $this->parser->parse($value, $this->countryCode);
return $address->isValid();
}
Override CLDR Data
For testing or custom locales, override CLDR data by extending the CountryRepository:
class CustomCountryRepository extends CountryRepository {
public function __construct() {
parent::__construct();
$this->overrideCountryData('US', [
'subdivisions' => ['CA' => 'California (Custom)'],
]);
}
}
Add Custom Address Fields
Extend the Address class to support additional fields:
class ExtendedAddress extends Address
How can I help you explore Laravel packages today?