最近 Laravel フレームワークにアイデアを送信しました - カスタム ページ分割された情報メソッドの検出を PaginatedResourceResponse
に追加して使用できるようにしました リソース
クラスが情報を出力する場合、ページング情報をカスタマイズすると非常に便利です。
Resource は、返されるデータを定義します。 [推奨:
laravel ビデオチュートリアル ]
Resource を使用すると非常に便利で、ロジックを明確にすることができます。ただし、ページ分割された情報が多すぎるという欠点があります。 API プロジェクトの場合、ほとんどの場合、デフォルトの出力ページング情報の多くのフィールドは必要ありませんが、古いプロジェクトに接続されることが多いため、古いデータ形式を使用するか、互換性を持たせる必要があります。ページング情報のフィールドは次のとおりです。まったく異なるため、デフォルトで返されるページング情報を直接使用する方法はありません。
Response をカスタマイズすることです。ここでデータ情報が再定義されます。2 つ目は、
Resource のすべての関連クラスをカスタマイズすることです。
src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php でページネーション情報を構築するとき、
Resource クラスに対応するコンポーネントのページネーション情報を使用できます。毎回行う必要はありません。多くのカテゴリをカスタマイズするのに苦労しましたか?そこで私はこのアイデアを Laravel フレームワークに提出しました。このコミットは最初は直接受け入れられませんでしたが、Taylor の調整後にマージされ、v8.73.2 でリリースされました。
{ "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 }}
クラスを使用する場合
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
クラスに追加します。例: <div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">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'],
];
}</pre><div class="contentsignin">ログイン後にコピー</div></div><div class="contentsignin">ログイン後にコピー</div></div>
<p>这是自定义后的数据输出情况:</p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">{
"data": [],
"page": 1,
"per_page": 15,
"total": 5,
"total_page": 1}</pre><div class="contentsignin">ログイン後にコピー</div></div>
<p>结果如我所愿。</p>
<h4>
<span class="header-link octicon octicon-link"></span>使用 <code>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 サイトの他の関連記事を参照してください。