Yii2:ArrayDataProvider 小改动后支持分页查询
前言
实现:通过对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 协议》,转载必须注明作者和本文链接