Laravel は Resource! を使用してカスタム ページング情報を返す実装を実装しています。

藏色散人
リリース: 2022-02-03 04:00:30
転載
3024 人が閲覧しました

Laravel は Resource! を使用してカスタム ページング情報を返す実装を実装しています。


最近 Laravel フレームワークにアイデアを送信しました - カスタム ページ分割された情報メソッドの検出をPaginatedResourceResponseに追加して使用できるようにしましたリソースクラスが情報を出力する場合、ページング情報をカスタマイズすると非常に便利です。

#必要な理由

私は基本的に API を開発しています。初期の頃は常に直接返していましたが、この方法では時々問題が発生し、メンテナンスが不便でした。また、カスタム フィールドを追加したり、目的ごとに異なるデータを提供する必要が多くなったりしました。それ以来、この方法を使用しています

Resourceは、返されるデータを定義します。 [推奨:laravel ビデオチュートリアル]

Resourceを使用すると非常に便利で、ロジックを明確にすることができます。ただし、ページ分割された情報が多すぎるという欠点があります。 API プロジェクトの場合、ほとんどの場合、デフォルトの出力ページング情報の多くのフィールドは必要ありませんが、古いプロジェクトに接続されることが多いため、古いデータ形式を使用するか、互換性を持たせる必要があります。ページング情報のフィールドは次のとおりです。まったく異なるため、デフォルトで返されるページング情報を直接使用する方法はありません。

同様の状況で、誰もがページング情報をどのように処理するかはわかりませんが、その前に、目的を達成するには、通常 2 つの方法があります。1 つは、

Responseをカスタマイズすることです。ここでデータ情報が再定義されます。2 つ目は、Resourceのすべての関連クラスをカスタマイズすることです。

私は Laravel の最下層についてはあまり詳しくなく、抽象フレームワークの開発は苦手ですが、これを経験してみると、物事がずっと簡単になることがわかりました。可能であれば PR

src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.phpでページネーション情報を構築するとき、Resourceクラスに対応するコンポーネントのページネーション情報を使用できます。毎回行う必要はありません。多くのカテゴリをカスタマイズするのに苦労しましたか?そこで私はこのアイデアを Laravel フレームワークに提出しました。このコミットは最初は直接受け入れられませんでしたが、Taylor の調整後にマージされ、v8.73.2 でリリースされました。

Laravel にコードをコントリビュートするのはこれが初めてであり、このような大規模なコード ベースにマージ リクエストを送信するのも初めてです。直接採用されていませんが、結果はエキサイティングです十分。

使用例

それでは、簡単な使用例をご紹介します。

デフォルト出力
{ "data": [], "links": { "first": "http://cooman.cootab-v4.test/api/favicons?page=1", "last": "http://cooman.cootab-v4.test/api/favicons?page=1", "prev": null, "next": null }, "meta": { "current_page": 1, "from": 1, "last_page": 1, "links": [ { "url": null, "label": "« 上一页", "active": false }, { "url": "http://cooman.cootab-v4.test/api/favicons?page=1", "label": "1", "active": true }, { "url": null, "label": "下一页 »", "active": false } ], "path": "http://cooman.cootab-v4.test/api/favicons", "per_page": 15, "to": 5, "total": 5 }}
ログイン後にコピー

これはLaravelがデフォルトで出力するページング情報です。多くのフィールドがあります。もちろん、これだけあれば多くのシナリオに対応できます。しかし、それが原因でトラブルに巻き込まれてしまうこともあります。少し柔軟性が必要です。

ResourceCollectionクラスを使用する場合

まず、基礎となるロジックを見てみましょう。

ResourceCollectionがコントローラーから返されると、そのtoResponseメソッドが最終的に呼び出されて応答します。次に、このメソッドを直接見つけて見てみましょう:

/** * Create an HTTP response that represents the object. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse */ public function toResponse($request) { if ($this->resource instanceof AbstractPaginator || $this->resource instanceof AbstractCursorPaginator) { return $this->preparePaginatedResponse($request); } return parent::toResponse($request); }
ログイン後にコピー
現在のリソースがページング オブジェクトの場合、タスクがページング応答の処理に移行することがわかりますか。次に見てください:

/** * Create a paginate-aware HTTP response. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse */ protected function preparePaginatedResponse($request) { if ($this->preserveAllQueryParameters) { $this->resource->appends($request->query()); } elseif (! is_null($this->queryParameters)) { $this->resource->appends($this->queryParameters); } return (new PaginatedResourceResponse($this))->toResponse($request); }
ログイン後にコピー
ああ、また

PaginatedResourceResponseに転送されています。これは最終的に変更する必要があるクラスです。toResponseの内容が長すぎるため、ここではありません 投稿、とにかく応答データはここから始まります もちろんページング情報もここで処理されますが、独立したメソッドを持っています。このメソッドはpaginationInformationで、PR を送信する前のロジックです:

/** * Add the pagination information to the response. * * @param \Illuminate\Http\Request $request * @return array */ protected function paginationInformation($request) { $paginated = $this->resource->resource->toArray(); return [ 'links' => $this->paginationLinks($paginated), 'meta' => $this->meta($paginated), ]; }
ログイン後にコピー
注意していれば、

$this->resource## を考えることができるはずです# 実際には、これは上記のResourceCollectionのインスタンスであり、そのresourceはリスト データ (ページング情報インスタンス) です。それでは、なぜResourceCollectionでページング情報を処理できないのでしょうか?もちろんですが、何かを追加する必要があったので、それが私が提出したアイデアです。PR をマージした後のロジックは次のとおりです:

/** * Add the pagination information to the response. * * @param \Illuminate\Http\Request $request * @return array */ protected function paginationInformation($request) { $paginated = $this->resource->resource->toArray(); $default = [ 'links' => $this->paginationLinks($paginated), 'meta' => $this->meta($paginated), ]; if (method_exists($this->resource, 'paginationInformation')) { return $this->resource->paginationInformation($request, $paginated, $default); } return $default; }
ログイン後にコピー

非常に単純な処理方法であり、対応するリソース クラスにカスタム ページング情報構築メソッドがある場合は、現時点では独自の を使用します。 、これは確かに良いアイデアです。

この時点で、ページング情報をカスタマイズする方法が明確になっているはずです。つまり、

paginationInformation

メソッドを対応するResourceCollectionクラスに追加します。例:

public function paginationInformation($request, $paginated, $default): array { return [ 'page' => $paginated['current_page'], 'per_page' => $paginated['per_page'], 'total' => $paginated['total'], 'total_page' => $paginated['last_page'], ]; }
ログイン後にコピー
ログイン後にコピー

这是自定义后的数据输出情况:

{ "data": [], "page": 1, "per_page": 15, "total": 5, "total_page": 1}
ログイン後にコピー

结果如我所愿。

使用 Resource类时

我通常只喜欢定义一个Resource类来应对单个对象和列表的情况,这里主要关注如何处理列表数据的分页自定义。

在控制器中,我一般都是这样使用:

public function Index(){ // .... return SomeResource::collection($paginatedData);}
ログイン後にコピー

再来看看collection方法里做了什么:

/** * Create a new anonymous resource collection. * * @param mixed $resource * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection */ public static function collection($resource) { return tap(new AnonymousResourceCollection($resource, static::class), function ($collection) { if (property_exists(static::class, 'preserveKeys')) { $collection->preserveKeys = (new static([]))->preserveKeys === true; } }); }
ログイン後にコピー

原来它把数据转给了ResourceCollection,那么只需要将这个AnonymousResourceCollection做个自定义不就可以了。

总结

这是一个很小优化,但是很有用。

在此之前,如果想要随着Resource返回自定义分页信息,会比较麻烦,需要自定义很多东西,这样的方式,对老用户而言小菜一碟,但是对新手就可能是件棘手的问题。那么自此之后,无论是老用户还是新手这件事将变得易如反掌。只需要在对应的ResourceCollection类中添加paginationInformation方法,类似下面这样:

public function paginationInformation($request, $paginated, $default): array { return [ 'page' => $paginated['current_page'], 'per_page' => $paginated['per_page'], 'total' => $paginated['total'], 'total_page' => $paginated['last_page'], ]; }
ログイン後にコピー
ログイン後にコピー

不过,如果你使用的是Resource::collection($pageData)方式,那么还需要额外自定义一个ResourceCollection类,并重写对应Resource类的collection方法。

我通常会定义一个对应的基类,然后其它的都继承它。也可以做个trait,然后共用。

最后

其实,这个想法我很早就想提交的,但是我一直比较犹豫,这到底是不是一个很大众的需求。不过我最后想明白了,这样做既然能为我节省大量重复且危险的工作,有那么多的开发者,总会有人需要的,所以我提交了,同时也是验证下我的想法到底是否可行,我的做法是否最优,结果当然是我学到了很多,比如写稍微复杂的测试用例。

另外,我想知道大家有没其它方法,或你们是怎么对待不同情况的分页信息的。

最后的最后,你如果也有好的想法,那么尽快提交吧!

以上がLaravel は Resource! を使用してカスタム ページング情報を返す実装を実装しています。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:learnku.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!