我们昨天说到了ActiveDataProvider、SqlDataProvider和ArrayDataProvider,从描述中不难发现这几个货的行为都差不多,因此yii2的开发者们为它们设置了一个BaseDataProvider的父类,而BaseDataProvider又实现了一个叫做DataProviderInterface的接口。
在PHP中,实现接口的类必须完成接口中声明的所有函数,当我们要看BaseDataProvider中有哪些可用方法的时候,首先要关注DataProviderInterface接口。
DataProviderInterface
- prepare
- getCount
- getTotalCount
- getModels
- getKeys
- getSort
- getPagination
以上是DataProviderInterface为我们提供的函数声明,也就是说BaseDataProvider类实现了这些函数,而我们的DataProvider三兄弟也因为继承了BaseDataProvider自然拥有了这些方法。
因此昨天的文章『小谈yii2中3个数据提供者及与GridView的搭配使用』中,我们大胆的使用了getCount、getTotalCount、getModels等。
接下来我们先说在BaseDataProvider中来自接口DataProviderInterface的方法。
prepare
数据准备,这是一个功能性的函数,它负责组装DataProvider中的_models和_keys属性,我们来大体看一下这个函数。
public function prepare($forcePrepare = false){
if ($forcePrepare || $this->_models === null) {
$this->_models = $this->prepareModels();
}
if ($forcePrepare || $this->_keys === null) {
$this->_keys = $this->prepareKeys($this->_models);
}
}
要研究明白这个函数,我们首先要了解下 _models 和 _keys 属性。
- _models 这个很容易理解,我们通过getModels或GridView得到的对象集或数组集合。每一项代表着具体的数据。
- _keys 表示每个数据项的唯一键,当我们使用ActiveDataProvider是就是每条数据的主键值,而其他两种DataProvider的是_models数组的key值。
prepare函数仅仅在BaseDataProvider类中定义,而每种DataProvider定义了自己的prepareModels和prepareKeys方法,因此我们在不同的DataProvider下调用prepare得到的是不同的值。
另外prepare也有一个叫做$forcePrepare的参数,用意很简单,是否在_models 和 _keys属性值已经存在的情况下强行刷新,默认为false不强行刷新。
getKeys
在介绍prepare的时候我们看到了prepareModels和prepareKeys,正因为有它们的存在我们才能正确通过getModels和getKeys函数拿到相应的数据。
我们先来说说getKeys函数,其实也就是在DataProvider中 $_keys 属性的内容。
这里有一点不同,我们来看下。
ActiveDataProvider
$dataProvider = new ActiveDataProvider([
'query' => Blog::find()->select(['title','id']),
'pagination' => [
'pageSize' => 20,
],
]);
VarDumper::dump($dataProvider->getKeys(),10,true);
我们得到的结果如下
[
0 => 1
1 => 2
2 => 3
3 => 4
4 => 5
5 => 9
]
是的,你一定发现了,_keys是一个数组,数组的key代表每一行数据项,value值代表对应数据的主键。
注意:如果你数据项中不存在id列,将返回null。比如我们上面代码的$query是Blog::find()->select(['title'])。
而针对ArrayDataProvider和SqlDataProvider提供者,getKeys得到的数组就简单的多了,数据项就是一个数组,因此得到的都是如下
[
0 => 0
1 => 1
2 => 2
3 => 3
4 => 4
5 => 5
]
当然你也可以通过setKeys函数对这些规则进行重写,后续篇章会讲到
getCount & getTotalCount
这是两个关于数量统计的函数,用意也及其明白,之所以诞生是因为DataProvider支持分页功能。
- getCount 当前页面的数据项数量
- getTotalCount 数据项总数量
getSort
得到排序的信息,这个方法实现及其简单,看一下。
public function getSort()
{
if ($this->_sort === null) {
$this->setSort([]);
}
return $this->_sort;
}
从代码看还是返回了_sort属性,那么问题就回到setSort方法身上,研究明白如何对_sort赋值就能知道getSort得到的是什么了~
我们先把代码贴过来
public function setSort($value){
if (is_array($value)) {
$config = ['class' => Sort::className()];
if ($this->id !== null) {
$config['sortParam'] = $this->id . '-sort';
}
$this->_sort = Yii::createObject(array_merge($config, $value));
} elseif ($value instanceof Sort || $value === false) {
$this->_sort = $value;
} else {
throw new InvalidParamException('Only Sort instance, configuration array or false is allowed.');
}
}
对于$value的传递一共有三种可能
- Array 一个配置数组
- Sort 一个sort对象
- Bool 一个布尔型的值
这些我们可以通过新建DataProvider对象时候传入,比如
$dataProvider = new ActiveDataProvider([
'query' => Blog::find()->select(['title','id']),
'sort'=>false
]);
重点 当sort为false时候代表不排序,sort不能为true(会报错),当我们要排序的时候应该出入配置数组和sort对象。
setSort方法会根据参数的类型来进行不同的逻辑处理,比如传递数组类型的会生成一个一个Sort对象并将你的设置作为新建对象的参数,当然你也可以直接传入一个Sort对象,效果是一样的。
getPagination
这是一个重要的函数,它负责分页。
public function getPagination()
{
if ($this->_pagination === null) {
$this->setPagination([]);
}
return $this->_pagination;
}
但是不要担心,这个方法和getSort方法的思路完全一致,当我们发现对象的_pagination不存在时,调用setPagination对其进行设置,接下来的代码你会非常熟悉。
public function setPagination($value)
{
if (is_array($value)) {
$config = ['class' => Pagination::className()];
if ($this->id !== null) {
$config['pageParam'] = $this->id . '-page';
$config['pageSizeParam'] = $this->id . '-per-page';
}
$this->_pagination = Yii::createObject(array_merge($config, $value));
} elseif ($value instanceof Pagination || $value === false) {
$this->_pagination = $value;
} else {
throw new InvalidParamException('Only Pagination instance, configuration array or false is allowed.');
}
}
是吧,你是不是发现和setSort完全一致,接收的函数也一样。
小结
现在你知道DataProvider的运行原理以及常用方法了么?接下来我将为你介绍在GridView中是如何对DataProvider对象进行处理的。
本文来自于 https://nai8.me