Как известно, слой API Resources используется для настройки вывода данных по API. И в случае с обычным получением данных, мы могли бы сделать что-то вроде следующего:
Файл app\Http\Resources\ArticleCollection.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ArticleCollection extends ResourceCollection
{
public static $wrap = '';
public function toArray($request): array
{
return [
'articles' => $this->collection,
'articlesCount' => $this->count()
];
}
}
Файл app\Http\Controllers\ArticleController.php
<?php
namespace App\Http\Controllers;
use App\Http\Resources\ArticleCollection;
use App\Models\Article;
class ArticleController extends Controller
{
public function index(): array
{
return new ArticleCollection(Article::all());
}
}
И это будет нормально работать т.к. в ArticleCollection
попадает предусмотренная для этого коллекция со статьями которая, в свою очередь, подставляется в обертку $wrap
и выводится как json.
Но в случаях с paginate, будет немного иначе. Например:
<?php
namespace App\Http\Controllers;
use App\Http\Resources\ArticleCollection;
use App\Models\Article;
class ArticleController extends Controller
{
public function index(): array
{
return new ArticleCollection(Article::cursorPaginate(5));
}
}
Вывод получится вот таким:
Как видно, пустая обертка $wrap
проигнорирована и добавлена в общий вывод с пустым ключом. Но чтобы использовать удобный нам результирующий набор данных, можно использовать зарезервированный метод withResponse()
в коллекции ArticleCollection
. Изначально, он ничего не делает, но он выполняется после метода toArray()
и с помощью него можно скорректировать вывод.
Решение
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ArticleCollection extends ResourceCollection
{
public static $wrap = 'data';
public function withResponse($request, $response)
{
$arrResponse = json_decode($response->getContent(), true);
unset($arrResponse['links'], $arrResponse['meta']);
$response->setContent(json_encode($arrResponse['data']));
}
public function toArray($request): array
{
return [
'articles' => $this->collection,
'count' => $this->count(),
'pagination' => [
'per_page' => $this->perPage(),
'next_page_url' => $this->nextPageUrl(),
'prev_page_url' => $this->previousPageUrl(),
]
];
}
}
Что сделали: добавили $wrap = 'data';
, добавили метод withResponse()
, в нем выпилили links
и meta
и записали в контент ответа то, что в data
.
В toArray()
составили тот ответ для API
, который нужен. Методы пагинации типа nextPage
, perPage
и т.д. смотреть в доках:
https://laravel.com/docs/9.x/pagination#cursor-paginator-instance-methods