自定义 Laravel 5.5 API 资源集合分页



我一直在使用 laravel api 资源。默认情况下,laravel提供链接和元,如下所示。

"links": {
"first": "https://demo.test/api/v2/taxes?page=1",
"last": "https://demo.test/api/v2/taxes?page=4",
"prev": null,
"next": "https://demo.test/api/v2/taxes?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 4,
"path": "https://demo.test/api/v2/taxes",
"per_page": 2,
"to": 2,
"total": 8
} 

但我不想要这个,相反,我想要类似的东西

"pagination": {
"total": 8,
"count": 8,
"per_page": 25,
"current_page": 1,
"total_pages": 1
}

我能够得到这些信息,但如果我return TaxResource::collection($taxes);,我不会得到这个。即使我有自定义收集方法

public static function collection($resource)
{
$resource->pagination = [
'total' => $resource->total(),
'count' => $resource->count(),
'per_page' => $resource->perPage(),
'current_page' => $resource->currentPage(),
'total_pages' => $resource->lastPage()
];
return parent::collection($resource);
}

它没有给予我想要的东西。但是如果我通过(TaxResource::collection($taxes))->pagination;参考,我就能得到它。但我希望当我这样做时将其退回return TaxResource::collection($taxes);

我对你的问题很感兴趣,并花了一些时间解决它。我想未来还有很多工作要做,以改进Eloquent:API Resources的功能

为了解决这个问题,我必须使用资源集合而不是资源

但是,如果需要自定义随集合返回的元数据,则需要定义资源集合

php artisan make:resource Tax --collection

php artisan make:resource TaxCollection

路线:

Route::get('/get-taxes', function () {
$taxes = Taxes::paginate();
return new TaxCollection($taxes);
});

税收.php:

<?php
namespace AppHttpResources;
use IlluminateHttpResourcesJsonResourceCollection;
class TaxCollection extends ResourceCollection
{        
public function toArray($request)
{
return [
'data' => $this->collection,
'pagination' => [
'total' => $this->total(),
'count' => $this->count(),
'per_page' => $this->perPage(),
'current_page' => $this->currentPage(),
'total_pages' => $this->lastPage()
],
];
}  
// Using Laravel < 5.6
public function withResponse($request, $response)
{
$originalContent = $response->getOriginalContent();
unset($originalContent['links'],$originalContent['meta']);
$response->setData($originalContent);
}
// Using Laravel >= 5.6
public function withResponse($request, $response)
{
$jsonResponse = json_decode($response->getContent(), true);
unset($jsonResponse['links'],$jsonResponse['meta']);
$response->setContent(json_encode($jsonResponse));
}
}

这解决了问题,但现在有一个新的问题: 与我不知道如何修改资源集合中的toArray字段不同,手册仅显示了我们发送未修改集合的'data' => $this->collection示例(资源集合允许我们更改元数据)。因此,如果我们只使用资源,那么我们可以修改集合数据,但不能修改元数据。

接受的答案对我不起作用(在 Laravel 5.6 中),但我找到了更好的方法恕我直言。

将分页信息保存在资源集合构造函数中,并将分页器资源替换为基础集合。

税收征收.php:

namespace AppHttpResources;
use IlluminateHttpResourcesJsonResourceCollection;
class TaxCollection extends ResourceCollection
{
private $pagination;
public function __construct($resource)
{
$this->pagination = [
'total' => $resource->total(),
'count' => $resource->count(),
'per_page' => $resource->perPage(),
'current_page' => $resource->currentPage(),
'total_pages' => $resource->lastPage()
];
$resource = $resource->getCollection();
parent::__construct($resource);
}
public function toArray($request)
{
return [
'data' => $this->collection,
'pagination' => $this->pagination
];
}
}

所以我发现在 PHP 中,您实际上可以在没有反射或其他解决方法的情况下调用祖父函数。

鉴于 TaxCollection 扩展了 ResoureCollection,进而扩展了 JsonResource,我们实际上可以绕过处理分页的 ResourceCollection 方法。

class TaxCollection extends ResourceCollection
{        
public function toArray($request)
{
return [
'data' => $this->collection,
'pagination' => [
'total' => $this->total(),
'count' => $this->count(),
'per_page' => $this->perPage(),
'current_page' => $this->currentPage(),
'total_pages' => $this->lastPage()
],
];
}  
public function toResponse($request)
{
return JsonResource::toResponse($request);
}
}

toResponse 方法调用不是静态的,而是调用祖父级 JsonResource::toResponse 方法,就像 parent::toResponse 调用 ResourceCollection toResponse(..) 实例方法一样。

这将从 JSON 响应中删除所有额外的分页字段(链接、元等),并允许您根据需要自定义响应toArray($request)

您还可以扩展JsonResource,AnonymousResourceCollection,ResourceCollection和最后的PaginatedResourceResponse

> @yrv16 Laravel 5.6 版本:

public function withResponse($request, $response)
{
$jsonResponse = json_decode($response->getContent(), true);
unset($jsonResponse['links'],$jsonResponse['meta']);
$response->setContent(json_encode($jsonResponse));
}

JsonResource 类附带了一个 extraal() 方法,它允许您指定在使用资源时要成为响应一部分的任何其他数据:

Route::get('/get-taxes', function () {
$taxes = Taxes::paginate();
return new TaxCollection($s)->additional([
'pagination' => [
'total' => $taxes->total,
...
]
]);
});

投票最多的答案对我不起作用(Laravel 10)。我需要在setData之前删除json_encodeTaxCollection.php

use IlluminateHttpResourcesJsonResourceCollection;
class TaxCollection extends ResourceCollection
{        
public function toArray($request)
{
return [
'data' => $this->collection,
'pagination' => [
'total' => $this->total(),
'count' => $this->count(),
'per_page' => $this->perPage(),
'current_page' => $this->currentPage(),
'total_pages' => $this->lastPage()
],
];
}  
// Using Laravel < 5.6
public function withResponse($request, $response)
{
$originalContent = $response->getOriginalContent();
unset($originalContent['links'],$originalContent['meta']);
$response->setData($originalContent);
}
// Using Laravel >= 5.6
public function withResponse($request, $response)
{
$jsonResponse = json_decode($response->getContent(), true);
unset($jsonResponse['links'],$jsonResponse['meta']);
$response->setContent(json_encode($jsonResponse));
}
// Using Laravel 10
public function withResponse($request, $response)
{
$jsonResponse = json_decode($response->getContent(), true);
unset($jsonResponse['links'],$jsonResponse['meta']);
$response->setContent($jsonResponse); // remove json_encode
}
}

在控制器中添加以下内容

return response()->json([
'data' => resource_collection(BookResource::collection(Book::all())),
]);

您可以通过这样的帮助程序函数来做到这一点

function resource_collection($resource): array
{
return json_decode($resource->response()->getContent(), true) ?? [];
}

最新更新