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()), ] ]); }
方法二:全局自定义分页响应(复用性高)
如果多个接口需要统一格式,可通过分页宏全局修改,避免重复代码:
- 在
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()), ] ]); }); }
- 控制器中调用宏:
public function avr_lobby(Request $request){ $lobbyRooms = LobbyRoom::orderBy('order','ASC')->with('gallery')->paginate(10); return $lobbyRooms->toCustomJson(); }
方法三:使用API资源类(规范RESTful格式)
通过Laravel的API资源类统一响应结构,适合大型项目的接口标准化:
- 创建单个资源类:
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); } }
- 创建资源集合类:
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()), ] ]; } }
- 控制器中使用资源集合:
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
相关产品推荐
相关产品推荐

