6.8 KiB
HasAddressAssignments Trait
Add the HasAddressAssignments trait to any Eloquent model that references addresses owned by other models.
use Blax\Addresses\Traits\HasAddressAssignments;
class Job extends Model
{
use HasAddressAssignments;
}
class Order extends Model
{
use HasAddressAssignments;
}
When to use this
Use HasAddressAssignments when a model needs to reference an address that it does not own. Instead of duplicating address data, the model creates an assignment that points to an existing AddressLink.
Example: A transport job needs a pickup address and a delivery address. Those addresses belong to customers. The job assigns the customers' address links to itself with context-specific roles.
// Customer owns the address
$pickupLink = $customer->addAddress(['city' => 'Vienna'], AddressLinkType::Office);
$deliveryLink = $recipient->addAddress(['city' => 'Berlin'], AddressLinkType::Home);
// Job references them
$job->assignAddressLink($pickupLink, 'pickup');
$job->assignAddressLink($deliveryLink, 'delivery');
A model can use both
HasAddressesandHasAddressAssignmentsif it both owns and references addresses.
Relationship
addressAssignments()
Returns all AddressAssignment records for this model.
$assignments = $job->addressAssignments;
foreach ($assignments as $assignment) {
echo $assignment->role; // "pickup"
echo $assignment->addressLink->type->label(); // "Office"
echo $assignment->addressLink->address->city; // "Vienna"
}
Return: MorphMany of AddressAssignment
Assigning
assignAddressLink(AddressLink|int $addressLink, ?string $role = null, array $extra = []): AddressAssignment
Assign an existing address link to this model.
use Blax\Addresses\Enums\AddressLinkType;
$link = $user->addAddress([
'street' => 'Kärntner Straße 21',
'city' => 'Vienna',
'country_code' => 'AT',
], AddressLinkType::Office);
// Assign with a role
$assignment = $job->assignAddressLink($link, 'pickup');
// Assign with extra attributes
$assignment = $job->assignAddressLink($link, 'delivery', [
'label' => 'Customer Office Delivery',
'meta' => ['priority' => 'express', 'time_window' => '09:00-12:00'],
]);
// Assign by link ID
$assignment = $job->assignAddressLink($link->id, 'origin');
Parameters:
$addressLink—AddressLinkmodel or its ID$role— Context-specific purpose string (e.g. "pickup", "delivery", "origin", "billing")$extra— Additional attributes:label,meta
Returns: The created AddressAssignment with addressLink.address loaded.
Removing
removeAddressAssignment(int $assignmentId): bool
Remove a specific assignment by its ID.
$assignment = $job->assignAddressLink($link, 'pickup');
$job->removeAddressAssignment($assignment->id); // true
removeAssignmentsForRole(string $role): int
Remove all assignments for a specific role.
// Remove all "pickup" assignments
$removed = $job->removeAssignmentsForRole('pickup'); // 1
Returns: Number of assignments removed.
removeAllAddressAssignments(): int
Remove all address assignments from this model.
$removed = $job->removeAllAddressAssignments(); // 3
Returns: Number of assignments removed.
Querying
addressAssignmentForRole(string $role): ?AddressAssignment
Get the first assignment for a specific role (eager-loads the address link and address).
$assignment = $job->addressAssignmentForRole('pickup');
if ($assignment) {
echo $assignment->role; // "pickup"
echo $assignment->addressLink->address->city; // "Vienna"
}
addressAssignmentsForRole(string $role): Collection
Get all assignments for a specific role. Useful when a model has multiple addresses for the same role.
// A job with multiple stops
$job->assignAddressLink($linkA, 'stop');
$job->assignAddressLink($linkB, 'stop');
$job->assignAddressLink($linkC, 'stop');
$stops = $job->addressAssignmentsForRole('stop'); // Collection of 3
assignedAddressForRole(string $role): ?Address
Convenience shortcut — returns the Address model directly for a role.
$pickupAddress = $job->assignedAddressForRole('pickup');
echo $pickupAddress->formatted; // "Kärntner Straße 21, 1010, Vienna, AT"
Returns: Address or null.
assignedAddresses(): Collection
Get all addresses assigned to this model (through their links).
$addresses = $job->assignedAddresses();
foreach ($addresses as $address) {
echo $address->city;
}
Returns: Collection of Address models.
hasAddressAssignments(): bool
Check whether this model has any address assignments.
if ($job->hasAddressAssignments()) {
// ...
}
hasAssignmentForRole(string $role): bool
Check whether this model has an assignment for a specific role.
if (! $job->hasAssignmentForRole('delivery')) {
// prompt to assign a delivery address
}
Cascade Behaviour
When an AddressLink is deleted (e.g. because the user removes their office address), all AddressAssignment rows referencing that link are cascade-deleted at the database level.
// User removes their office address link
$user->removeAddressLink($officeLink->id);
// All jobs that referenced this link automatically lose their assignment
$job->hasAssignmentForRole('pickup'); // false
Full Example
use App\Models\User;
use App\Models\Job;
use Blax\Addresses\Enums\AddressLinkType;
// Setup: users own addresses
$sender = User::create(['name' => 'Alice']);
$receiver = User::create(['name' => 'Bob']);
$senderOffice = $sender->addAddress([
'street' => 'Stephansplatz 1',
'city' => 'Vienna',
'country_code' => 'AT',
], AddressLinkType::Office);
$receiverHome = $receiver->addAddress([
'street' => 'Unter den Linden 77',
'city' => 'Berlin',
'country_code' => 'DE',
], AddressLinkType::Home);
// Job references both addresses
$job = Job::create(['title' => 'Piano Transport #42']);
$job->assignAddressLink($senderOffice, 'pickup', [
'label' => "Alice's Office",
]);
$job->assignAddressLink($receiverHome, 'delivery', [
'label' => "Bob's Home",
'meta' => ['floor' => 3, 'elevator' => false],
]);
// Query
$job->assignedAddressForRole('pickup')->city; // "Vienna"
$job->assignedAddressForRole('delivery')->city; // "Berlin"
$job->assignedAddresses()->count(); // 2
$job->hasAssignmentForRole('pickup'); // true
$job->hasAssignmentForRole('billing'); // false
// Clean up a single assignment
$job->removeAssignmentsForRole('delivery');
$job->assignedAddresses()->count(); // 1
// Clean up everything
$job->removeAllAddressAssignments();