Laravel 使用 Resource 遇到 Paginate 該怎辦

一般在 Controller 不處理直接 return $data 的結果

但想要優化程式碼,統一由Resource輸出,卻卡關不知道該怎輸出成page的樣式

1
return User::query()->paginate();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"current_page": 1,
"data": [
{
"id": 1,
"name": "泰斯特",
"gender": 1,
}
],
"first_page_url": "https://tyeydy.com?page=1",
"from": 1,
"last_page": 8,
"last_page_url": "https://tyeydy.com?page=8",
"links": [
{
"url": null,
"label": "pagination.previous",
"active": false
},
{
"url": "https://tyeydy.com?page=1",
"label": "1",
"active": true
}
],
"next_page_url": "https://tyeydy.com?page=2",
"path": "https://tyeydy.com",
"per_page": 1,
"prev_page_url": null,
"to": 1,
"total": 8
}

比較好的做法是經過 Resource 統一過濾後輸出需要的欄位與格式,避免一些多餘的資料產生,
也可以透過 Resource 進行一些格式的加工處理

當遇到 paginate 就無法直接用 Resource 會把無視page參數只輸出資料的內容
就需要用兩層的 Resource 搭配 內建的 paginate 達到一樣的格式

  • UserController

    1
    2
    $data = User::query()->paginate();
    return new UserPageResource();
  • 第一層 Resource - UserPageResource

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class TaskPageResource extends JsonResource
    {
    public function toArray($request)
    {
    return [
    'total' => $this->total(),
    'per_page' => $this->perPage(),
    'current_page' => $this->currentPage(),
    'last_page' => $this->lastPage(),
    'first_page_url' => $this->url(1),
    'last_page_url' => $this->url($this->lastPage()),
    'next_page_url' => $this->nextPageUrl(),
    'prev_page_url' => $this->previousPageUrl(),
    'data' => UserListResource::collection($this->items()),
    ];
    }
    }
  • 第二層 Resource - UserPageResource

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class UserListResource extends JsonResource
    {
    public function toArray($request)
    {
    return [
    'id' => $this->id,
    'name' => $this->_name(),
    ];
    }

    private function _name()
    {
    switch ($this->gender) {
    case 1:
    return sprintf('%s %s', $this->name, '先生');
    case 2:
    return sprintf('%s %s', $this->name, '小姐');
    default:
    return sprintf('%s %s', $this->name, '貴賓');
    }
    }
    }

官方文件的 page method 可以自由搭配

Method Description
$paginator->count() Get the number of items for the current page.
$paginator->currentPage() Get the current page number.
$paginator->firstItem() Get the result number of the first item in the results.
$paginator->getOptions() Get the paginator options.
$paginator->getUrlRange($start, $end) Create a range of pagination URLs.
$paginator->hasPages() Determine if there are enough items to split into multiple pages.
$paginator->hasMorePages() Determine if there are more items in the data store.
$paginator->items() Get the items for the current page.
$paginator->lastItem() Get the result number of the last item in the results.
$paginator->lastPage() Get the page number of the last available page. (Not available when using simplePaginate).
$paginator->nextPageUrl() Get the URL for the next page.
$paginator->onFirstPage() Determine if the paginator is on the first page.
$paginator->perPage() The number of items to be shown per page.
$paginator->previousPageUrl() Get the URL for the previous page.
$paginator->total() Determine the total number of matching items in the data store. (Not available when using simplePaginate).
$paginator->url($page) Get the URL for a given page number.
$paginator->getPageName() Get the query string variable used to store the page.
$paginator->setPageName($name) Set the query string variable used to store the page.

參考文章:
https://laravel.com/docs/9.x/pagination