#development #laravel #php

I've run into a problem where I've used an attribute casted as an array in a Laravel resource and I wanted to preserve the keys of that array. By default, Laravel will re-index the array, which is not what I wanted.

To preserve the keys, you can use the preserveKeys method on the collection. Here's an example:

 1namespace App\Http\Resources;
 2
 3use Illuminate\Http\Resources\Json\JsonResource;
 4
 5class User extends JsonResource
 6{
 7    /**
 8     * Indicates if the resource's collection keys should be preserved.
 9     *
10     * @var bool
11     */
12    public $preserveKeys = true;
13}

When the preserveKeys property is set to true, collection keys will be preserved:

1use App\User;
2use App\Http\Resources\User as UserResource;
3
4Route::get('/user', function () {
5    return UserResource::collection(User::all()->keyBy->id);
6});

What I didn't know is that this didn't only apply to the resource, but also to the attributes of the resource.

If you don't want to enable this option for the complete resource, once approach you can take is to create a new resource like this:

 1namespace App\Http\Resources;
 2
 3use Illuminate\Http\Request;
 4use Illuminate\Http\Resources\Json\JsonResource;
 5
 6class ArrayPreservingKeysResource extends JsonResource
 7{
 8    /**
 9     * Indicates if the resource's collection keys should be preserved.
10     *
11     * @var bool
12     */
13    public $preserveKeys = true;
14
15    public function toArray(Request $request): array
16    {
17        return $this->resource;
18    }
19}

You can then apply to any array you want to preserve the keys of in the resource:

 1namespace App\Http\Resources;
 2
 3use App\Domains\Predictions\Models\Prediction;
 4use Illuminate\Http\Request;
 5use Illuminate\Http\Resources\Json\JsonResource;
 6
 7/**
 8 * @mixin Company
 9 */
10class CompanyResource extends JsonResource
11{
12    public function toArray(Request $request): array
13    {
14        return [
15            'id' => $this->id,
16            'name' => $this->name,
17            'data' => new ArrayPreservingKeysResource($this->data),
18        ];
19    }
20}