Completed
Push — 2.1 ( 21da0e...a39d12 )
by
unknown
10:45
created

BatchQueryResult::next()   C

Complexity

Conditions 10
Paths 12

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 14
cts 14
cp 1
rs 6.6746
c 0
b 0
f 0
cc 10
eloc 15
nc 12
nop 0
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\db;
9
10
use yii\base\BaseObject;
11
12
/**
13
 * BatchQueryResult represents a batch query from which you can retrieve data in batches.
14
 *
15
 * You usually do not instantiate BatchQueryResult directly. Instead, you obtain it by
16
 * calling [[Query::batch()]] or [[Query::each()]]. Because BatchQueryResult implements the [[\Iterator]] interface,
17
 * you can iterate it to obtain a batch of data in each iteration. For example,
18
 *
19
 * ```php
20
 * $query = (new Query)->from('user');
21
 * foreach ($query->batch() as $i => $users) {
22
 *     // $users represents the rows in the $i-th batch
23
 * }
24
 * foreach ($query->each() as $user) {
25
 * }
26
 * ```
27
 *
28
 * @author Qiang Xue <[email protected]>
29
 * @since 2.0
30
 */
31
class BatchQueryResult extends BaseObject implements \Iterator
32
{
33
    /**
34
     * @var Connection the DB connection to be used when performing batch query.
35
     * If null, the "db" application component will be used.
36
     */
37
    public $db;
38
    /**
39
     * @var Query the query object associated with this batch query.
40
     * Do not modify this property directly unless after [[reset()]] is called explicitly.
41
     */
42
    public $query;
43
    /**
44
     * @var int the number of rows to be returned in each batch.
45
     */
46
    public $batchSize = 100;
47
    /**
48
     * @var bool whether to return a single row during each iteration.
49
     * If false, a whole batch of rows will be returned in each iteration.
50
     */
51
    public $each = false;
52
53
    /**
54
     * @var DataReader the data reader associated with this batch query.
55
     */
56
    private $_dataReader;
57
    /**
58
     * @var array the data retrieved in the current batch
59
     */
60
    private $_batch;
61
    /**
62
     * @var mixed the value for the current iteration
63
     */
64
    private $_value;
65
    /**
66
     * @var string|int the key for the current iteration
67
     */
68
    private $_key;
69
70
71
    /**
72
     * Destructor.
73
     */
74 6
    public function __destruct()
75
    {
76
        // make sure cursor is closed
77 6
        $this->reset();
78 6
    }
79
80
    /**
81
     * Resets the batch query.
82
     * This method will clean up the existing batch query so that a new batch query can be performed.
83
     */
84 6
    public function reset()
85
    {
86 6
        if ($this->_dataReader !== null) {
87 6
            $this->_dataReader->close();
88
        }
89 6
        $this->_dataReader = null;
90 6
        $this->_batch = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_batch.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
91 6
        $this->_value = null;
92 6
        $this->_key = null;
93 6
    }
94
95
    /**
96
     * Resets the iterator to the initial state.
97
     * This method is required by the interface [[\Iterator]].
98
     */
99 6
    public function rewind()
100
    {
101 6
        $this->reset();
102 6
        $this->next();
103 6
    }
104
105
    /**
106
     * Moves the internal pointer to the next dataset.
107
     * This method is required by the interface [[\Iterator]].
108
     */
109 6
    public function next()
110
    {
111 6
        if ($this->_batch === null || !$this->each || $this->each && next($this->_batch) === false) {
112 6
            $this->_batch = $this->fetchData();
113 6
            reset($this->_batch);
114
        }
115
116 6
        if ($this->each) {
117 3
            $this->_value = current($this->_batch);
118 3
            if ($this->query->indexBy !== null) {
119 3
                $this->_key = key($this->_batch);
120 3
            } elseif (key($this->_batch) !== null) {
121 3
                $this->_key = $this->_key === null ? 0 : $this->_key + 1;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->_key === null ? 0 : $this->_key + 1 can also be of type double. However, the property $_key is declared as type string|integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
122
            } else {
123 3
                $this->_key = null;
124
            }
125
        } else {
126 6
            $this->_value = $this->_batch;
127 6
            $this->_key = $this->_key === null ? 0 : $this->_key + 1;
128
        }
129 6
    }
130
131
    /**
132
     * Fetches the next batch of data.
133
     * @return array the data fetched
134
     */
135 6
    protected function fetchData()
136
    {
137 6
        if ($this->_dataReader === null) {
138 6
            $this->_dataReader = $this->query->createCommand($this->db)->query();
139
        }
140
141 6
        $rows = [];
142 6
        $count = 0;
143 6
        while ($count++ < $this->batchSize && ($row = $this->_dataReader->read())) {
144 6
            $rows[] = $row;
145
        }
146
147 6
        return $this->query->populate($rows);
148
    }
149
150
    /**
151
     * Returns the index of the current dataset.
152
     * This method is required by the interface [[\Iterator]].
153
     * @return int the index of the current row.
154
     */
155 3
    public function key()
156
    {
157 3
        return $this->_key;
158
    }
159
160
    /**
161
     * Returns the current dataset.
162
     * This method is required by the interface [[\Iterator]].
163
     * @return mixed the current dataset.
164
     */
165 6
    public function current()
166
    {
167 6
        return $this->_value;
168
    }
169
170
    /**
171
     * Returns whether there is a valid dataset at the current position.
172
     * This method is required by the interface [[\Iterator]].
173
     * @return bool whether there is a valid dataset at the current position.
174
     */
175 6
    public function valid()
176
    {
177 6
        return !empty($this->_batch);
178
    }
179
}
180