如何从 laravel 8 中的 API 正确解码响应分页资源?
How to properly decode response paginated resource from an API in laravel 8?
我正在尝试开发一个 laravel 应用程序,它必须有一个内部 API 来始终获取数据和前端控制器来使用这个 API 来呈现视图。此 API 将由移动应用程序使用,因此所有请求都将由 API.
处理
这是我的 API 索引操作,工作正常:
public function index(Request $request)
{
$filters = $request->all();
$query = Place::query()->with('user');
if(!isset($filters['filterType']) || !in_array(Str::lower($filters['filterType']), ['and', 'or']) ){
$filters['filterType'] = 'or';
}
//apply filters
foreach($filters as $filter => $value){
if(Place::hasProperty($filter, app(Place::class)->getTable())){
if($filters['filterType'] == 'and'){
$query->where($filter, $value);
}
else{
$query->orWhere($filter, $value);
}
}
}
//sorting
if(!isset($filters['sortOrder']) || !in_array($filters['sortOrder'], ['asc', 'desc'])){
$sortOrder = 'desc';
}
else{
$sortOrder = $filters['sortOrder'];
}
if(isset($filters['sortBy'])){
$sortBy = $filters['sortBy'];
foreach(explode(',', $sortBy) as $sortField){
if(Place::hasProperty($sortField, app(Place::class)->getTable())){
$query->orderBy($sortField, $sortOrder);
}
}
}
//default pagination
if(!isset($filters['maxResults'])){
$filters['maxResults'] = 5;
}
if(!isset($filters['page'])){
$filters['page'] = 1;
}
//apply pagination
$results = $query->paginate($filters['maxResults'], ['*'], 'page', $filters['page']);
$resultsCollectionResource = PlaceResource::collection($results);
return $resultsCollectionResource;
}
如果我通过邮递员请求
http://api.site.test/places?fields=id,name,user_id
{
"maxResults": 2
}
我得到了预期的结果,具有 meta 和 links 属性:
{
"data": [
{
"id": 1,
"name": "Lubowitz Group (Customer-focused real-time complexity)",
"user_id": 3
},
{
"id": 2,
"name": "Heaney, Dietrich and Spencer (Fully-configurable multi-state processimprovement)",
"user_id": 10
}
],
"links": {
"first": "http://api.ourplaces.test/places?page=1",
"last": "http://api.ourplaces.test/places?page=5",
"prev": null,
"next": "http://api.ourplaces.test/places?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 5,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=1",
"label": "1",
"active": true
},
{
"url": "http://api.ourplaces.test/places?page=2",
"label": "2",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=3",
"label": "3",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=4",
"label": "4",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=5",
"label": "5",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=2",
"label": "Next »",
"active": false
}
],
"path": "http://api.ourplaces.test/places",
"per_page": 2,
"to": 2,
"total": 10
}
}
然后我有了前端控制器,这个动作:
public function index()
{
$request = Request::create(env('API_URL').'/places', 'GET');
$response = Route::dispatch($request);
$responseContent = $response->content();
$places = json_decode($responseContent);
return view('places.index', ['places' => $places]);
}
而这个观点:
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Places') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
@foreach($places->data as $place)
<div class="row">
<div class="col-md-12 text-center">
<h1 class="post-title">{{ $place->name }}</h1>
<p>{{ $place->streetAddress }}!</p>
<p><a href="{{ route('web.places.show', [ 'place' => $place->id ]) }}">Ver Sitio...</a></p>
</div>
</div>
<hr>
@endforeach
<div class="row">
<div class="col-md-12 text-center">
{{ $places->links() }}
</div>
</div>
</div>
</div>
</div>
</x-app-layout>
但我得到错误:
Error
Call to undefined method stdClass::links() (View: C:\xampp\htdocs\ourplaces\resources\views\places\index.blade.php)
我认为问题出在前端控制器中,我认为我对 API 发出了错误的请求,因为在发出 json_decode 之后,我得到了 stdClass 对象,而不是原来的对象API 控制器生成。
API 对象:
前端解码对象:
我做错了什么?
谢谢大家
编辑
根据@matiaslauriti 的回复,我将 API 呼叫更改为 guzzle:
public function index(Request $request)
{
//$places = redirect()->route('api.places.index', ['request' => $request ])->content();
$response = Http::get(env('API_URL').'/places');
$places = $response->object();
return view('places.index', ['places' => $places]);
}
但我仍然遇到完全相同的问题。我测试了 $response->object() 以外的其他方法,比如 collection。但是我从来没有得到一个可以在视图中使用 $places->links() 方法的对象。
$places->links()
你倾向于调用的这个函数是 Laravel paginator class 的成员,$places
应该是这个 class 的实例以支持这个函数
如果您想继续使用现有的实现并支持 Laravel 分页功能,您应该创建 Laravel lengthawarepaginator 的实例并手动创建分页器实例。
根据其参数,这可能看起来像这样:
在你的前端控制器中添加:
$paginatedPlaces = new LengthAwarePaginator($places->data, $places->meta->total, $places->meta->per_page)
然后将 $paginatedPlaces
传递给您的视图
我建议的第二个选项 是不使用 ->links()
函数只是简单地从响应中打印出链接 属性。
我正在尝试开发一个 laravel 应用程序,它必须有一个内部 API 来始终获取数据和前端控制器来使用这个 API 来呈现视图。此 API 将由移动应用程序使用,因此所有请求都将由 API.
处理这是我的 API 索引操作,工作正常:
public function index(Request $request)
{
$filters = $request->all();
$query = Place::query()->with('user');
if(!isset($filters['filterType']) || !in_array(Str::lower($filters['filterType']), ['and', 'or']) ){
$filters['filterType'] = 'or';
}
//apply filters
foreach($filters as $filter => $value){
if(Place::hasProperty($filter, app(Place::class)->getTable())){
if($filters['filterType'] == 'and'){
$query->where($filter, $value);
}
else{
$query->orWhere($filter, $value);
}
}
}
//sorting
if(!isset($filters['sortOrder']) || !in_array($filters['sortOrder'], ['asc', 'desc'])){
$sortOrder = 'desc';
}
else{
$sortOrder = $filters['sortOrder'];
}
if(isset($filters['sortBy'])){
$sortBy = $filters['sortBy'];
foreach(explode(',', $sortBy) as $sortField){
if(Place::hasProperty($sortField, app(Place::class)->getTable())){
$query->orderBy($sortField, $sortOrder);
}
}
}
//default pagination
if(!isset($filters['maxResults'])){
$filters['maxResults'] = 5;
}
if(!isset($filters['page'])){
$filters['page'] = 1;
}
//apply pagination
$results = $query->paginate($filters['maxResults'], ['*'], 'page', $filters['page']);
$resultsCollectionResource = PlaceResource::collection($results);
return $resultsCollectionResource;
}
如果我通过邮递员请求 http://api.site.test/places?fields=id,name,user_id
{
"maxResults": 2
}
我得到了预期的结果,具有 meta 和 links 属性:
{
"data": [
{
"id": 1,
"name": "Lubowitz Group (Customer-focused real-time complexity)",
"user_id": 3
},
{
"id": 2,
"name": "Heaney, Dietrich and Spencer (Fully-configurable multi-state processimprovement)",
"user_id": 10
}
],
"links": {
"first": "http://api.ourplaces.test/places?page=1",
"last": "http://api.ourplaces.test/places?page=5",
"prev": null,
"next": "http://api.ourplaces.test/places?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 5,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=1",
"label": "1",
"active": true
},
{
"url": "http://api.ourplaces.test/places?page=2",
"label": "2",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=3",
"label": "3",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=4",
"label": "4",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=5",
"label": "5",
"active": false
},
{
"url": "http://api.ourplaces.test/places?page=2",
"label": "Next »",
"active": false
}
],
"path": "http://api.ourplaces.test/places",
"per_page": 2,
"to": 2,
"total": 10
}
}
然后我有了前端控制器,这个动作:
public function index()
{
$request = Request::create(env('API_URL').'/places', 'GET');
$response = Route::dispatch($request);
$responseContent = $response->content();
$places = json_decode($responseContent);
return view('places.index', ['places' => $places]);
}
而这个观点:
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Places') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
@foreach($places->data as $place)
<div class="row">
<div class="col-md-12 text-center">
<h1 class="post-title">{{ $place->name }}</h1>
<p>{{ $place->streetAddress }}!</p>
<p><a href="{{ route('web.places.show', [ 'place' => $place->id ]) }}">Ver Sitio...</a></p>
</div>
</div>
<hr>
@endforeach
<div class="row">
<div class="col-md-12 text-center">
{{ $places->links() }}
</div>
</div>
</div>
</div>
</div>
</x-app-layout>
但我得到错误:
Error Call to undefined method stdClass::links() (View: C:\xampp\htdocs\ourplaces\resources\views\places\index.blade.php)
我认为问题出在前端控制器中,我认为我对 API 发出了错误的请求,因为在发出 json_decode 之后,我得到了 stdClass 对象,而不是原来的对象API 控制器生成。
API 对象:
前端解码对象:
我做错了什么? 谢谢大家
编辑
根据@matiaslauriti 的回复,我将 API 呼叫更改为 guzzle:
public function index(Request $request)
{
//$places = redirect()->route('api.places.index', ['request' => $request ])->content();
$response = Http::get(env('API_URL').'/places');
$places = $response->object();
return view('places.index', ['places' => $places]);
}
但我仍然遇到完全相同的问题。我测试了 $response->object() 以外的其他方法,比如 collection。但是我从来没有得到一个可以在视图中使用 $places->links() 方法的对象。
$places->links()
你倾向于调用的这个函数是 Laravel paginator class 的成员,$places
应该是这个 class 的实例以支持这个函数
如果您想继续使用现有的实现并支持 Laravel 分页功能,您应该创建 Laravel lengthawarepaginator 的实例并手动创建分页器实例。
根据其参数,这可能看起来像这样:
在你的前端控制器中添加:
$paginatedPlaces = new LengthAwarePaginator($places->data, $places->meta->total, $places->meta->per_page)
然后将 $paginatedPlaces
传递给您的视图
我建议的第二个选项 是不使用 ->links()
函数只是简单地从响应中打印出链接 属性。