ahoi
3 months ago

"Nested pagination": Paginate (sub-)item in ApiResource

Posted 3 months ago by ahoi

Hello everybody,

I got an ApiResource like this:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Gate;


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

Now I'd like to add a relation to this: Items:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Gate;


class UserResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id'     => $this->id,
            'name'   => $this->name,
            'email'  => $this->email,
            'items'  => new ItemResourceCollection
            ($this->items()->paginate(5)),
            'status' => $this->status,
        ];
    }
    
}

This is ItemResourceCollection:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;


class ItemResourceCollection extends ResourceCollection
{
    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        return [
            'current_page'   => $this->resource->currentPage(),
            'first_page_url' => $this->resource->url(1),
            'from'           => $this->resource->firstItem(),
            'last_page'      => $this->resource->lastPage(),
            'last_page_url'  => $this->resource->url($this->lastPage()),
            'next_page_url'  => $this->resource->nextPageUrl(),
            'per_page'       => $this->resource->perPage(),
            'prev_page_url'  => $this->resource->previousPageUrl(),
            'to'             => $this->resource->lastItem(),
            'total'          => $this->resource->total(),
            'data'           => $this->collection->transform(function ($item) {
                return [
                    'id'          => $item->id,
                    'title'       => $item->title,
                    'status'      => $item->status,
                ];
            }),
        ];
    }
}

Well - this is the result:

{
  "data": {
    "id": 1,
    "name": "John Doe",
    "email": "[email protected]",
    "items": {
      "current_page": 1,
      "first_page_url": "http://example.org/api/user/1?page=1",
      "from": 1,
      "last_page": 1,
      "last_page_url": "http://example.org/api/user/1?page=1",
      "next_page_url": null,
      "per_page": 5,
      "prev_page_url": null,
      "to": 1,
      "total": 1,
      "data": [
        {
          "id": 1,
          "title": "Test",
          "description": "<p>Test</p>",
          "status": "published"
        }
      ]
    },
    "status": "active"
  }
}

Hm, it seems that this does not really work, because the page-urls are referring the parent model and not the relation?

I would love to see something like: http://example.org/api/user/items?page=1 or something like that and fetch the results using Axios on my frontend:

axios.get ('/api/user/items?page=' + this.pagination.current_page + '&length=' + this.pagination.per_page);

Any idea whether this is possible?

Otherwise I would have to create a route for /user/items/index or something like that and return data from there.

Please sign in or create an account to participate in this conversation.