前言
實現:透過對ArrayDataProvider
的繼承和稍微的改動之後,讓ArrayDataProvider
能夠實現指定某一頁再查詢功能。
Yii2提供了三個資料提供者,分別是:
- yii\data\ActiveDataProvider
- yii\data\SqlDataProvider
- yii\data\ArrayDataProvider
對ArrayDataProvider
的介紹如下:
yii\data\ArrayDataProvider 非常適用於大的陣列。資料提供者允許你返回一個 經過一個或者多個欄位排序的陣列資料頁面。為了使用 yii\data\ArrayDataProvider, 你應該指定 allModels 屬性作為一個大的陣列。 這個大陣列的元素既可以是一些關聯陣列(例如:DAO查詢出來的結果) 也可以是一些物件(例如:Active Record例項)
在實踐過程中,我對ArrayDataProvider
的理解是:
假設傳入一個陣列擁有100項,每頁顯示10條資料。那麼ArrayDataProvider
就會自動給你分成10頁。倘若我這個陣列很大的話,那麼這個資料提供者的效率就會降低。
可是我想讓ArrayDataProvider
擁有如ActiveDataProvider
的功能:點選哪一頁就開始查詢哪一頁的資料,而不是一開始就將所有資料載入進來。
開始
我的需求
我目前正在做ES查詢的結果用ArrayDataProvider
提供分頁。可是我ES返回的資料集合可能很大,幾千甚至幾萬條(當然誇張了)。這麼大的資料集合一次性返回給ArrayDataProvider
做分頁肯定不行。於是有沒有其他的方案呢,能夠讓我指定某一頁查詢。
改造
本身ES是支援分頁的,兩種方式:
- from
- lastid
對ES來說幾千幾萬條資料分頁也是最好採用lastId的方式,而不是用from。但是為了能夠實現分頁功能,用的是from。lastId似乎不能跳頁(若錯求指正)。
於是我只要能夠讓ArrayDataProvider
每次只顯示ES查詢的當前頁即可實現。於是改動如下:
1、定義一個類MyArrayDataProvider
繼承ArrayDataProvider
<?php
namespace app\utils;
use yii\data\ArrayDataProvider;
class MyArrayDataProvider extends ArrayDataProvider
{
protected function prepareModels()
{
if (($models = $this->allModels) === null) {
return [];
}
if (($sort = $this->getSort()) !== false) {
$models = $this->sortModels($models, $sort);
}
if (($pagination = $this->getPagination()) !== false) {
$pagination->totalCount = $this->getTotalCount();
if ($pagination->getPageSize() > 0) {
// $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit(), true);
$models = array_slice($models, 0, $pagination->getLimit(), true);
}
}
return $models;
}
}
然後在資料提供者ArrayDataProvider
改成MyArrayDataProvider
。用法全部都和文件一樣。
<?php
//...
$from = ($page-1) * $pageSize;
// 然後透過ES查詢的時候傳遞 from 分頁查詢
$dataProvider = new MyArrayDataProvider([
'allModels' => $data, //$data是一個分頁查詢後的陣列
'pagination' => ['pageSize'=>10,], // pagination 用於分頁
'totalCount' => $totalCount,
]);
討論
畢竟對Yii還沒有很深入的去學習,你們是怎麼做的呢?
本作品採用《CC 協議》,轉載必須註明作者和本文連結