I used laravel resources for my api responses and added paginate method. Upon using paginate method I always get a result like this where laravel by default gives three keys namely "data", "links" and "meta". But I want to change the resource to my own need.

{
"data": [
    {
        "id": 1,
        "name": "Eladio Schroeder Sr.",
        "email": "[email protected]",
    },
    {
        "id": 2,
        "name": "Liliana Mayert",
        "email": "[email protected]",
    }
],
"links":{
    "first": "http://example.com/pagination?page=1",
    "last": "http://example.com/pagination?page=1",
    "prev": null,
    "next": null
},
"meta":{
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "path": "http://example.com/pagination",
    "per_page": 15,
    "to": 10,
    "total": 10
}

}

But I want a result like this

{
"data": [
    {
        "id": 1,
        "name": "Eladio Schroeder Sr.",
        "email": "[email protected]",
    },
    {
        "id": 2,
        "name": "Liliana Mayert",
        "email": "[email protected]",
    }
],
"metadata": {
    "pagination": {
        "offset": 50,
        "limit": 25,
        "previousOffset": 25,
        "nextOffset": 75,
        "currentPage": 3,
        "pageCount": 40,
        "totalCount": 1000
    }
}

}

How can I be able to achieve this. I am using Laravel 7.*

My controller code:

public function index(Request $request)
{
    return DiscussionResource::collection($this->discussion->getDiscussionList($request));
}

My Model method looks like this:

public function getDiscussionList($request){
    return $this->ofSearch($request)
        ->orderBy('created_at', config('settings.pagination.order_by'))
        ->paginate(config('settings.pagination.per_page'));
}

My resource looks like this:

class DiscussionResource extends JsonResource
{
/**
 * Transform the resource into an array.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
public function toArray($request)
{
    return [
        'id' => $this->id,
        'question_id' => $this->question_id,
        'user_id' => $this->user_id,
        'user_image' => $this->user->userProfile->image,
        'user_role' => $this->user->type,
        'comment' => $this->comment,
        'is_pinned' => $this->is_pinned,
        'created_at' => $this->created_at->toDateString()
    ];
}

}

2

There are 2 best solutions below

0
On

If you want to customize the metadata you can take the help of the with() method that comes with laravel for collections.

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

If you want to customize it from controller you may do something like this

return (DiscussionResource::collection($this->discussion->getDiscussionList($request)))
                ->additional(['meta' => [
                    'key' => 'value',
                ]]);

And in case you want it for a single resource you can modify it at the toArray() method

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

For more details you can check this out https://laravel.com/docs/7.x/eloquent-resources#adding-meta-data

0
On

There are so many ways to do that in laravel and here you go 2 ways of it:

First Way: you can create a custom PaginatedResourceResponse and override the default paginationLinks. for example like below:

use Illuminate\Http\Resources\Json\PaginatedResourceResponse;

class CustomPaginatedResourceResponse extends PaginatedResourceResponse
{
    protected function paginationLinks($paginated)
    {
        return [
            'prev' => $paginated['prev_page_url'] ?? null,
            'next' => $paginated['next_page_url'] ?? null,
        ];
    }

    protected function meta($paginated)
    {
        $metaData = parent::meta($paginated);
        return [
            'current_page' => $metaData['current_page'] ?? null,
            'total_items' => $metaData['total'] ?? null,
            'per_page' => $metaData['per_page'] ?? null,
            'total_pages' => $metaData['total'] ?? null,
        ];
    }
}

then override toResponse method(Actually, the toResponse method converts resource collection to responses)

public function toResponse($request)
{
    return $this->resource instanceof AbstractPaginator
                ? (new CustomPaginatedResourceResponse($this))->toResponse($request)
                : parent::toResponse($request);
}

You may consider overriding other methods if you want to customize your response furthermore.

Second Way: you can just override the toResponse method in the ResourceCollection and make it as you wish!

More Ways HERE!