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

Addressing Laravel Package

commerceguys/addressing

A PHP 8+ addressing library powered by CLDR and Google's address data. It provides address formats for 200+ countries, subdivisions, translations, HTML/plain-text formatting, validation via symfony/validator, and zones.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What this is: commerceguys/addressing is a framework-agnostic PHP 8.0+ domain library — not a Laravel package. It provides a value-object address model (xAL-aligned field names, immutable with* mutators plus an AddressBuilder), CLDR-backed reference data (countries in 150+ locales, address formats for 200+ countries, hierarchical subdivisions for 62), two formatters (display and postal-label), Symfony Validator constraints, and a Zone matcher for territorial groupings. There is no service provider, facade, config file, migration, or Blade view. Every Laravel integration point is ours to build.

Architecture fit: Strong at the domain layer, absent at the framework layer. The library gives us three things we would otherwise hand-roll badly and maintain forever: (1) per-country address format metadata — which fields exist, their order, which are required, which are uppercased for mail sorting, and the correct field labels ("State" vs "Province" vs "Prefecture" vs "Region"); (2) postal-code and subdivision validation data; (3) country/subdivision reference lists with local-script names. That is a genuine differentiator for any product with cross-border checkout, shipping, or tax. The address model itself is deliberately persistence-ignorant, so it will not fight Eloquent — but it also will not help.

Integration feasibility: Composer-installable, MIT, no exotic extensions, no network calls, no database. The realistic integration surface is small and well-bounded:

  • Bind CountryRepository, AddressFormatRepository, SubdivisionRepository as container singletons. They are stateless after construction and read packaged JSON; re-instantiating them per request is pure waste.
  • Wrap AddressFormatConstraint / CountryConstraint behind Laravel validation rules so controllers and FormRequests keep a single error contract.
  • Drive address form rendering from AddressFormat (field presence/order/required/labels) via a Blade component.
  • Map AddressInterface to Eloquent via a JSON column cast or flattened columns.

The friction is concentrated in one place: validation. Adopting the library's checks means running symfony/validator alongside Laravel's validator, then translating violations into Laravel's error bag and localizing messages through Laravel's lang files. That is a deliberate two-validator-stack decision and should be made explicitly, not discovered in review.

Technical risk:

Risk Severity Note
No parser — the library formats and validates, it does not parse free-text addresses High Any backfill of legacy unstructured addresses needs a separate vendor or manual re-entry. Scope this before committing to a migration.
Data-driven release cadence Medium Releases routinely contain data corrections (postal-code patterns, renamed subdivisions, e.g. TR Afyon → Afyonkarahisar). Version pins need a review habit, not blind composer update.
API deprecations at minor versions Low–Medium v2.3.0 replaced subdivision_depth with subdivision_data_fields and deprecated getSubdivisionDepth(). Legacy definitions still convert, but custom configs must be tracked.
Maintainer concentration / bus factor Medium Small core team plus community PRs; no commercial SLA. Mitigated by MIT + packaged static data (forkable, data is in-repo).
Metadata hygiene Low The "Dependents: 0" figure contradicts the library's actual footprint (it is the engine behind Drupal's Address module and Drupal Commerce). Verify via Packagist before using it as an adoption signal; the future-dated "last release" also warrants a sanity check.

Key questions for engineering:

  1. Does any user-facing flow actually require parsing existing addresses, or is this greenfield capture only?
  2. Are we willing to run symfony/validator in-process, or do we reimplement the constraints as native Laravel rules and accept divergence from upstream data?
  3. Which markets are in scope at launch? A 3-country launch is a one-sprint integration; a 190-country launch is a QA and localization program.
  4. Do we need Zone (shipping rates, VAT territory logic), or is that already owned by a tax/fulfilment vendor? Duplicating zone logic in two systems is a defect generator.
  5. What is the storage contract — JSON column, flattened columns, or a hybrid (indexed country/postal for queries, JSON for the rest)?
  6. Under Laravel Octane, are singleton repositories and their loaded data sets acceptable as long-lived process state?

Integration Approach

Stack fit: Clean. Pure PHP, PSR-friendly, no global state, no Laravel version coupling. It composes with Laravel 9–12 and PHP 8.0–8.5 without conflict; the only transitive dependency of consequence is symfony/validator, which most Laravel apps already have somewhere in the tree.

Recommended shape:

  • composer require commerceguys/addressing with a caret pin, plus a Renovate/Dependabot rule that surfaces data-only releases for changelog review rather than auto-merging.
  • A thin AddressServiceProvider registering the three repositories as singletons and publishing a config file for default locale and formatter options.
  • A PostalAddress castable / value-object mapper between Eloquent and AddressInterface.
  • A AddressFormat-driven Blade component for capture, and a DefaultFormatter-backed component for display (its HTML output is already semantic and translate="no"-annotated, which is a small accessibility/localization win).
  • Laravel rule wrappers (ValidAddressFormat, ValidCountry) delegating to the Symfony constraints, with violation messages mapped into the app's translation namespace.

Migration path: Phased, and gated on the parser question.

  1. Spike (1–2 weeks): prove format-driven form rendering + validation for the top 2–3 markets in a branch. Confirm the Symfony-validator bridge produces usable Laravel errors. This de-risks ~80% of the unknowns.
  2. Greenfield capture first: apply to new address capture (checkout, account, shipping) before touching stored data. Immediate value, no backfill risk.
  3. Storage and backfill: add structured columns, dual-write, and backfill only where a source of truth exists (e.g. existing country + postal fields). Treat legacy free-text as best-effort; do not promise 100% normalization.
  4. Zones last: only if shipping/tax rate logic is in-house and not already delegated.
  5. Postal labels: PostalLabelFormatter is a genuine differentiator if we print fulfilment labels or carrier manifests — it handles the UPU convention of adding the English country name for international mail and suppressing the country name domestically. Scoped narrowly it is a half-day of work.

Compatibility notes: Subdivision coverage is 62 countries, not 200. For the remainder, administrative areas must be free-text, so the UI cannot hard-assume a dropdown everywhere — the subdivision_data_fields metadata is the switch that must drive this. Also: store canonical codes, format for display. Uppercasing is a presentation concern applied by PostalLabelFormatter; never persist uppercased values.

Operational Impact

Maintenance: Low code-maintenance, non-zero data-maintenance. The library version is the data version; address formats, postal-code patterns, and subdivision lists evolve with real-world administrative changes. Budget a recurring line item — roughly one engineer-day per quarter — for reviewing release notes, re-running the market QA checklist, and regression-testing postal-code validation on top markets. Because everything is packaged locally, there is no runtime dependency on a third-party service and therefore no availability or rate-limit exposure.

Support: Community-only. GitHub issues, no vendor SLA, no security bulletin channel. The security posture is favourable — no network I/O, no deserialization of untrusted input, no file writes — so CVE exposure is minimal, but supply-chain diligence still applies (pin versions, commit the lockfile, vendor-audit in CI).

Scaling: Effectively free. Operations are in-process array lookups and regex matches against packaged JSON; the cost is dominated by the first request in a process loading subdivision data. Two rules keep it flat: bind repositories as singletons, and do not construct them inside loops or per-line-item. Under Octane this is a benefit (data loads once per worker). No cache layer, no external calls, no cold-start problem worth modelling.

Failure modes to design for:

  • Unknown country/subdivision lookups — pin down whether these throw or return null, and handle both at the boundary; never let a data gap produce a 500 on checkout.
  • Locale fallback — a requested locale absent from CLDR data silently falls back to English. Acceptable, but should be visible in logs when it happens for a top market.
  • Postal-code pattern false negatives — pattern data lags reality for edge territories (the NG 11-character and CL Ñuble fixes in recent releases are examples). A hard validation block on an unpatched pattern is a lost order. Mitigation: warn-don't-block on postal code for non-primary markets, or a support override path.
  • Silent field dropping — the validator rejects fields the country's format marks unused. If a UI collects "State" for a country with no administrative areas, the save fails with a message users will not understand. This must be surfaced as a UI constraint, not a validation surprise.
  • Dual-validator divergence — Symfony constraints and Laravel rules returning different messages for the same field is a confusing-UI bug class. Own the mapping in one class.

Ramp-up: Small. The README is genuinely executable — copy-paste examples for every feature — and the domain vocabulary (address format, subdivision, zone) is intuitive to anyone who has shipped checkout. A mid-level Laravel engineer should be productive in a day and confident in a week. The learning cost is not the library; it is the international address-formatting domain itself, and this library is the cheapest way to acquire that knowledge rather than reimplement it.

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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator