1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.yiiframework.com/ |
4
|
|
|
* @copyright Copyright (c) 2008 Yii Software LLC |
5
|
|
|
* @license http://www.yiiframework.com/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace yii\data; |
9
|
|
|
|
10
|
|
|
use yii\base\InvalidConfigException; |
11
|
|
|
use yii\base\Model; |
12
|
|
|
use yii\db\ActiveQueryInterface; |
13
|
|
|
use yii\db\Connection; |
14
|
|
|
use yii\db\QueryInterface; |
15
|
|
|
use yii\di\Instance; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* ActiveDataProvider implements a data provider based on [[\yii\db\Query]] and [[\yii\db\ActiveQuery]]. |
19
|
|
|
* |
20
|
|
|
* ActiveDataProvider provides data by performing DB queries using [[query]]. |
21
|
|
|
* |
22
|
|
|
* The following is an example of using ActiveDataProvider to provide ActiveRecord instances: |
23
|
|
|
* |
24
|
|
|
* ```php |
25
|
|
|
* $provider = new ActiveDataProvider([ |
26
|
|
|
* 'query' => Post::find(), |
27
|
|
|
* 'pagination' => [ |
28
|
|
|
* 'pageSize' => 20, |
29
|
|
|
* ], |
30
|
|
|
* ]); |
31
|
|
|
* |
32
|
|
|
* // get the posts in the current page |
33
|
|
|
* $posts = $provider->getModels(); |
34
|
|
|
* ``` |
35
|
|
|
* |
36
|
|
|
* And the following example shows how to use ActiveDataProvider without ActiveRecord: |
37
|
|
|
* |
38
|
|
|
* ```php |
39
|
|
|
* $query = new Query(); |
40
|
|
|
* $provider = new ActiveDataProvider([ |
41
|
|
|
* 'query' => $query->from('post'), |
42
|
|
|
* 'pagination' => [ |
43
|
|
|
* 'pageSize' => 20, |
44
|
|
|
* ], |
45
|
|
|
* ]); |
46
|
|
|
* |
47
|
|
|
* // get the posts in the current page |
48
|
|
|
* $posts = $provider->getModels(); |
49
|
|
|
* ``` |
50
|
|
|
* |
51
|
|
|
* For more details and usage information on ActiveDataProvider, see the [guide article on data providers](guide:output-data-providers). |
52
|
|
|
* |
53
|
|
|
* @author Qiang Xue <[email protected]> |
54
|
|
|
* @since 2.0 |
55
|
|
|
*/ |
56
|
|
|
class ActiveDataProvider extends BaseDataProvider |
57
|
|
|
{ |
58
|
|
|
/** |
59
|
|
|
* @var QueryInterface the query that is used to fetch data models and [[totalCount]] |
60
|
|
|
* if it is not explicitly set. |
61
|
|
|
*/ |
62
|
|
|
public $query; |
63
|
|
|
/** |
64
|
|
|
* @var string|callable the column that is used as the key of the data models. |
65
|
|
|
* This can be either a column name, or a callable that returns the key value of a given data model. |
66
|
|
|
* |
67
|
|
|
* If this is not set, the following rules will be used to determine the keys of the data models: |
68
|
|
|
* |
69
|
|
|
* - If [[query]] is an [[\yii\db\ActiveQuery]] instance, the primary keys of [[\yii\db\ActiveQuery::modelClass]] will be used. |
70
|
|
|
* - Otherwise, the keys of the [[models]] array will be used. |
71
|
|
|
* |
72
|
|
|
* @see getKeys() |
73
|
|
|
*/ |
74
|
|
|
public $key; |
75
|
|
|
/** |
76
|
|
|
* @var Connection|array|string the DB connection object or the application component ID of the DB connection. |
77
|
|
|
* If not set, the default DB connection will be used. |
78
|
|
|
* Starting from version 2.0.2, this can also be a configuration array for creating the object. |
79
|
|
|
*/ |
80
|
|
|
public $db; |
81
|
|
|
|
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Initializes the DB connection component. |
85
|
|
|
* This method will initialize the [[db]] property to make sure it refers to a valid DB connection. |
86
|
|
|
* @throws InvalidConfigException if [[db]] is invalid. |
87
|
|
|
*/ |
88
|
26 |
|
public function init() |
89
|
|
|
{ |
90
|
26 |
|
parent::init(); |
91
|
26 |
|
if (is_string($this->db)) { |
92
|
|
|
$this->db = Instance::ensure($this->db, Connection::className()); |
|
|
|
|
93
|
|
|
} |
94
|
26 |
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* {@inheritdoc} |
98
|
|
|
*/ |
99
|
24 |
|
protected function prepareModels() |
100
|
|
|
{ |
101
|
24 |
|
if (!$this->query instanceof QueryInterface) { |
102
|
|
|
throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); |
103
|
|
|
} |
104
|
24 |
|
$query = clone $this->query; |
105
|
24 |
|
if (($pagination = $this->getPagination()) !== false) { |
106
|
24 |
|
$pagination->totalCount = $this->getTotalCount(); |
107
|
24 |
|
if ($pagination->totalCount === 0) { |
108
|
3 |
|
return []; |
109
|
|
|
} |
110
|
21 |
|
$query->limit($pagination->getLimit())->offset($pagination->getOffset()); |
111
|
|
|
} |
112
|
21 |
|
if (($sort = $this->getSort()) !== false) { |
113
|
21 |
|
$query->addOrderBy($sort->getOrders()); |
114
|
|
|
} |
115
|
|
|
|
116
|
21 |
|
return $query->all($this->db); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* {@inheritdoc} |
121
|
|
|
*/ |
122
|
26 |
|
protected function prepareKeys($models) |
123
|
|
|
{ |
124
|
26 |
|
$keys = []; |
125
|
26 |
|
if ($this->key !== null) { |
126
|
|
|
foreach ($models as $model) { |
127
|
|
|
if (is_string($this->key)) { |
128
|
|
|
$keys[] = $model[$this->key]; |
129
|
|
|
} else { |
130
|
|
|
$keys[] = call_user_func($this->key, $model); |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
return $keys; |
135
|
26 |
|
} elseif ($this->query instanceof ActiveQueryInterface) { |
136
|
|
|
/* @var $class \yii\db\ActiveRecordInterface */ |
137
|
14 |
|
$class = $this->query->modelClass; |
|
|
|
|
138
|
14 |
|
$pks = $class::primaryKey(); |
139
|
14 |
|
if (count($pks) === 1) { |
140
|
14 |
|
$pk = $pks[0]; |
141
|
14 |
|
foreach ($models as $model) { |
142
|
14 |
|
$keys[] = $model[$pk]; |
143
|
|
|
} |
144
|
|
|
} else { |
145
|
|
|
foreach ($models as $model) { |
146
|
|
|
$kk = []; |
147
|
|
|
foreach ($pks as $pk) { |
148
|
|
|
$kk[$pk] = $model[$pk]; |
149
|
|
|
} |
150
|
|
|
$keys[] = $kk; |
151
|
|
|
} |
152
|
|
|
} |
153
|
|
|
|
154
|
14 |
|
return $keys; |
155
|
|
|
} |
156
|
|
|
|
157
|
12 |
|
return array_keys($models); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* {@inheritdoc} |
162
|
|
|
*/ |
163
|
24 |
|
protected function prepareTotalCount() |
164
|
|
|
{ |
165
|
24 |
|
if (!$this->query instanceof QueryInterface) { |
166
|
|
|
throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.'); |
167
|
|
|
} |
168
|
24 |
|
$query = clone $this->query; |
169
|
24 |
|
return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* {@inheritdoc} |
174
|
|
|
*/ |
175
|
23 |
|
public function setSort($value) |
176
|
|
|
{ |
177
|
23 |
|
parent::setSort($value); |
178
|
23 |
|
if (($sort = $this->getSort()) !== false && $this->query instanceof ActiveQueryInterface) { |
179
|
|
|
/* @var $modelClass Model */ |
180
|
14 |
|
$modelClass = $this->query->modelClass; |
|
|
|
|
181
|
14 |
|
$model = $modelClass::instance(); |
182
|
14 |
|
if (empty($sort->attributes)) { |
183
|
13 |
|
foreach ($model->attributes() as $attribute) { |
184
|
13 |
|
$sort->attributes[$attribute] = [ |
185
|
13 |
|
'asc' => [$attribute => SORT_ASC], |
186
|
13 |
|
'desc' => [$attribute => SORT_DESC], |
187
|
13 |
|
'label' => $model->getAttributeLabel($attribute), |
188
|
|
|
]; |
189
|
|
|
} |
190
|
|
|
} else { |
191
|
1 |
|
foreach ($sort->attributes as $attribute => $config) { |
192
|
1 |
|
if (!isset($config['label'])) { |
193
|
1 |
|
$sort->attributes[$attribute]['label'] = $model->getAttributeLabel($attribute); |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
} |
198
|
23 |
|
} |
199
|
|
|
|
200
|
|
|
public function __clone() |
201
|
|
|
{ |
202
|
|
|
if (is_object($this->query)) { |
203
|
|
|
$this->query = clone $this->query; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
parent::__clone(); |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.