Laravel 5.6:自定义分页资源集合元和链接属性
Posted
技术标签:
【中文标题】Laravel 5.6:自定义分页资源集合元和链接属性【英文标题】:Laravel 5.6: Customise a paginated resource collection meta and links attributes 【发布时间】:2019-04-25 02:20:21 【问题描述】:如何自定义 Laravel ResourceCollection 元和链接信息。
链接应仅包含 prev、next 和 self,而不是默认情况下的 first、last、prev、next。
元应包括分页信息,例如:current_page、total_items、items_per_page、total_pages,而不是 current_page、from、last_page、path、per_page、to、total。
这是元数据和链接信息现在在 JSON 响应中的样子:
"meta":
"currentPage": 2,
"current_page": 1,
"from": 1,
"last_page": 3,
"path": "http://localhost:8000/api",
"per_page": 5,
"to": 5,
"total": 14
,
"links":
"self": "http://localhost:8000/api",
"first": "http://localhost:8000/api?page=1",
"last": "http://localhost:8000/api?page=3",
"prev": null,
"next": "http://localhost:8000/api?page=2"
.. 我希望它是这样的:
"meta":
"current_page": 1,
"total_items": 15,
"per_page": 5,
"total_pages": 3
,
"links":
"prev": null,
"next": "http://localhost:8000/api?page=2"
"self": "http://localhost:8000/api",
【问题讨论】:
我的回答解决了你的问题吗? 【参考方案1】:我不喜欢 Laravel 如何实现分页器和资源,因为它很难做某些事情,比如你提到的问题。
内部
在以您想要的方式自定义响应之前,您首先需要了解 ResourceCollections 如何转换为响应。
资源集合的原始toResponse
方法如下所示:
public function toResponse($request)
return $this->resource instanceof AbstractPaginator
? (new PaginatedResourceResponse($this))->toResponse($request)
: parent::toResponse($request);
如果您进一步查看PaginatedResourceResponse
类,您将看到以下代码。
...
protected function paginationLinks($paginated)
return [
'first' => $paginated['first_page_url'] ?? null,
'last' => $paginated['last_page_url'] ?? null,
'prev' => $paginated['prev_page_url'] ?? null,
'next' => $paginated['next_page_url'] ?? null,
];
...
protected function meta($paginated)
return Arr::except($paginated, [
'data',
'first_page_url',
'last_page_url',
'prev_page_url',
'next_page_url',
]);
我建议您完整阅读Illuminate\Http\Resources\Json\PaginatedResourceResponse
和Illuminate\Http\Resources\Json\ResourceResponse
以了解发生了什么。
解决方案 1:创建自定义 PaginatedResourceResponse
一种解决方案是创建一个扩展PaginatedResourceResponse
的新类,并覆盖paginationLinks
方法。
所以它看起来像:
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,
];
然后您可以覆盖您的 toResponse
方法,使其看起来像:
public function toResponse($request)
return $this->resource instanceof AbstractPaginator
? (new CustomPaginatedResourceResponse($this))->toResponse($request)
: parent::toResponse($request);
如果您想进一步自定义响应,可以考虑覆盖覆盖其他方法。
解决方案 2:在 ResourceCollection 中覆盖 toResponse
您可以使用类似代码的轻量级版本覆盖 ResourceCollection 中的 toResponse
方法,而不是覆盖 PaginatedResourceResponse
,如下所示:
public function toResponse($request)
$data = $this->resolve($request);
if ($data instanceof Collection)
$data = $data->all();
$paginated = $this->resource->toArray();
// perform a dd($paginated) to see how $paginated looks like
$json = array_merge_recursive(
[
self::$wrap => $data
],
[
'links' => [
'first' => $paginated['first_page_url'] ?? null,
'last' => $paginated['last_page_url'] ?? null,
'prev' => $paginated['prev_page_url'] ?? null,
'next' => $paginated['next_page_url'] ?? null,
],
'meta' => [
'current_page' => $metaData['current_page'] ?? null,
'total_items' => $metaData['total'] ?? null,
'per_page' => $metaData['per_page'] ?? null,
'total_pages' => $metaData['total'] ?? null,
],
],
$this->with($request),
$this->additional
);
$status = $this->resource instanceof Model && $this->resource->wasRecentlyCreated ? 201 : 200;
return response()->json($json, $status);
解决方案 3:覆盖 withResponse
方法
一个更简单但功能可能不那么强大的选项是只覆盖资源集合中的withResponse
,如下所示:
public function withResponse($request, $response)
$data = $response->getData(true);
$prev = $data['links']['prev'];
$next = $data['links']['next'];
$self = $data['links']['self'];
$data['links'] = compact('prev', 'next', 'self');
$response->setData($data);
【讨论】:
感谢您的彻底回复。您能否详细说明如何执行您提到的这些覆盖?我对您的第二个解决方案最感兴趣,但不确定实施它所需的步骤。我应该在哪里添加新的toResponse
方法?
没关系,我在这个页面的帮助下解决了这个问题 - laravel.com/docs/5.8/eloquent-resources以上是关于Laravel 5.6:自定义分页资源集合元和链接属性的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 中通过自定义分页器分页方法实现伪静态分页链接以利于 SEO