feat(address): standardized address creation#5
Merged
Conversation
Introduce `PostalAddress` data transfer object to standardize schema.org postal address representation. Added `toArray` and `toJsonLd` methods for rendering address data as fragments or standalone JSON-LD. Updated the `Address` model with a `toSchemaOrg` method to generate `PostalAddress` instances. Includes tests and documentation updates.
Add a typed, swappable way to create an address for a model. - AddressData: canonical write DTO (fromArray/withType/toArray), plus PlaceDetails::toAddressData() and PostalAddress::toAddressData() bridges - CreatesAddresses contract + default AddressCreator service (bound singleton); rebind it to customise creation (dedupe, geocoding, uniqueness, defaults) - HasAddresses::addAddress(AddressData|array, AddressType|string|null) - Config::addressesRelation(): single source of truth for the morph wiring - AddressType roles are now Billing/Shipping/Home/Work (Primary dropped) The package enforces no cardinality policy (no dedupe/uniqueness/default). No migration change. Includes the design spec under docs/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a standardized, swappable address-creation flow to the package by introducing a canonical write DTO (AddressData), a container-bound creation contract (CreatesAddresses), and a typed entry point on owner models (HasAddresses::addAddress). It also centralizes the polymorphic relation wiring and extends schema.org support with a PostalAddress DTO plus model mapping.
Changes:
- Introduces
AddressData(write DTO) plus bridges from existing DTOs (PlaceDetails,PostalAddress) to unify creation input. - Adds
CreatesAddresses+ defaultAddressCreator(container binding) and exposesHasAddresses::addAddress(...)as the standard persistence entry point. - Adds schema.org
PostalAddressDTO +Address::toSchemaOrg(), updatesAddressTyperoles, and expands docs/tests.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/PostalAddressTest.php | Adds unit coverage for schema.org PostalAddress array/JSON-LD output behavior. |
| tests/Unit/AddressDataTest.php | Adds unit coverage for AddressData construction, normalization, and bridge methods. |
| tests/Feature/AddressCreationTest.php | Adds feature coverage for addAddress() DTO/array paths, type override, enum-disabled mode, and container rebinding. |
| tests/Feature/AddressableTest.php | Extends feature coverage to include Address::toSchemaOrg() mapping. |
| src/App/Support/Config.php | Centralizes polymorphic relation wiring via Config::addressesRelation(). |
| src/App/Services/AddressCreator.php | Adds default CreatesAddresses implementation that persists via the configured relation. |
| src/App/Models/Address.php | Adds toSchemaOrg() mapping to PostalAddress DTO (and model docblock properties). |
| src/App/Enums/AddressType.php | Updates built-in enum cases to Billing/Shipping/Home/Work (drops Primary). |
| src/App/Data/PostalAddress.php | Adds schema.org PostalAddress DTO with fragment + JSON-LD rendering and bridge to AddressData. |
| src/App/Data/PlaceDetails.php | Adds toAddressData() bridge to the canonical write DTO. |
| src/App/Data/AddressData.php | Adds canonical write DTO with fromArray(), withType(), and column-ready toArray(). |
| src/App/Contracts/CreatesAddresses.php | Adds the contract used as the swap point for address creation. |
| src/App/Concerns/HasAddresses.php | Switches addresses() to use centralized relation and adds addAddress() entry point. |
| src/AddressableServiceProvider.php | Binds CreatesAddresses to the default AddressCreator implementation. |
| README.md | Documents standardized creation (addAddress/AddressData) and schema.org PostalAddress emission. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+89
to
+93
| return new class ($sentinel, $called) implements CreatesAddresses { | ||
| public function __construct( | ||
| private readonly Address $sentinel, | ||
| private bool &$called, | ||
| ) {} |
Comment on lines
+7
to
+10
| case Billing = 'billing'; | ||
| case Shipping = 'shipping'; | ||
| case Primary = 'primary'; | ||
| case Home = 'home'; | ||
| case Work = 'work'; |
Replace Config::addressesRelation() (a relation builder living on the config accessor) with an Addressable contract that the HasAddresses trait satisfies. CreatesAddresses::create() now takes Model&Addressable $owner and calls $owner->addresses() directly, so the morphMany wiring lives only in HasAddresses::addresses(). Models using HasAddresses now declare `implements Addressable`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address Copilot review feedback: - README "Address type enum" still listed the dropped `primary` default; update to billing/shipping/home/work. - Replace the by-reference promoted property in the container-rebinding test with a holder-object spy (cleaner, avoids the unusual by-ref pattern). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a standardized, type-safe, swappable way to create an address for a model. The package provides the mechanism and enforces no policy — no dedupe, no per-type uniqueness, no default/primary. An app imposes its own rules by rebinding the contract.
What's included
AddressData— canonical write DTO (fromArray/withType/toArray), plusPlaceDetails::toAddressData()andPostalAddress::toAddressData()bridges so the existing DTOs converge onto one shape.CreatesAddressescontract + defaultAddressCreatorservice (bound singleton) — the swap point.HasAddresses::addAddress(AddressData|array, AddressType|string|null)— the typed entry point.Config::addressesRelation()— single source of truth for the polymorphicmorphManywiring (used by bothHasAddresses::addresses()andAddressCreator).AddressTyperoles are nowBilling / Shipping / Home / Work(Primarydropped — it conflated a default flag with a role).No migration change.
Testing
composer test— 119 passing (506 assertions)composer stan— clean at level 9, zero suppressionsNew:
tests/Unit/AddressDataTest.php,tests/Feature/AddressCreationTest.php(covers DTO + array paths, country uppercasing, type casting, container rebinding, and enum-disabled mode).