Open source
Addresses for Laravel
composer require roundly-consulting/addresses-for-laravelOverview
Addresses for any Eloquent model, native to Laravel. Add the HasAddresses trait and attach as many billing, shipping, home or office addresses as you need through one polymorphic addresses table — created with a fluent builder or a DTO, typed by the six built-in AddressType cases or your own configured types, with at most one primary address per type, promoted atomically, owner-checked updates and deletes, and ISO country codes normalised on the way in. Query scopes, lifecycle events, an API resource and test helpers are included. MIT-licensed and built only on Laravel and Roundly’s own package toolkit — no third-party dependencies, no network calls.
What you get
Addresses on any model
One trait and one polymorphic table give any Eloquent model billing, shipping or office addresses — for bigint, UUID or ULID owners.
Configurable address types
Six built-in types — default, billing, shipping, home, work, office — or your own list in addresses.types. Unlisted types are refused on write; labels in English and Slovak.
One primary per type
Promoting an address demotes its siblings atomically, under a lock on the owner + type group. Owner-checked update, delete and setPrimary refuse another owner’s address.
Facade, DI or actions
Addresses::for($customer)->new()->in(…)->at(…)->save() reads like a sentence; inject AddressManager or run an action for the same result.
ISO country normalisation
Codes are trimmed, upper-cased and shape-checked on write. Plug in your own CountryResolver for names and geocoding — no network calls.
Events, scopes & API resource
Four lifecycle events, primary/ofType/inCountry query scopes and a stable AddressResource for JSON APIs.
Recording fake & test helpers
Addresses::fake() records every write without touching the database, plus assertHasAddress(), assertPrimaryAddress() and an AddressFactory.
Documentation
Installation
Install via Composer, publish and run the addresses migration (set a UUID or ULID key type first), and optionally publish config/addresses.php.
Configuration
Every config key and its default — the address model, owner key type, allowed address types, default type, country normalisation, resolver and alias.
Database schema & key types
The addresses table column by column, and how key_type shapes the polymorphic owner column for bigint, UUID or ULID models.
The HasAddresses trait
Add HasAddresses to any Eloquent model for a polymorphic addresses relation plus create, read and primary-address helpers.
Address types
Six built-in AddressType cases or your own types in addresses.types — writes refuse unlisted types; labels, ValidAddressType and select options.
The Addresses facade
Addresses::for($owner) returns an owner’s address book with owner-checked writes; flat update, delete, types and countryName need no owner.
DI and actions
Skip the facade: inject AddressManager or run one of the four actions directly — the facade method → action map.
AddressData & CreateAddressAction
Build writes with the AddressData DTO — make(), its defaults and the default_type fallback — or createAddress(), and run CreateAddressAction on any model.
Fluent builder
Create addresses with Addresses::for()->new() or newAddress() — a readable PendingAddress chain that refuses incomplete addresses.
Reading addresses
Fetch all addresses, the first or primary address of a type, a typed collection or a quick existence check.
Primary addresses
One primary address per owner and type — promote, demote, set it on create and guard against another owner’s address.
Query scopes
Filter addresses with the primary(), ofType() and inCountry() scopes — on the model, on any owner’s relation, or combined.
The Address model
Attributes, casts, the owner relation, JSON meta and the formatted() one-line label on the Address model.
Updating & deleting
Owner-checked or unscoped updates with a full AddressData, soft-delete and restore addresses, and clean up when an owner goes.
Country codes & resolvers
ISO country normalisation on every write, plus an optional CountryResolver for names and geocoding — no bundled data, no network calls.
Events
AddressCreated, AddressUpdated, AddressDeleted and PrimaryAddressChanged — when each one fires, why they wait for the commit, and how to listen.
API resource
AddressResource renders an address for JSON APIs with a stable shape — lines, country, primary flag, formatted label and meta.
Custom address model
Swap in your own Address subclass through config to add scopes, relations or casts — every package path follows it.
Exceptions
One AddressesException base and five typed exceptions — incomplete address, invalid country, foreign address, deleted address and invalid type.
Testing
The recording Addresses::fake(), InteractsWithAddresses assertions, the AddressFactory with billing, shipping and primary states, and a Pest example.
Requirements
PHP 8.4+ and Laravel 13 — no PHP extensions, no third-party dependencies and no network calls.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.