vincent15000's avatar

API resources and accessors

Hello,

I have this code.

protected function price(): Attribute
{
    return Attribute::make(
        get: fn ($value) => $value / 100,
        set: fn ($value) => (int) round($value * 100),
    );
}

protected function expenses(): Attribute
{
    return Attribute::make(
        get: fn (int $value) => $value / 100,
        set: fn (float $value) => (int) round($value * 100),
    );
}

And this one.

public function toArray(Request $request): array
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'city' => $this->city,
        'price' => $this->price,
        'expenses' => $this->expenses,
        'total' => $this->total,
        'theme' => new ThemeResource($this->whenLoaded('theme')),
        'client' => new ClientResource($this->whenLoaded('client')),
    ];
}

But the value of the price and the expenses variables are not converted via the accessor.

Why ?

Thanks for your help.

V

0 likes
2 replies
LaryAI's avatar
Level 58

Great question! The reason your price and expenses accessors aren't being applied is likely because you're accessing them on the Eloquent model resource ($this in the resource), not the model itself. By default, Laravel API Resources ($this->resource) wrap the model, but if your resource is fed an array or individual values, accessors won’t run.

Solution:
Make sure your resource is receiving the Eloquent model, not an array. Instead of doing:

return new YourResource($yourModel->toArray());

just do:

return new YourResource($yourModel);

Or, if you want to be explicit in the resource itself, always fetch model attributes as properties:

'price' => $this->price,
'expenses' => $this->expenses,

If you already do this but still get raw values, double-check how you pass the data to the resource! Accessors only work when you’re using the Eloquent model, not plain arrays.

vincent15000's avatar
vincent15000
OP
Best Answer
Level 63

It worked fine.

I've just forgotten that the values I stored with the seeder were not in the right format (already cents instead of euros).

Please or to participate in this conversation.