Pagination not showing after I use Resource to display data
Asked Answered
D

2

6

I'm having issues with pagination after I use a resource to display data. Before this, I was using this code to display data, and the output shows the pagination as well.

Output enter image description here

Controller

$All = Customers::with('order')->paginate(10);

return response()->json([
    'code' => 0,
    'success' => true,
    'data' => $All,
], 200);

But right after I'm using Resources to display data, the pagination is gone.

$All = Customers::with('order')->paginate(10);

return response()->json([
    'code' => 0,
    'success' => true,
    'data' => DataResource::collection($All),
], 200);

DataResource

public function toArray($request)
{
    //return parent::toArray($request);
    return [
        'name' => $this->name,
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
        'order' => Resources::collection($this->order)
    ];
}
Desirous answered 19/8, 2019 at 3:18 Comment(0)
S
0

It appears you are using Eloquent: API Resources, although it is uncertain which version of Laravel is used because the newer version shows a very different pagination.

When I show a dump() of the first snippet, the paginator (also called the LengthAwarePaginator object) is in the root of the response:

LengthAwarePaginator {#406 ▼
  #total: 3
  #lastPage: 1
  #items: Collection {#401 ▶}
  #perPage: 10
  #currentPage: 1
  #path: "http://laravelsoplayground"
  #query: []
  #fragment: null
  #pageName: "page"
  +onEachSide: 3
  #options: array:2 [▶]
}

After the resources have been applied, the paginator is still present but has been moved to the resource attribute.

AnonymousResourceCollection {#331 ▼
  +collects: "App\Http\Resources\DataResource"
  +collection: Collection {#214 ▶}
  +resource: LengthAwarePaginator {#406 ▶}
  +with: []
  +additional: []
}
Spirituality answered 20/8, 2019 at 16:57 Comment(0)
U
0

I had this same problem and was confused because in the documentation it says:

You may pass a Laravel paginator instance to the collection method of a resource or to a custom resource collection... Paginated responses always contain meta and links keys with information about the paginator's state (Laravel 6 docs).

The problem is that these resource objects are designed to be returned directly rather than included in a larger JSON response. See my thoughts on why this is happening, here.

There's two ways you could solve this problem.

Solution 1 Eliminate the meta data being sent along with the response (the 'code', and 'success' fields). These are somewhat redundant because when the JSON resource is returned, it will be sent with an HTTP response who's status is 200 OK. Code that is consuming your API should be able to parse both the status and the status message. Your controller function would now look like this:

public function index()
{
    return new DataResource::collection(Customers::with('order')->paginate(10))
}

Solution 2 If the consumers of your API absolutely rely on the meta data your sending along, Laravel has a solution for that. Laravel provides a ResourceCollection class which can include arbitrary meta data.

While resources translate a single model into an array, resource collections translate a collection of models into an array. It is not absolutely necessary to define a resource collection class for each one of your model types since all resources provide a collection method to generate an "ad-hoc" resource collection on the fly. However, if you need to customize the meta data returned with the collection, it will be necessary to define a resource collection.

Begin by modifying your DataResource to extend Illuminate\Http\Resources\Json\ResourceCollection instead of Illuminate\Http\Resources\Json\Resource. You can then add meta data to the response in any of 3 ways. 1) By adding it to the array returned by the toArray() function. 2) Defining a with() function on the collection resource that is called when the resource is returned from a controller function. Or 3) append it to the resource when creating the collection (see docs). I'm going to show option 2 because it's only called when the collection is returned as the outer most resource.

Resource

use Illuminate\Http\Resources\Json\ResourceCollection;

class DataCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return [
            'name' => $this->name,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
            'order' => Resources::collection($this->order)
        ];
    }

    public function with($request)
        {
            return [
                'meta' => [
                    'success' => 'true',
                    'code' => 0,
                ],
            ];
        }

Controller

use App\Http\Resources\DataCollection;

public function index()
{
    return new DataCollection(Customers::with('order')->paginate(10));
}

Renaming your resource is optional, but matches convention. Meta tags you define will be merged with the meta tags created by the paginator.

This functionality has been in place since at least Laravel 6.X. Check docs for earlier compatibility if needed.

Undemonstrative answered 20/11, 2023 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.