Laravel 5.6: настройка мета-страницы коллекции ресурсов и атрибутов ссылок - PullRequest
0 голосов
/ 22 ноября 2018

Как мне настроить мета и ссылки Laravel ResourceCollection информация.

Ссылки должны включать только prev, next и self вместо first, last, prev, next, следующее по умолчанию.

Meta должно включать информацию о разбиении на страницы, например: 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 Ответ

0 голосов
/ 23 ноября 2018

Я не был фанатом того, как 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);
}
...