最近向Laravel 框架提交了一個想法— 在PaginatedResourceResponse
中加入一個自訂分頁資訊方法的偵測,以便在使用Resource
類別輸出資訊時,能夠非常方便地自訂分頁資訊。
為什麼需要它
我基本上都是在開發 API。早期時候我都是直接返回,但是這種方式有時候會出現一些問題,也不方便維護,加上經常需要添加自定義字段和針對不同端給出不同數據的情況,我後來就一直在使用Resource
來定義傳回的資料。 【推薦:laravel影片教學】
使用 Resource
很方便也能讓邏輯清晰。但它有個不好的地方,那就是分頁資訊太多了。針對API 專案而言,大多數情況下,預設輸出的分頁資訊裡很多欄位並不需要,並且由於經常對接的是一些老項目,需要沿用老的資料格式或做相容,分頁資訊的欄位大不相同,沒辦法直接使用預設回傳的分頁資訊。
我不知道大家是怎麼處理類似情況時的分頁資訊的,但在此之前,為了能夠達到目的,我通常有兩種做法,一是自訂Response
,在這裡面把資料資訊重新定義,二是將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; }
很簡單的處理方式,如果對應資源類別中有自訂的分頁資訊組成方法,那就使用它自己的,目前而言,這確實是個好想法。
於此,如何自訂分頁資訊應該很清晰了。那就是在自己對應的 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'], ]; }
这是自定义后的数据输出情况:
{ "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中文網其他相關文章!

Laravel優化Web開發流程的方法包括:1.使用路由系統管理URL結構;2.利用Blade模板引擎簡化視圖開發;3.通過隊列處理耗時任務;4.使用EloquentORM簡化數據庫操作;5.遵循最佳實踐提高代碼質量和可維護性。

Laravel是一個現代化的PHP框架,提供了強大的工具集,簡化了開發流程並提高了代碼的可維護性和可擴展性。 1)EloquentORM簡化數據庫操作;2)Blade模板引擎使前端開發直觀;3)Artisan命令行工具提升開發效率;4)性能優化包括使用EagerLoading、緩存機制、遵循MVC架構、隊列處理和編寫測試用例。

Laravel的MVC架構通過模型、視圖、控制器分離數據邏輯、展示和業務處理,提高了代碼的結構化和可維護性。 1)模型處理數據,2)視圖負責展示,3)控制器處理用戶輸入和業務邏輯,這種架構讓開發者專注於業務邏輯,避免陷入代碼泥潭。

Laravel是一個基於MVC架構的PHP框架,具有簡潔的語法、強大的命令行工具、便捷的數據操作和靈活的模板引擎。 1.優雅的語法和易用的API使開發快速上手。 2.Artisan命令行工具簡化了代碼生成和數據庫管理。 3.EloquentORM讓數據操作直觀簡單。 4.Blade模板引擎支持高級視圖邏輯。

Laravel適合構建後端服務,因為它提供了優雅的語法、豐富的功能和強大的社區支持。 1)Laravel基於MVC架構,簡化了開發流程。 2)它包含EloquentORM,優化了數據庫操作。 3)Laravel的生態系統提供瞭如Artisan、Blade和路由系統等工具,提升開發效率。

在這個技術不斷進步的時代,掌握先進的框架對於現代程序員至關重要。本文將通過分享 Laravel 框架中鮮為人知的技巧,幫助你提升開發技能。 Laravel 以其優雅的語法和廣泛的功能而聞名,本文將深入探討其強大的特性,提供實用技巧和竅門,幫助你打造高效且維護性高的 Web 應用程序。

Laravel 和 ThinkPHP 都是流行的 PHP 框架,在開發中各有優缺點。本文將深入比較這兩者,重點介紹它們的架構、特性和性能差異,以幫助開發者根據其特定項目需求做出明智的選擇。

在 Laravel 中構建用戶登錄功能是一個至關重要的任務,本文將提供一個全面的概述,涵蓋從用戶註冊到登錄驗證的每個關鍵步驟。我們將深入探討 Laravel 的內置驗證功能的強大功能,並指導您自定義和擴展登錄過程以滿足特定需求。通過遵循這些一步一步的說明,您可以創建安全可靠的登錄系統,為您的 Laravel 應用程序的用戶提供無縫的訪問體驗。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

SublimeText3漢化版
中文版,非常好用

Dreamweaver Mac版
視覺化網頁開發工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器