Reputation: 1078
I'm working with API resources but I wanted to add some extra logic. I have this Resource:
return [
'id' => $this->id,
'name' => $this->name,
'contacts' => $this->whenLoaded('contacts'),
'phone' => $this->whenLoaded('contacts',
$this->contacts->where('type', '=', 'phone')->first()
? $this->contacts->where('type', '=', 'phone')->first()->value
: null),
];
contacts
is a relationship 'one-to-many' where there a multiple ways to contact (phone, email, etc).
Then I wanted to add the attribute 'phone' where it will return the phone contact.
This code works fine, the problem is the attribute phone is always loaded even when the 'contacts' relation is not loaded, this is so bad for the performance because is doing the N+1 problem when I don't need the phone attribute.
Am I using bad the whenLoaded method? The logic is very simply, when the contacts relation is loaded get the phone attribute else don't do it.
Upvotes: 0
Views: 4595
Reputation: 7561
Your second argument is executed as it gets sent to the function. So the solution is to pass a callable.
You have to structure it like this:
return [
'id' => $this->id,
'name' => $this->name,
'contacts' => $this->whenLoaded('contacts'),
'phone' => $this->whenLoaded('contacts', function() {
return object_get($this->contacts->where('type', 'phone')->first(), 'value');
})
];
I've added some simplification using object_get()
as well.
Upvotes: 1