Я не был фанатом того, как Laravel реализовал нумераторы страниц и ресурсы, так как сложно делать определенные вещи, такие как проблема, о которой вы упоминали.
Internals
Прежде чем вы сможете настроить ваши ответы так, как вы хотите, вам сначала нужно понять, как 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);
}