Как известно, слой 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
