Passed
Push — fix-array-access ( 050ccc...ecf3a7 )
by Alexander
56:12 queued 49:24
created

ActiveDataProvider::init()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
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|null the query that is used to fetch data models and [[totalCount]] if it is not explicitly set.
60
     */
61
    public $query;
62
    /**
63
     * @var string|callable|null the column that is used as the key of the data models.
64
     * This can be either a column name, or a callable that returns the key value of a given data model.
65
     *
66
     * If this is not set, the following rules will be used to determine the keys of the data models:
67
     *
68
     * - If [[query]] is an [[\yii\db\ActiveQuery]] instance, the primary keys of [[\yii\db\ActiveQuery::modelClass]] will be used.
69
     * - Otherwise, the keys of the [[models]] array will be used.
70
     *
71
     * @see getKeys()
72
     */
73
    public $key;
74
    /**
75
     * @var Connection|array|string|null the DB connection object or the application component ID of the DB connection.
76
     * If set it overrides [[query]] default DB connection.
77
     * Starting from version 2.0.2, this can also be a configuration array for creating the object.
78
     */
79
    public $db;
80
81
82
    /**
83
     * Initializes the DB connection component.
84
     * This method will initialize the [[db]] property (when set) to make sure it refers to a valid DB connection.
85
     * @throws InvalidConfigException if [[db]] is invalid.
86
     */
87 28
    public function init()
88
    {
89 28
        parent::init();
90 28
        if ($this->db !== null) {
91 12
            $this->db = Instance::ensure($this->db, Connection::className());
0 ignored issues
show
Deprecated Code introduced by
The function yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

91
            $this->db = Instance::ensure($this->db, /** @scrutinizer ignore-deprecated */ Connection::className());

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
92
        }
93 28
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 24
    protected function prepareModels()
99
    {
100 24
        if (!$this->query instanceof QueryInterface) {
101
            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.');
102
        }
103 24
        $query = clone $this->query;
104 24
        if (($pagination = $this->getPagination()) !== false) {
105 24
            $pagination->totalCount = $this->getTotalCount();
106 24
            if ($pagination->totalCount === 0) {
107 3
                return [];
108
            }
109 21
            $query->limit($pagination->getLimit())->offset($pagination->getOffset());
110
        }
111 21
        if (($sort = $this->getSort()) !== false) {
112 21
            $query->addOrderBy($sort->getOrders());
113
        }
114
115 21
        return $query->all($this->db);
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121 26
    protected function prepareKeys($models)
122
    {
123 26
        $keys = [];
124 26
        if ($this->key !== null) {
125
            foreach ($models as $model) {
126
                if (is_string($this->key)) {
127
                    $keys[] = $model[$this->key];
128
                } else {
129
                    $keys[] = call_user_func($this->key, $model);
130
                }
131
            }
132
133
            return $keys;
134 26
        } elseif ($this->query instanceof ActiveQueryInterface) {
135
            /* @var $class \yii\db\ActiveRecordInterface */
136 14
            $class = $this->query->modelClass;
0 ignored issues
show
Bug introduced by
Accessing modelClass on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
137 14
            $pks = $class::primaryKey();
138 14
            if (count($pks) === 1) {
139 14
                $pk = $pks[0];
140 14
                foreach ($models as $model) {
141 14
                    $keys[] = $model[$pk];
142
                }
143
            } else {
144
                foreach ($models as $model) {
145
                    $kk = [];
146
                    foreach ($pks as $pk) {
147
                        $kk[$pk] = $model[$pk];
148
                    }
149
                    $keys[] = $kk;
150
                }
151
            }
152
153 14
            return $keys;
154
        }
155
156 12
        return array_keys($models);
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 24
    protected function prepareTotalCount()
163
    {
164 24
        if (!$this->query instanceof QueryInterface) {
165
            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.');
166
        }
167 24
        $query = clone $this->query;
168 24
        return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db);
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174 23
    public function setSort($value)
175
    {
176 23
        parent::setSort($value);
177 23
        if ($this->query instanceof ActiveQueryInterface && ($sort = $this->getSort()) !== false) {
178
            /* @var $modelClass Model */
179 14
            $modelClass = $this->query->modelClass;
180 14
            $model = $modelClass::instance();
181 14
            if (empty($sort->attributes)) {
182 13
                foreach ($model->attributes() as $attribute) {
183 13
                    $sort->attributes[$attribute] = [
184 13
                        'asc' => [$attribute => SORT_ASC],
185 13
                        'desc' => [$attribute => SORT_DESC],
186 13
                        'label' => $model->getAttributeLabel($attribute),
187
                    ];
188
                }
189
            } else {
190 1
                foreach ($sort->attributes as $attribute => $config) {
191 1
                    if (!isset($config['label'])) {
192 1
                        $sort->attributes[$attribute]['label'] = $model->getAttributeLabel($attribute);
193
                    }
194
                }
195
            }
196
        }
197 23
    }
198
199 1
    public function __clone()
200
    {
201 1
        if (is_object($this->query)) {
202 1
            $this->query = clone $this->query;
203
        }
204
205 1
        parent::__clone();
206 1
    }
207
}
208