Laravel custom attributes loads relationships even when attribute is not asked

I have a custom attribute that calculates the squad name (to make our frontend team lives easier).

This requires a relation to be loaded and even if the attribute is not being called/asked (this happens with spatie query builder, an allowedAppends array on the model being passed to the query builder and a GET param with the required append(s)) it still loads the relationship.

// Model
public function getSquadNameAttribute()
{
    $this->loadMissing('slots');
    // Note:  This model's slots is guaranteed to all have the same squad name (hence the first() on slots).
    $firstSlot = $this->slots->first()->loadMissing('shift.squad');
    return ($firstSlot) ? $firstSlot->shift->squad->name : null;
}

// Resource
public function toArray($request)
{
    return [
        'id'         => $this->id,
        'squad_name' => $this->when(array_key_exists('squad_name', $this->resource->toArray()), $this->squad_name),

        'slots'      => SlotResource::collection($this->whenLoaded('slots')),
    ];
}

Note: squad_name does not get returned if it’s not being asked in the above example, the relationship is however still being loaded regardless

A possible solution I found was to edit the resource and includes if’s but this heavily reduces the readability of the code and I’m personally not a fan.

public function toArray($request)
{
    $collection = [
        'id'    => $this->id,

        'slots' => SlotResource::collection($this->whenLoaded('slots')),
    ];

    if (array_key_exists('squad_name', $this->resource->toArray())) {
        $collection['squad_name'] = $this->squad_name;
    }
    
    return $collection;
}

Is there another way to avoid the relationship being loaded if the attribute is not asked without having spam my resource with multiple if’s?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

The easiest and most reliable way I have found was to make a function in a helper class that checks this for me.

This way you can also customize it to your needs.

— RequestHelper class

public static function inAppends(string $value)
{
    $appends = strpos(request()->append, ',') !== false ? preg_split('/, ?/', request()->append) : [request()->append];
    return in_array($value, $appends);
}

— Resource
'squad_name' => $this->when(RequestHelper::inAppends('squad_name'), function () {
    return $this->squad_name;
}),


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x