Laravel 5.6: настройка мета-страницы коллекции ресурсов и атрибутов ссылок
Как я могу настроить метаданные 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: переопределить toResponse
в ResourceCollection
Вместо переопределения PaginatedResourceResponse
Вы можете просто переопределить toResponse
метод в ResourceCollection с облегченной версией аналогичного кода, например, так:
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);
}