Marc Pont
Marc Pont

Reputation: 1078

Laravel API resource whenLoaded not working properly with another values

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

Answers (1)

Flame
Flame

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

Related Questions