简体   繁体   中英

Filter attributes in Laravel Resource Collection

In the new Laravel Resource classes, you are able to remove attributes based on anything you like.

If you want to return many items, you can use the function

Resource::collection()

But that does not let you add metadata in one place. Enter a Collection, great, this is many items in a nice format with the ability to add meta data. What you cannot do though, is filter the collection you have to hide attributes like you can with a resource. The only way I can see to do it is

foreach ($this->collection as $item) {
        if ($notAdmin) {
            $temp = array_except($item->toArray(), ['secret']);
        }
        $temp['links'] = ['self' => route('restaurant.show', [$item])];
        $data[] = $temp;
    }

Is there something I am missing? This seems like a massive overlooked ability for a Resource Collection

Based in this thread, it seems that when using a ResourceCollection class to customize a collection (for example BookCollection ) Laravel look up for a Resource class named the same but without the Collection sufix class (in the example, a class named just Book ).

So you will need to have a resource class named: Book where you customize the attributes to be returned to the response and a collection class named: BookCollection , that will use Book -to customize the data- and will also let you customize the metadata.

app/Http/Resources/Book.php

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class Book extends Resource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
        ];
    }
}

app/Http/Resources/BookCollection.php

<?php

namespace App\Http\Resources\Users;

use Illuminate\Http\Resources\Json\ResourceCollection;

class BookCollection extends ResourceCollection
{
    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request
     * @return array
     */
    public function toArray($request)
    {
        return $this->collection;
    }

    public function with($request)    
    {
        return [
            'meta' => [
                'key' => 'value',
            ],
        ];
    }
}

Ok, here's how you do it:

  1. Create a Resource for a single resource, where you can easily have conditional attributes

  2. Create a RCollection for the collection, where you can add meta data .

  3. Pass the Resource::collection(Model::all) into the new RCollection() .

Something like this (from my testing):

Route::get('users/all', function() {
    return new \App\Http\Resources\Users(
        \App\Http\Resources\UserResource::collection(\App\User::get())
    );
});

Works like a charm!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM