如何从 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
}

我得到了预期的结果,具有 metalinks 属性:

{
    "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() 函数只是简单地从响应中打印出链接 属性。