You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel如何将分页元数据移至JSON末尾并嵌套进meta字段

Laravel分页返回格式自定义:将元数据嵌套进meta字段并后置

问题场景

在Laravel中使用paginate()方法返回分页数据时,默认JSON结果里的current_page等元数据排在顶部,需要将这些元数据移至JSON末尾,并嵌套到meta字段中。

当前返回格式

{
    "current_page": 1,
    "data": [
        {
            "id": 1,
            "created_at": "2022-07-20T00:00:00.000000Z",
            "updated_at": "2022-07-20T00:00:00.000000Z",
            "status": 1,
            "order": 1,
            "gallery_id": 22,
            "gallery": {
                "id": 22,
                "name": "Test Fine Art",
                "description": null,
                "image": null,
                "exhibition_count": 5,
                "has_created_exhibition": 1,
                "stripe_id": null,
                "pm_type": null,
                "pm_last_four": null,
                "trial_ends_at": null,
                "created_at": "2022-07-20T15:25:02.000000Z",
                "updated_at": "2022-07-20T15:25:03.000000Z",
                "deleted_at": null,
                "free_rooms_plan_id": 0,
                "free_rooms": 0,
                "thumbnail": null,
                "owner": {
                    "id": 187,
                    "first_name": "Alina",
                    "last_name": "test@gmail.com",
                    "email": "testt@gmail.com",
                    "email_verified_at": "2022-07-20T15:24:10.000000Z",
                    "is_active": 1,
                    "permission_level": 0,
                    "provider": null,
                    "provider_id": null,
                    "access_token": null,
                    "imported_user_id": 206,
                    "created_at": "2022-07-20T15:24:10.000000Z",
                    "updated_at": "2022-07-20T15:24:10.000000Z",
                    "deleted_at": null,
                    "permissions": {
                        "gallery_id": 22,
                        "user_id": 187,
                        "user_type": "owner"
                    }
                },
                "users": [
                    {
                        "id": 187,
                        "first_name": "Alina",
                        "last_name": "test@gmail.com",
                        "email": "test@gmail.com",
                        "email_verified_at": "2022-07-20T15:24:10.000000Z",
                        "is_active": 1,
                        "permission_level": 0,
                        "provider": null,
                        "provider_id": null,
                        "access_token": null,
                        "imported_user_id": 206,
                        "created_at": "2022-07-20T15:24:10.000000Z",
                        "updated_at": "2022-07-20T15:24:10.000000Z",
                        "deleted_at": null,
                        "permissions": {
                            "gallery_id": 22,
                            "user_id": 187,
                            "user_type": "owner"
                        }
                    }
                ]
            }
        }
    ],
    "first_page_url": "http://127.0.0.1:8000/api/lobby?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "http://127.0.0.1:8000/api/lobby?page=1",
    "links": [
        {
            "url": null,
            "label": "« Previous",
            "active": false
        },
        {
            "url": "http://127.0.0.1:8000/api/lobby?page=1",
            "label": "1",
            "active": true
        },
        {
            "url": null,
            "label": "Next »",
            "active": false
        }
    ],
    "next_page_url": null,
    "path": "http://127.0.0.1:8000/api/lobby",
    "per_page": 10,
    "prev_page_url": null,
    "to": 1,
    "total": 1
}

期望返回格式

{
    "data": [
        {
            "id": 1,
            "created_at": "2022-07-20T00:00:00.000000Z",
            "updated_at": "2022-07-20T00:00:00.000000Z",
            "status": 1,
            "order": 1,
            "gallery_id": 22,
            "gallery": {
                "id": 22,
                "name": "Test Fine Art",
                "description": null,
                "image": null,
                "exhibition_count": 5,
                "has_created_exhibition": 1,
                "stripe_id": null,
                "pm_type": null,
                "pm_last_four": null,
                "trial_ends_at": null,
                "created_at": "2022-07-20T15:25:02.000000Z",
                "updated_at": "2022-07-20T15:25:03.000000Z",
                "deleted_at": null,
                "free_rooms_plan_id": 0,
                "free_rooms": 0,
                "thumbnail": null,
                "owner": {
                    "id": 187,
                    "first_name": "Alina",
                    "last_name": "test@gmail.com",
                    "email": "testt@gmail.com",
                    "email_verified_at": "2022-07-20T15:24:10.000000Z",
                    "is_active": 1,
                    "permission_level": 0,
                    "provider": null,
                    "provider_id": null,
                    "access_token": null,
                    "imported_user_id": 206,
                    "created_at": "2022-07-20T15:24:10.000000Z",
                    "updated_at": "2022-07-20T15:24:10.000000Z",
                    "deleted_at": null,
                    "permissions": {
                        "gallery_id": 22,
                        "user_id": 187,
                        "user_type": "owner"
                    }
                },
                "users": [
                    {
                        "id": 187,
                        "first_name": "Alina",
                        "last_name": "test@gmail.com",
                        "email": "test@gmail.com",
                        "email_verified_at": "2022-07-20T15:24:10.000000Z",
                        "is_active": 1,
                        "permission_level": 0,
                        "provider": null,
                        "provider_id": null,
                        "access_token": null,
                        "imported_user_id": 206,
                        "created_at": "2022-07-20T15:24:10.000000Z",
                        "updated_at": "2022-07-20T15:24:10.000000Z",
                        "deleted_at": null,
                        "permissions": {
                            "gallery_id": 22,
                            "user_id": 187,
                            "user_type": "owner"
                        }
                    }
                ]
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 3,
        "links": [
            {
                "url": null,
                "label": "« Previous",
                "active": false
            },
            {
                "url": "http://127.0.0.1:8000/api/room?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": "http://127.0.0.1:8000/api/room?page=2",
                "label": "2",
                "active": false
            },
            {
                "url": "http://127.0.0.1:8000/api/room?page=3",
                "label": "3",
                "active": false
            },
            {
                "url": "http://127.0.0.1:8000/api/room?page=2",
                "label": "Next »",
                "active": false
            }
        ],
        "path": "http://127.0.0.1:8000/api/room",
        "per_page": 50,
        "to": 50,
        "total": 107
    }
}

当前控制器代码

public function avr_lobby(Request $request){
    return $lobbyRooms = LobbyRoom::orderBy('order','ASC')->with('gallery')->paginate(10);
}

解决方案

方法一:手动重组响应数据(快速实现)

直接在控制器内将分页实例的数据与元数据重新组合,快速满足需求:

public function avr_lobby(Request $request){
    $lobbyRooms = LobbyRoom::orderBy('order','ASC')->with('gallery')->paginate(10);
    
    return response()->json([
        'data' => $lobbyRooms->items(),
        'meta' => [
            'current_page' => $lobbyRooms->currentPage(),
            'from' => $lobbyRooms->firstItem(),
            'last_page' => $lobbyRooms->lastPage(),
            'links' => $lobbyRooms->links()->elements,
            'path' => $lobbyRooms->path(),
            'per_page' => $lobbyRooms->perPage(),
            'to' => $lobbyRooms->lastItem(),
            'total' => $lobbyRooms->total(),
            'next_page_url' => $lobbyRooms->nextPageUrl(),
            'prev_page_url' => $lobbyRooms->previousPageUrl(),
            'first_page_url' => $lobbyRooms->url(1),
            'last_page_url' => $lobbyRooms->url($lobbyRooms->lastPage()),
        ]
    ]);
}

方法二:全局自定义分页响应(复用性高)

如果多个接口需要统一格式,可通过分页宏全局修改,避免重复代码:

  1. 在App\Providers\AppServiceProvider.php的boot()方法中添加分页宏:
use Illuminate\Pagination\LengthAwarePaginator;

public function boot()
{
    LengthAwarePaginator::macro('toCustomJson', function () {
        return response()->json([
            'data' => $this->items(),
            'meta' => [
                'current_page' => $this->currentPage(),
                'from' => $this->firstItem(),
                'last_page' => $this->lastPage(),
                'links' => $this->links()->elements,
                'path' => $this->path(),
                'per_page' => $this->perPage(),
                'to' => $this->lastItem(),
                'total' => $this->total(),
                'next_page_url' => $this->nextPageUrl(),
                'prev_page_url' => $this->previousPageUrl(),
                'first_page_url' => $this->url(1),
                'last_page_url' => $this->url($this->lastPage()),
            ]
        ]);
    });
}
  1. 控制器中调用宏:
public function avr_lobby(Request $request){
    $lobbyRooms = LobbyRoom::orderBy('order','ASC')->with('gallery')->paginate(10);
    
    return $lobbyRooms->toCustomJson();
}

方法三:使用API资源类(规范RESTful格式)

通过Laravel的API资源类统一响应结构,适合大型项目的接口标准化:

  1. 创建单个资源类:
php artisan make:resource LobbyRoomResource

编辑app/Http/Resources/LobbyRoomResource.php:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class LobbyRoomResource extends JsonResource
{
    public function toArray($request)
    {
        // 可自定义返回字段,也直接使用父类默认逻辑
        return parent::toArray($request);
    }
}
  1. 创建资源集合类:
php artisan make:resource LobbyRoomCollection

编辑app/Http/Resources/LobbyRoomCollection.php:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class LobbyRoomCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'meta' => [
                'current_page' => $this->currentPage(),
                'from' => $this->firstItem(),
                'last_page' => $this->lastPage(),
                'links' => $this->links()->elements,
                'path' => $this->path(),
                'per_page' => $this->perPage(),
                'to' => $this->lastItem(),
                'total' => $this->total(),
                'next_page_url' => $this->nextPageUrl(),
                'prev_page_url' => $this->previousPageUrl(),
                'first_page_url' => $this->url(1),
                'last_page_url' => $this->url($this->lastPage()),
            ]
        ];
    }
}
  1. 控制器中使用资源集合:
use App\Http\Resources\LobbyRoomCollection;

public function avr_lobby(Request $request){
    $lobbyRooms = LobbyRoom::orderBy('order','ASC')->with('gallery')->paginate(10);
    
    return new LobbyRoomCollection($lobbyRooms);
}

内容的提问来源于stack exchange,提问作者Ghaith Tabbaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 11:15:37