How to get a single field from a Laravel whenLoaded resource

613 Views Asked by At

I am using a Laravel Resource to return my object. The object has optional relationships. My Resource code so far is below and is working as expected:

public function toArray(Request $request): array
{
    return [
        'id'                 => (string) $this->id,
        'attributes'         => [
            'name'             => $this->name,
            'status_id'        => $this->status_id,
            'created_at'       => $this->created_at,
            'updated_at'       => $this->updated_at,
        ],
        'relationships' => [
            'status'        => $this->whenLoaded('status'),
        ]
    ];
}

But I would like for the "status" relationship to only include one field from the model - the name. I thought just appending ->name would work. i.e. 'status' => $this->whenLoaded('status')->name,

This does work when the relationship is loaded, but generates an error when the relationship does not exist.

Is there any way to use whenLoaded and show only one field?

3

There are 3 best solutions below

0
Typhoon101 On

I think I have found the answer.

public function toArray(Request $request): array
{
    return [
        'id'                 => (string) $this->id,
        'attributes'         => [
            'name'             => $this->name,
            'status_id'        => $this->status_id,
            'created_at'       => $this->created_at,
            'updated_at'       => $this->updated_at,
        ],
        'relationships' => [
            'status' => $this->when(
                $this->resource->relationLoaded('status'), function ()
                {
                    return $this->resource->status->name;
                }),
        ]
    ];
}
1
Usama Akbar On

You can use the optional helper function provided by Laravel. The optional function accepts the object you want to work with and returns a new, nullable object. This way, you can safely access the "name" attribute even if the relationship is not loaded.

public function toArray(Request $request): array
{
    return [
        'id'          => (string) $this->id,
        'attributes'  => [
            'name'      => $this->name,
            'status_id' => $this->status_id,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ],
        'relationships' => [
            'status' => optional($this->whenLoaded('status'))->only('name'),
        ],
    ];
}
0
panthro On

You can add the value you wish to return from whenLoaded via the 2nd param, with the 3rd param being a default value to return.

'status' => $this->whenLoaded('status', 'the value I wish to return', 'a default value if relationship is not loaded');

There is an issue though if you want to return a field from the relationship:

'status' => $this->whenLoaded('status', $this->status->name);

The above looks like it will work. But by calling $this->status->name, and say you have no eager loaded the relationship, it will load the relationship and whenLoaded will have no effect.

A solution would be to use a callback:

'status' => $this->whenLoaded('status', fn () => $this->status->name);