miguelsmuller
miguelsmuller

Reputation: 59

Hide attributes relationship from laravel eloquent resources collection

I'm trying to building API Resource and I wanna hide in collection the relationship attribute.

For example, I want to hide attribute 'permissions' only in RoleCollection. I mean I just only wanna hide this attribute in Collection, not Resource. Because Collection be called from Resource but I don't want to hide it in Resource.

Role.php

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class Role extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'created_at' => $this->created_at->format('Y-m-d H:i:s'),
            'updated_at' => $this->updated_at->format('Y-m-d H:i:s'),
            'permissions' => Permission::collection($this->permissions),
        ];
    }
}

RoleCollection.php

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class RoleCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return parent::toArray($request);
    }
}

RoleController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Spatie\Permission\Models\Role;
use App\Http\Resources\Role as RoleResource;
use App\Http\Resources\RoleCollection;

class RoleController extends Controller
{
    public function index()
    {
        $resource = Role::paginate();    
        return new RoleCollection($resource);
    }

    public function show($id)
    {
        $resource = Role::with('permissions')->find($id);    
        return new RoleResource($resource);
    }
}

Response from: api/role/1

{
    "data": {
        "id": 1,
        "name": "Super Administrador",
        "created_at": "2019-05-07 16:45:38",
        "updated_at": "2019-05-07 16:45:38",
        "permissions": [
            {
                "id": 1,
                "name": "user.list"
            },
            {
                "id": 2,
                "name": "user.view"
            },
            {
                "id": 3,
                "name": "user.save"
            },
            {
                "id": 4,
                "name": "user.delete"
            }
        ]
    }
}

Response from : /api/roles

{
    "data": [
        {
            "id": 1,
            "name": "Super Administrador",
            "created_at": "2019-05-07 16:45:38",
            "updated_at": "2019-05-07 16:45:38",
            "permissions": [
                {
                    "id": 1,
                    "name": "user.list"
                },
                {
                    "id": 2,
                    "name": "user.view"
                },
                {
                    "id": 3,
                    "name": "user.save"
                },
                {
                    "id": 4,
                    "name": "user.delete"
                }
            ]
        },
        {
            "id": 2,
            "name": "Administrador",
            "created_at": "2019-05-07 16:45:38",
            "updated_at": "2019-05-07 16:45:38",
            "permissions": []
        }
    ],
    "links": {
        "first": "http://127.0.0.1:32773/api/roles?page=1",
        "last": "http://127.0.0.1:32773/api/roles?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "http://127.0.0.1:32773/api/roles",
        "per_page": 15,
        "to": 2,
        "total": 2
    }
}

Upvotes: 1

Views: 2422

Answers (2)

Thomas Van der Veen
Thomas Van der Veen

Reputation: 3226

One way to do this is to use the whenLoaded method. The whenLoaded will return a MissingValue instance when a relationship has not been loaded. Laravel in turn will exclude this property from your resonse.

It is not only useful for hiding properties in certain responses, but also helps with performance. Currently your resource will do a query to fetch Permission models for every Role when this relationship was not loaded.

Your resource could look like:

return [
    ...
    'permissions' => Permission::collection($this->whenLoaded('permissions')),
];

Laravel docs

Upvotes: 2

Leonardo Rossi
Leonardo Rossi

Reputation: 3022

One of the best way to handle this stuff is to use Fractals.

You can define a Transformer class for all your model, handle whether to include relationships or not every time you call them, and you can also define what attributes to show or to hide.

Basically you have one and only one point where your model can be serialized in JSON and you put all your logic there.

Also you can JSON-ize whole collections, through the single model transformers, very handy!

Upvotes: 0

Related Questions