ホームページ  >  記事  >  PHPフレームワーク  >  Laravel は Resource! を使用してカスタム ページング情報を返す実装を実装しています。

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

藏色散人
藏色散人転載
2022-02-03 04:00:303136ブラウズ

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 クラスに追加します。例: <pre class="brush:php;toolbar:false">public function paginationInformation($request, $paginated, $default): array     {         return [             'page' =&gt; $paginated['current_page'],             'per_page' =&gt; $paginated['per_page'],             'total' =&gt; $paginated['total'],             'total_page' =&gt; $paginated['last_page'],         ];     }</pre> <p>这是自定义后的数据输出情况:</p> <pre class="brush:php;toolbar:false">{     &quot;data&quot;: [],     &quot;page&quot;: 1,     &quot;per_page&quot;: 15,     &quot;total&quot;: 5,     &quot;total_page&quot;: 1}</pre> <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 サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。