[Yii2笔记]062数据提供器(Data Providers) [ 技术分享 ]
说明
学习Yii Framework 2(易2框架)的过程是漫长的,也是充满乐趣的,以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现,提供了较完整的代码,供你参考。不妥之处,请多多指正!
原文网址:
http://www.yiiframework.com/doc-2.0/guide-output-data-providers.html
本文主题:数据提供器(Data Providers)
在分页和排序章节,我们已说明了怎样让用户去选择一个指定页的数据去显示,并按照指定列去排序。因为分页和排序使用非常广泛,Yii提供了一组数据提供器类来封装它。
数据提供器是实现了yii\data\DataProviderInterface接口的类,它主要用于获取分页和排序的数据,它常与数据小部件一起使用,这样用户可以就可以互动式的分页和排序数据了。
Yii发布的数据提供器类包括以下几个: yii\data\ActiveDataProvider:使用yii\db\Query或yii\db\ActiveQuery从数据库中查询查询数据,然后以数组或AR实例的形式返回它们。 yii\data\SqlDataProvider:执行一个SQL语句,以数组形式返回数据。 yii\data\ArrayDataProvider:获取一个大数组,根据分页和排序规则取出来一小部分并返回。
这些数据提供器的用法使用的是相同模式:
//配置分页和排序属性,并创建数据提供器
$provider=new XyzDataProvider([
'pagination'=>[...],
'sort'=>[...],
]);
//获取分页和排序的数据
$models=$provider->getModels();
//获取当前页的数据条数
$count=$provider->getCount();
//获取数据总条数
$totalCount=$provider->getTotalCount();
你通过配置分页和排序属性定义了分页和排序行为,也就是对应于yii\data\Pagination和yii\data\Sort的配置。如果不需要分页和排序功能,你也可以将它们设置为false。
数据小部件,如yii\grid\GridView,有一个名为dataProvider的属性,将获取一个数据提供器实例,并显示其中的数据,例如:
echo yii\grid\GridView::widget([
'dataProvider'=>$dataProvider,
]);
这些数据提供器的主要区别是定义的数据源不同,接下来,我们将详细介绍每种数据提供器的详细用法。
1、Active Data Provider(活动数据提供器)
要使用yii\data\ActiveDataProvider,你应配置它的query属性,它即可以是yii\db\Query对象,也可以是yii\db\ActiveQuery对象,前者返回的数据是数组,后者返回的数据可以是数据或Active Record实例,例如:
use yii\data\ActiveDataProvider;
$query=Post::find()->where(['status'=>1]);
$provider=new ActiveDataProvider([
'query' =>$query,
'pagination'=>[
'pageSize'=>10,
],
'sort'=>[
'defaultOrder'=>[
'created_at'=>SORT_DESC,
'title'=>SORT_ASC,
],
],
]);
$posts=$provider->getModels();//返回当前页的记录数据
如果上例中$query 由以下代码创建,则返回的数据将是数组:
use yii\db\Query;
$query=(new Query())->from('post')->where(['status'=>1]);
注意:如果查询语句已经定义了orderBy子句,由用户指定的新排序指令(指sort配置)将被追加到现存的orderBy子句,任何现存的在limit和offset子句将被用户端的分页请求所覆盖(指pagination配置)。
默认情况下,yii\data\ActiveDataProvider使用db应用组件作为数据库连接,你可以配置yii\data\ActiveDataProvider::$db 属性来使用另一个数据库连接。
实例,ActiveDataProvider
D:\phpwork\news\controllers\ArticlesController.php
public function actionActiveDataProvider() {
$data=TbArticles::valActiveDataProvider();
return $this->render('activeDataProvider',$data);
}
D:\phpwork\news\views\articles\activeDataProvider.php
<?php
use yii\grid\GridView;
?>
<?=GridView::widget([
//GridView使用的是DataProvider对象,而不是AR
'dataProvider'=>$dataProvider,
'columns'=>[
'title',
[
'attribute' => 'createdAt',
'format' => ['date','php:Y-n-j'],
'label' => '创建日期',
],
[
'attribute' => 'lastEdited',
'format' => ['date','php:Y-n-j'],
'label' => '最后更新',
],
],
])?>
D:\phpwork\news\models\TbArticles.php
public static function valActiveDataProvider() {
$provider=new ActiveDataProvider([
'query'=>static::find()->where(['isDeleted'=>0]),
'pagination'=>[
'pageSize'=>5,
],
'sort'=>[
'defaultOrder'=>[
'createdAt'=>SORT_DESC,
'title'=>SORT_ASC,
],
],
]);
return ['dataProvider'=>$provider];
}
测试结果:
http://localhost:8085/articles/active-data-provider
/*
Showing 1-5 of 23 items.
Title 创建日期 最后更新
中国首艘国产航母在大连正式下水 完成优雅转身 2017-4-27 2017-4-27
我国第二艘航空母舰下水 范长龙出席下水仪式并致辞 2017-4-26 2017-4-26
国土部:年底前所有地方房源接入国家平台 2017-3-31 2017-4-13
心脏支架的内幕:耗材成医疗腐败重灾区 2017-3-31 2017-4-13
共享单车平台已设年龄门槛 小学生为何仍能开锁 2017-3-31 2017-4-14
« 1 2 3 4 5 »
*/
2、SQL Data Provider
yii\data\SqlDataProvider使用一个原生的SQL语句来获取所需的数据。基于设定好的sort和pagination,提供器将调整SQL语句中的ORDER BY和LIMIT子查询,从而按照期望的排序方式只查询出请求页的数据。
要使用yii\data\SqlDataProvider,你应定义sql和totalCount属性,例如:
use yii\data\SqlDataProvider;
$count = Yii::$app->db->createCommand('
SELECT COUNT(*) FROM post WHERE status=:status
', [':status' => 1])->queryScalar();
$provider = new SqlDataProvider([
'sql' => 'SELECT * FROM post WHERE status=:status',
'params' => [':status' => 1],
'totalCount' => $count,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => [
'title',
'view_count',
'created_at',
],
],
]);
//返回一个数据行的数组
$models = $provider->getModels();
信息:只有在对数据进行分页时,才需要totalCount属性。这是因为使用sql定义的SQL语句会被提供器修改,这样才会只发送当前请求的页面的数据。提供器仍然需要知道数据总数,以正确计算有效的页数。
实例,SqlDataProvider
D:\phpwork\news\controllers\ArticlesController.php
public function actionSqlDataProvider() {
$data=TbArticles::valSqlDataProvider();
return $this->render('sqlDataProvider',$data);
}
D:\phpwork\news\models\TbArticles.php
public static function valSqlDataProvider() {
$count=Yii::$app->db->createCommand('SELECT COUNT(*) FROM articles WHERE isDeleted=:isDeleted',['isDeleted'=>0])->queryScalar();
$provider=new SqlDataProvider([
'sql'=>"SELECT * FROM articles WHERE isDeleted=:isDeleted",
'params'=>[':isDeleted'=>0],
'totalCount'=>$count,
'sort'=>[
'defaultOrder'=>[
'createdAt'=>SORT_DESC,
'lastEdited'=>SORT_ASC,
],
'attributes' => [
'title',
'createdAt',
'lastEdited',
],
],
'pagination'=>[
'defaultPageSize'=>5,
],
]);
return ['dataProvider'=>$provider];
}
D:\phpwork\news\views\articles\sqlDataProvider.php
<?php
use yii\grid\GridView;
?>
SqlDataProvider<br />
<?=GridView::widget([
'dataProvider'=>$dataProvider,
'columns'=>[
'title',
[
'attribute' => 'createdAt',
'format' => ['date','php:Y-n-j'],
'label' => '创建日期',
],
[
'attribute' => 'lastEdited',
'format' => ['date','php:Y-n-j'],
'label' => '最后更新',
],
],
])?>
测试结果:
http://localhost:8085/articles/sql-data-provider
/*
SqlDataProvider
Showing 1-5 of 23 items.
Title 创建日期 最后更新
中国首艘国产航母在大连正式下水 完成优雅转身 2017-4-27 2017-4-27
我国第二艘航空母舰下水 范长龙出席下水仪式并致辞 2017-4-26 2017-4-26
国土部:年底前所有地方房源接入国家平台 2017-3-31 2017-4-13
心脏支架的内幕:耗材成医疗腐败重灾区 2017-3-31 2017-4-13
共享单车平台已设年龄门槛 小学生为何仍能开锁 2017-3-31 2017-4-14
« 1 2 3 4 5 »
*/
3、Array Data Provider(数组提供器)
yii\data\ArrayDataProvider适用于一个大数组。此提供器允许你返回按一列或多列排序排序后一页数组数据。要使用yii\data\ArrayDataProvider,你需要将大数据定义到allModels属性上。大数组中的元素可以是关联数组(如DAO的查询结果),也可以是对象(如Active Record),例如:
use yii\data\ArrayDataProvider;
$data=[
['id'=>1,'name'=>'name 1',...],
['id'=>2,'name'=>'name 2',...],
...
['id'=>100,'name'=>'name 100',...],
];
$provider=new ArrayDataProvider([
'allModels' =>$data,
'pagination'=>[
'pageSize'=>10,
],
'sort'=>[
'attributes'=>['id','name'],
],
]);
//获取当前请求页的记录
$rows=$provider->getModels();
注意:与Active Data Provider和SQL Data Provider不同的是,数组提供器效率不高,因为它需要先将所有数据加载到内存中。
实例,ArrayDataProvider
D:\phpwork\news\controllers\ArticlesController.php
public function actionArrayDataProvider() {
$data=TbArticles::valArrayDataProvider();
return $this->render('arrayDataProvider',$data);
}
D:\phpwork\news\models\TbArticles.php
public static function valArrayDataProvider() {
$data=Yii::$app->db->createCommand('SELECT * FROM articles WHERE isDeleted=:isDeleted',['isDeleted'=>0])->queryAll();
$provider=new ArrayDataProvider([
'allModels'=>$data,
'pagination'=>[
'pageSize'=>3,
],
'sort'=>[
'attributes'=>['createdAt','title'],
],
]);
return ['dataProvider'=>$provider];
}
D:\phpwork\news\views\articles\arrayDataProvider.php
<?php
use yii\grid\GridView;
?>
SqlDataProvider<br />
<?=GridView::widget([
'dataProvider'=>$dataProvider,
'columns'=>[
'title',
[
'attribute' => 'createdAt',
'format' => ['date','php:Y-n-j'],
'label' => '创建日期',
],
[
'attribute' => 'lastEdited',
'format' => ['date','php:Y-n-j'],
'label' => '最后更新',
],
],
])?>
测试结果:
http://localhost:8085/articles/array-data-provider
/*
SqlDataProvider
Showing 1-3 of 23 items.
Title 创建日期 最后更新
巴黎数千人再次示威 警方用催泪弹驱赶场面混乱 2017-3-29 2017-3-29
复星CEO宣布辞职 梁信军辞职全体员工信 2017-3-29 2017-3-29
国家气候中心预测今年汛期我国气候状况总体偏差 2017-3-29 2017-3-29
« 1 2 3 4 5 6 7 8 »
*/
4、Working with Data Keys(使用数据键名)
当使用由数据提供器返回的数据项时,你需要使用一个唯一键去标识每个数据,例如,如果数据项代表客户信息,你可能想要使用客户ID作为每个客户数据的唯一键。数据提供器将返回由yii\data\DataProviderInterface::getModles()获取的一个键名、数据对应列表,例如:
use yii\data\ArrayDataProvider;
$query=Post::find()->where(['status'=>1]);
$provider=new ActiveDataProvider([
'query' =>$query;
]);
//返回Post对象的数组
$posts=$provider->getModels();
//返回对应于$posts的主键值
$ids=$provider->getKeys();
在上例中,因为提供了yii\data\ActiveDataProvider和yii\db\ActiveQuery对象,它自动将主键值作为键名,你也可以显式定义怎样获取键名,主要方法是配置yii\data\ActiveDataProvider::$key 为一个列名或一个可计算键名的回调函数。例如:
//使用'slug'列作为键名
$provider=new ActiveDataProvider([
'query' => Post::find(),
'key'=>'slug',
]);
//使用md5(id)作为键名:
$provider=new ActiveDataProvider([
'query' =>Post::find(),
'key'=>function($model){
return md5($model->id);
}
]);
5、Creating Custom Data Provider
创建自定义的数据提供器类,你需要实现yii\data\DataProviderInterface接口。一个更简便的方法是继承自yii\data\BaseDataProvider,这样你可以更关注于核心数据提供器的逻辑。实际上,你主要需要实现以下方法: prepareModels():准备数据模型,这些数据是当前面中的有效数据,并将作为数组进行返回。 prepareKeys():接收当前有效数据模型的数组,并返回与它们关联的键名。 prepareTotalCount():返回数据提供器中数据模型的总数。
下面是一个数据提供器的例子,它将有效读取CSV数据:
use yii\data\BaseDataProvider;
class CsvDataProvider extends BaseDataProvider{
public $filename;
public $key;
protected $fileObject;
public function init(){
parent::init();
$this->fileObject=new SqlFileObject($this->filename);
}
protected function prepareModels(){
$models=[];
$pagination=$this->getPagination();
if($pagination===false){
while(!this->fileObject->eof()){
$models[]=$this->fileObject->fgetcsv();
$this-fileObject->next();
}
}else{
$pagination->totalCount=$this->getTotalCount();
$this->fileObject->seek($pagination->getOffset());
$limit=$pagination->getLimit();
for($count=0;$count<$limit;++$count){
$models[]=$this->fileObject->fgetcsv();
$this->fileObject->next();
}
}
return $models;
}
protected function prepareKeys($models){
if($this->key!==null){
$keys=[];
foreach($mdels as $model){
if(is_string($this->key)){
$keys[]=$model[$this->key];
}else{
$keys[]=call_user_func($this->key,$model);
}
}
return $keys;
}else{
return array_keys($models);
}
}
protected function prepareTotalCount(){
$count=0;
while(!$this->fileObject->eof()){
$this->fileObject->next();
++$count;
}
return $count;
}
}
(全文完)
共 0 条回复
阿江
最后登录:2024-03-03
在线时长:186小时21分
- 粉丝94
- 金钱16816
- 威望160
- 积分20276