Customising Laravel 5.5 Api Resource Collection pagination

I was interested in your question and spent some time resolving it. I guess there are a lot of work to be done to improve Eloquent: API Resources' functionality in the future.

In order to resolve it I must use Resource Collections instead of Resources:

However, if you need to customize the meta data returned with the collection, it will be necessary to define a resource collection

php artisan make:resource Tax --collection

or

php artisan make:resource TaxCollection

Route:

Route::get('/get-taxes', function () {
    $taxes = Taxes::paginate();
    return new TaxCollection($taxes);
});

TaxCollection.php:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class TaxCollection extends ResourceCollection
{        
    public function toArray($request)
    {
        return [
        'data' => $this->collection,
        'pagination' => [
            'total' => $this->total(),
            'count' => $this->count(),
            'per_page' => $this->perPage(),
            'current_page' => $this->currentPage(),
            'total_pages' => $this->lastPage()
        ],
    ];
    }  

    // Using Laravel < 5.6
    public function withResponse($request, $response)
    {
        $originalContent = $response->getOriginalContent();
        unset($originalContent['links'],$originalContent['meta']);
        $response->setData($originalContent);
    }

    // Using Laravel >= 5.6
    public function withResponse($request, $response)
    {
        $jsonResponse = json_decode($response->getContent(), true);
        unset($jsonResponse['links'],$jsonResponse['meta']);
        $response->setContent(json_encode($jsonResponse));
    }
}

This solve the problem but now there are new one: Unlike Resources I don't know how to modify toArray fields in Resource Collections, the manual shows only example with 'data' => $this->collection where we send not modified collection (Resource Collections allows us change meta data). So If we use just Resource then we can modify collection data but not meta data.


The accepted answer did not work for me (in Laravel 5.6), but I found a better way IMHO.

Save the pagination informations in your ResourceCollection constructor and replace the Paginator resource with the underlying Collection.

TaxCollection.php:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class TaxCollection extends ResourceCollection
{
    private $pagination;

    public function __construct($resource)
    {
        $this->pagination = [
            'total' => $resource->total(),
            'count' => $resource->count(),
            'per_page' => $resource->perPage(),
            'current_page' => $resource->currentPage(),
            'total_pages' => $resource->lastPage()
        ];

        $resource = $resource->getCollection();

        parent::__construct($resource);
    }

    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'pagination' => $this->pagination
        ];
    }
}

So I've discovered that in PHP you can actually call a grandparent function without reflection or other workarounds.

Given that TaxCollection extends ResoureCollection, which in turn extends JsonResource we can actually bypass the ResourceCollection method that handles the pagination.

class TaxCollection extends ResourceCollection
{        
    public function toArray($request)
    {
        return [
        'data' => $this->collection,
        'pagination' => [
            'total' => $this->total(),
            'count' => $this->count(),
            'per_page' => $this->perPage(),
            'current_page' => $this->currentPage(),
            'total_pages' => $this->lastPage()
        ],
    ];
    }  

    public function toResponse($request)
    {
        return JsonResource::toResponse($request);
    }
}

the toResponse method call is NOT static, but instead calling the grandparent JsonResource::toResponse method, just as parent::toResponse would call the ResourceCollection toResponse(..) instance method.

This will remove all extra pagination fields from the JSON response (links, meta, etc) and allow you to customize the response as you'd like in toArray($request)

Tags:

Laravel 5.5