阿江 2017-10-15 07:30:15 2990次浏览 0条回复 2 0 0

说明

学习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;
	}
}

(全文完)

    没有找到数据。
您需要登录后才可以回复。登录 | 立即注册