Laravel 的限制條數再分頁

guaosi發表於2019-03-22

本文搬運自我自己的部落格

        有這麼一個需求,我想取出一個表(比如user表)中,按照某一排序規則(比如按照時間倒敘),取出前100條,進行分頁,每頁10條。應該如何實現?自然而然可能會這樣寫下:


$users = User::orderBy('id','desc')->limit(100)->paginate(10)

最後列印結果可以發現,limit並未生效,依舊是將所有結果進行分頁。

        本文中用到的user模型,資料,控制器,路由之類的都已經在另一篇文章 手摸手教你讓Laravel開發Api更得心應手 建立好了。

users表中的資料

user-data

繼續通過paginate方法來分頁以及行不通了。確幸Laravel框架給我們提供了自定義分頁類,我們通過使用自定義分頁類來達到我們限制條數再分頁的需求。

下面我們分別講解陣列手動分頁以及模型物件手動分頁

3.1. 需求

通過id來倒敘排序,並且取出前6條來分頁,每頁2條資料

3.2. 陣列

3.2.1. 程式碼

public function index1(Request $request){
    //將物件結果集轉為陣列結果集
    $data = User::orderBy('id','desc')->limit(6)->get()->toArray();
    //傳入頁數,預設值為1
    $page = $request->page ?? 1;
    //每頁的條數
    $perPage = 2;
    //計算每頁分頁的初始位置
    $offset = ($page * $perPage) - $perPage;
    //例項化LengthAwarePaginator類,並傳入對應的引數
    $data = new LengthAwarePaginator(array_slice($data, $offset, $perPage, true), count($data), $perPage,$page, ['path' => $request->url(), 'query' => $request->query()]);
    return $data;
}

3.2.2. 測試

符合我們的需求

array_paginate

3.2.3. 適用

比較適用於自建的陣列想進行分頁。

因為一開始就被轉換為陣列了,所以想要用模型中的方法是不可能了。

3.2.4. 缺點

1.無法使用對應模型裡的方法。

2.內建的Api資源無法正常使用。

當我們的UserResource.php裡的內容為這樣時:

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id'=>$this->id,
            'name' => $this->name,
            'status' => UserEnum::getStatusName($this->status),
            'created_at'=>(string)$this->created_at,
            'updated_at'=>(string)$this->updated_at
        ];
    }
}

此時在控制器中使用Api資源來返回結果


return UserResource::collection($data);

報錯,提示Trying to get property 'id' of non-object。這是由於我們傳入到內建分頁類中的是陣列而不是一開始的物件形式,所以提示找不到這個屬性。我們只需要進行一些稍微的修改。

public function toArray($request)
{
    return [
        'id'=>$this->resource['id'],
        'name' => $this->resource['name'],
        'status' => UserEnum::getStatusName($this->resource['status']),
        'created_at'=>(string)$this->resource['created_at'],
        'updated_at'=>(string)$this->resource['updated_at']
    ];
}

此時返回結果正常,但是不會報錯。但是還是有很多問題,比如,無法使用資料包裹,條件關聯等等。因為傳入的分頁是陣列而不是物件導致的。

所以說,陣列來進行分頁,只適用於自己構建的資料陣列。

3.3. 物件

接著解決上面的痛點,一開始我們就將物件結果集轉為了陣列結果集(百度上千篇一律都是轉成了陣列結果集),所以讓導致模型方法以及Api資源都不能很好地使用。

現在我們不轉換為陣列,直接用物件結果集來進行自定義分頁。

先來看一個函式


array_slice()

這是上面陣列能進行分頁的關鍵,可以指定從第幾個元素開始,顯示幾個元素。

那物件結果集是否有類似的方法可以呼叫?這樣我們就可以做出物件結果集的分頁了。答案是有的。文件中的集合方法slice()擁有一樣的功能。

3.3.1. 程式碼

public function index(Request $request){
    $data = User::orderBy('id','desc')->limit(6)->get();
    //傳入頁數,預設值為1
    $page = $request->page ?? 1;
    //每頁的條數
    $perPage = 2;
    //計算每頁分頁的初始位置
    $offset = ($page * $perPage) - $perPage;
    //例項化LengthAwarePaginator類,並傳入對應的引數
    $data = new LengthAwarePaginator($data->slice($offset,$perPage), count($data), $perPage,$page, ['path' => $request->url(), 'query' => $request->query()]);
    return UserResource::collection($data);
}

此時UserResource.php檔案中的內容為

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id'=>$this->id,
            'name' => $this->name,
            'status' => UserEnum::getStatusName($this->status),
            'created_at'=>(string)$this->created_at,
            'updated_at'=>(string)$this->updated_at
        ];
    }
}

3.3.2. 測試

沒有任何錯誤,符合我們的要求

object_paginate

3.3.3. 適用

非自建陣列,想使用模型的方法或者使用Api資源。

相關文章