首先看看ArrayDataProvider官方的doc:php
ArrayDataProvider implements a data provider based on a data array.
ArrayDataProvider
实现了一个基于数据数组的数据提供器。htmlThe [[allModels]] property contains all data models that may be sorted and/or paginated.
[[allModels]]
包含了须要排序和(或)分页的全部数据模型。数据库ArrayDataProvider will provide the data after sorting and/or pagination.
ArrayDataProvider
提供排序和(或)分页后的数据。数组You may configure the [[sort]] and [[pagination]] properties to
customize the sorting and pagination behaviors.
你能够配置[[sort]]
和[[pagination]]
属性自定义排序和分页行为。服务器Elements in the [[allModels]] array may be either objects (e.g. model objects) or associative arrays (e.g. query results of DAO).
[[allModels]]
数组中的元素也许是对象(如,model对象)也许是关联数组(如,PDO的查询结果)。yii2Make sure to set the [[key]] property to the name of the field that uniquely identifies a data record or false if you do not have such a field.
确保设置的[[key]]
属性是惟一标识一条记录的字段的名字,若是没有这样的字段,则设为false。lessCompared to [[ActiveDataProvider]], ArrayDataProvider could be less efficient because it needs to have [[allModels]] ready.
与[[ActiveDataProvider]]
比较,ArrayDataProvider
可能效率较低,由于它须要准备[[allModels]]
。yiiArrayDataProvider may be used in the following way:
ArrayDataProvider
能够按照下面的方式使用:异步$query = new Query; $provider = new ArrayDataProvider([ 'allModels' => $query->from('post')->all(), 'sort' => [ 'attributes' => ['id', 'username', 'email'], ], 'pagination' => [ 'pageSize' => 10, ], ]); // get the posts in the current page $posts = $provider->getModels();Note: if you want to use the sorting feature, you must configure the [[sort]] property
so that the provider knows which columns can be sorted.
注意:你给你想使用排序功能,你必须配置[[sort]]
属性。ide@author Qiang Xue <qiang.xue@gmail.com>
@since 2.0
从上面的指南能够看出,使用ArrayDataProvider
须要准备好[[allModels]]
数据,才开始渲染视图,并实现分页。
ArrayDataProvider
是先把数据拉渠道内存中,而后再根据已有数据进行分页,这一点感受像JQuery的DataTables插件,可是DataTables插件支持异步获取数据,也就是说能够根据配置能够分页从数据库中获取数据,显然,yii2自带的ArrayDataProvider明显不提供此功能。
先看看,yii2的ArrayDataProvider提供预处理models的方法,该方法处理排序和分页:
/** * @inheritdoc */ 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()); } } return $models; }
对于分页代码,如过设置了pagination对象,也就是设置了分页,则统计数据总条数,而后根据每页的大小分片。
if (($pagination = $this->getPagination()) !== false) {
$pagination->totalCount = $this->getTotalCount(); if ($pagination->getPageSize() > 0) { $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit()); }}
再看看另外一个方法,yii2的ArrayDataProvider提供的数据统计总条数的方法:
/** * @inheritdoc */ protected function prepareTotalCount() { return count($this->allModels); }
是的,ArrayDataProvider默认计算分页总数是根据allModels数组计算的,而allModels的数据就是咱们查询赋值给提供器的。
这里面有两个很重要的方法必须看看:
public function getTotalCount() { if ($this->getPagination() === false) { return $this->getCount(); } elseif ($this->_totalCount === null) { $this->_totalCount = $this->prepareTotalCount(); } return $this->_totalCount; }
该方法就是统计数据总数的,相应的应该有一个设置数据总数的:
public function setTotalCount($value) { $this->_totalCount = $value; }
而在ArrayDataProvider及其分类中,并无一个public的totalCount属性,所以yii在处理的时候,将totalCount经过魔法函数进行设置,由于yii2中全部的类都是Object的子类,关于魔法函数,这一块内容参考深刻理解yii2.0,在此感谢做者带咱们走的这么深。
所以,无论你分页不分页,ArrayDataProvider并非服务器端分页的,而是将已有数据分页处理的。
这种状况,若是数据量很大的时候,一点也很差,线上服务动辄上百万的数据,一会儿拿出来分页,服务器吃不消,你也耗不起这个等待时间。
下面,咱们须要重写这两个方法:
models预处理方法
取消对已有数据的分片处理,统计数据总数根据咱们的方式统计,好比数据库中的总条数。
/* * @inheritdoc */ 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(); } return $models; }
统计总数预处理函数
直接获取经过getTotalCount()函数获取传递给数据提供器的数据总和。
/* * @inheritdoc */ protected function prepareTotalCount() { return $this->getTotalCount(); }
下面给出重写后的完整ArrayDataProvider:
<?php namespace backend\extensions; use Yii; use yii\base\Component; class ArrayDataProvider extends \yii\data\ArrayDataProvider { /* * @inheritdoc */ 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(); } return $models; } /* * @inheritdoc */ protected function prepareTotalCount() { return $this->getTotalCount(); } }
最后,来一个实际使用案例:
// TODO 业务逻辑 $data = ... // 数据数组或对象 $count = ... // 数据总条数,并非count($data)的值,是数据库中符合条件的全部数据总数 $dataProvider = new \backend\extensions\ArrayDataProvider([ 'allModels' => $data, 'totalCount' => isset($count) ? $count : 0, 'key' => 'ltime', 'sort' => [ 'attributes' => [ 'gmv', 'ltime', 'uv' ], 'defaultOrder' => [ 'gmv' => SORT_DESC, 'ltime' => SORT_DESC, 'uv' => SORT_DESC, ], ], 'pagination' => [ 'pageSize' => 15, ], ]); // 传递到test视图渲染 return $this->render('test', ['model' => $model, 'dataProvider' => $dataProvider]);
在视图层接收该数据提供器,传递给一个数据渲染插件,好比GridView:
echo GridView::widget([ 'dataProvider' => $dataProvider, 'columns' => [ ['class' => 'yii\grid\SerialColumn'], [ 'class' => 'yii\grid\DataColumn', 'value' => function ($data) { if (isset($data['ltime']) && !empty($data['ltime'])) { return date('Y-m-d', $data['ltime']); } }, 'label' => '日期', 'format' => 'raw', ], 'moneyPerUvOrder:raw:订单UV单价', 'moneyPerUvPurchase:raw:销售UV单价' ] ]);
到此结束,若是帮到你,请点击收藏!