其实有更优解针对API分页
在 app/Providers/AppServiceProvider.php 中:
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
JsonResource::withoutWrapping();
JsonResource::macro('paginationInformation', function (Request $request, array $paginated, array $default) {
return ['meta' => Arr::only($paginated, [
'current_page',
'last_page',
'per_page',
'total',
])];
});
}
}
只要加这个就行,其他都不用变,也不需要创建 Collection 类,只要基础的 Resource 类就行
那我给个完整版的
app/Providers/AppServiceProvider.php:
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}
public function boot(): void
{
JsonResource::withoutWrapping();
JsonResource::macro('paginationInformation', function (Request $request, array $paginated, array $default) {
return ['meta' => Arr::only($paginated, [
'current_page',
'last_page',
'per_page',
'total',
])];
});
}
}
app/Http/Resources/Api/UserResource.php:
<?php
namespace App\Http\Resources\Api;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'avatar' => $this->avatar,
];
}
}
app/Http/Controllers/Api/UsersController.php:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\Api\UserResource;
use App\Models\User;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
class UsersController extends Controller
{
public function index(): AnonymousResourceCollection
{
return UserResource::collection(User::query()->latest()->paginate());
}
}
routes/api.php:
<?php
use App\Http\Controllers\Api\UsersController;
use Illuminate\Support\Facades\Route;
Route::get('/users', [UsersController::class, 'index']);
访问接口 /api/users 返回的数据就是这样:
{
"data": [
{
"id": 1,
"name": "user",
"avatar": ""
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 1
}
}
如果是要对分页后的数据进行整理输出的话,可以使用through方法
return Product::paginate()->through(fn($p) => [
'id' => $p->id,
'name' => $p->name,
'price' => Number::currency($p->price, 'CNY', 'zh')
]);
这个返回的是一个AbstractPaginator对象,需要注意的是,这种方式不会走模型中定义的casts,当然你可以为casts数组中定义的字段定义对应的访问器,也可以用toArray方法来触发casts,
或者你也可以像下面这样处理,这种直接返回模型,同样会走casts相关的数据转换
return Product::paginate()->through(function($p) {
$p->marked = true;
unset($p->name);
return $p;
});
transform是集合的一个遍历方法,foreach是迭代语法结构, 这2个有什么关系呢?
分页数据处理,laravel不是有很多方法吗?你的目标是遍历处理数据,方法只是实现工具,因为每个业务数据处理是不同的,没必要过度封装,我个人一般都是ResourceCollection处理数据就行了,transform/map等等都可以,如果用JsonResource,每次遍历都会实例化一个JsonResource对象,如果不在乎实例开销,也可以只用JsonResource,我一般倾向于单独用ResourceCollection实现。

关于 LearnKu
建议用 Resource 定义数据输出转换。如果不想用 Resource,那么你需要明白几点:
如果分页里面的数据项是对象,处理后还是原对象,除了 transform 用哪个无所谓。 否则
transform 会改变当前数据,需要返回修改后的数据,否则将是一场空,它是 map 后赋值的快捷方法
foreach 只是循环,要变更数据,需要依个 put 或 最后统一赋值(类似 map 后修改)
each 类似 foreach,但只能单个修改,否则不会对原值有影响