'Laravel Eloquent - Do something before returning models from a relationship
We have some circular dependencies between a couple of models and we would like to optimize that.
Here is a quick overview of the DB schema
Person : id, main_address_id
Address: id, addressable_type, addressable_id
Which translates into Eloquent models:
class Person {
function addresses() {
return $this->morphMany(Address::class, 'addressable', 'addressable_type', 'addressable_id');
}
function main_address() {
return $this->belongsTo(Address::class, 'main_address_id');
}
}
class Address {
public function addressable(): MorphTo
{
return $this->morphTo('addressable', 'addressable_type', 'addressable_id');
}
public function isMainAddress(): bool {
return $this->id === $this->addressable?->main_address_id;
}
}
Everything is working pretty good but we noticed we could save quite a lot of DB queries when dealing with the following type of code:
$addresses = $person->addresses;
foreach ($addresses as $address) {
$address->isMainAddress(); // Loads the addressable from DB to check the IDs
}
One easy fix on the above code is to add a call to setRelation:
$addresses = $person->addresses->each(fn($a) => $a->setRelation('addressable', $person));
That way, the addressable relationship from each address is not queried.
All is fine in a simple case like that, we want to avoid manually doing the setRelation in each place we need it.
Basically we are looking for a way to run a callback on the models returned by the relationship after each time it gets queries. Something like that basically:
function addresses() {
return $this->morphMany(Address::class, 'addressable', 'addressable_type', 'addressable_id')
->prepareModels(fn($a) => $a->setRelation('addressable', $this));
}
function main_address() {
return $this->belongsTo(Address::class, 'main_address_id')
->prepareModels(fn($a) => $a->setRelation('addressable', $this));
}
Kindly note that this is a pure Laravel question. I am not looking for advice regarding how the DB schema would be better another way.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
