Completed
Pull Request — master (#149)
by
unknown
02:23
created

ResultSet::fetchFromStore()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 7
nc 7
nop 1
1
<?php
2
3
namespace Foolz\SphinxQL\Drivers;
4
5
use Foolz\SphinxQL\Drivers\Pdo\ResultSetAdapter as PdoResultSetAdapter;
6
use Foolz\SphinxQL\Exception\ResultSetException;
7
8
class ResultSet implements ResultSetInterface
9
{
10
    /**
11
     * @var int
12
     */
13
    protected $num_rows = 0;
14
15
    /**
16
     * @var int
17
     */
18
    protected $cursor = 0;
19
20
    /**
21
     * @var int
22
     */
23
    protected $next_cursor = 0;
24
25
    /**
26
     * @var int
27
     */
28
    protected $affected_rows = 0; // leave to 0 so SELECT etc. will be coherent
29
30
    /**
31
     * @var array
32
     */
33
    protected $fields;
34
35
    /**
36
     * @var null|array
37
     */
38
    protected $stored;
39
40
    /**
41
     * @var null|array
42
     */
43
    protected $fetched;
44
45
    /**
46
     * @var ResultSetAdapterInterface
47
     */
48
    protected $adapter;
49
50
    /**
51
     * @param ResultSetAdapterInterface $adapter
52
     */
53
    public function __construct(ResultSetAdapterInterface $adapter)
54
    {
55
        $this->adapter = $adapter;
56
        $this->init();
57
58
        if ($adapter instanceof PdoResultSetAdapter) { //only for pdo for some reason
59
            $this->store();
60
        }
61
    }
62
63
    /**
64
     * @inheritdoc
65
     */
66
    public function hasRow($num)
67
    {
68
        return $num >= 0 && $num < $this->num_rows;
69
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74
    public function hasNextRow()
75
    {
76
        return $this->cursor + 1 < $this->num_rows;
77
    }
78
79
    /**
80
     * @inheritdoc
81
     */
82
    public function getAffectedRows()
83
    {
84
        return $this->affected_rows;
85
    }
86
87
    /**
88
     * @inheritdoc
89
     */
90
    public function offsetExists($offset)
91
    {
92
        return $this->hasRow($offset);
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98
    public function offsetGet($offset)
99
    {
100
        return $this->toRow($offset)->fetchAssoc();
101
    }
102
103
    /**
104
     * @inheritdoc
105
     * @codeCoverageIgnore
106
     */
107
    public function offsetSet($offset, $value)
108
    {
109
        throw new \BadMethodCallException('Not implemented');
110
    }
111
112
    /**
113
     * @inheritdoc
114
     * @codeCoverageIgnore
115
     */
116
    public function offsetUnset($offset)
117
    {
118
        throw new \BadMethodCallException('Not implemented');
119
    }
120
121
    /**
122
     * @inheritdoc
123
     */
124
    public function current()
125
    {
126
        $row = $this->fetched;
127
        unset($this->fetched);
128
129
        return $row;
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135
    public function next()
136
    {
137
        $this->fetched = $this->fetch(true);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->fetch(true) can also be of type boolean. However, the property $fetched is declared as type null|array. 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...
138
    }
139
140
    /**
141
     * @inheritdoc
142
     */
143
    public function key()
144
    {
145
        return (int)$this->cursor;
146
    }
147
148
    /**
149
     * @inheritdoc
150
     */
151
    public function valid()
152
    {
153
        if ($this->stored !== null) {
154
            return $this->hasRow($this->cursor);
155
        }
156
157
        return $this->adapter->valid();
158
    }
159
160
    /**
161
     * @inheritdoc
162
     */
163
    public function rewind()
164
    {
165
        if ($this->stored === null) {
166
            $this->adapter->rewind();
167
        }
168
169
        $this->next_cursor = 0;
170
171
        $this->fetched = $this->fetch(true);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->fetch(true) can also be of type boolean. However, the property $fetched is declared as type null|array. 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...
172
    }
173
174
    /**
175
     * Returns the number of rows in the result set
176
     * @inheritdoc
177
     */
178
    public function count()
179
    {
180
        return $this->num_rows;
181
    }
182
183
    protected function init()
184
    {
185
        if ($this->adapter->isDml()) {
186
            $this->affected_rows = $this->adapter->getAffectedRows();
187
        } else {
188
            $this->num_rows = $this->adapter->getNumRows();
189
            $this->fields = $this->adapter->getFields();
190
        }
191
    }
192
193
    /**
194
     * @param array $numeric_array
195
     *
196
     * @return array
197
     */
198
    protected function makeAssoc($numeric_array)
199
    {
200
        $assoc_array = array();
201
        foreach ($numeric_array as $col_key => $col_value) {
202
            $assoc_array[$this->fields[$col_key]->name] = $col_value;
203
        }
204
205
        return $assoc_array;
206
    }
207
208
    /**
209
     * @param bool $assoc
210
     *
211
     * @return array|bool|null
212
     */
213
    protected function fetchFromStore($assoc = true)
214
    {
215
        if ($this->stored === null) {
216
            return false;
217
        }
218
219
        $row = isset($this->stored[$this->cursor]) ? $this->stored[$this->cursor] : null;
220
221
        if ($row !== null) {
222
            $row = $assoc ? $this->makeAssoc($row) : $row;
223
        }
224
225
        return $row;
226
    }
227
228
    /**
229
     * @param bool $assoc
230
     *
231
     * @return array|bool
232
     */
233
    protected function fetchAllFromStore($assoc)
234
    {
235
        if ($this->stored === null) {
236
            return false;
237
        }
238
239
        $result_from_store = array();
240
241
        $this->cursor = $this->next_cursor;
242
        while ($row = $this->fetchFromStore($assoc)) {
243
            $result_from_store[] = $row;
244
            $this->cursor = ++$this->next_cursor;
245
        }
246
247
        return $result_from_store;
248
    }
249
250
    /**
251
     * @param bool $assoc
252
     *
253
     * @return array
254
     */
255
    protected function fetchAll($assoc = true)
256
    {
257
        $fetch_all_result = $this->fetchAllFromStore($assoc);
258
259
        if ($fetch_all_result === false) {
260
            $fetch_all_result = $this->adapter->fetchAll($assoc);
261
        }
262
263
        $this->cursor = $this->num_rows;
264
        $this->next_cursor = $this->cursor + 1;
265
266
        return $fetch_all_result;
267
    }
268
269
    /**
270
     * @inheritdoc
271
     */
272
    public function store()
273
    {
274
        if ($this->stored !== null) {
275
            return $this;
276
        }
277
278
        if ($this->adapter->isDml()) {
279
            $this->stored = $this->affected_rows;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->affected_rows of type integer is incompatible with the declared type null|array of property $stored.

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...
280
        } else {
281
            $this->stored = $this->adapter->store();
282
        }
283
284
        return $this;
285
    }
286
287
    /**
288
     * @inheritdoc
289
     */
290
    public function getStored()
291
    {
292
        $this->store();
293
        if ($this->adapter->isDml()) {
294
            return $this->getAffectedRows();
295
        }
296
297
        return $this->fetchAllAssoc();
298
    }
299
300
    /**
301
     * @inheritdoc
302
     */
303
    public function toRow($num)
304
    {
305
        if (!$this->hasRow($num)) {
306
            throw new ResultSetException('The row does not exist.');
307
        }
308
309
        $this->cursor = $num;
310
        $this->next_cursor = $num;
311
312
        if ($this->stored === null) {
313
            $this->adapter->toRow($this->cursor);
314
        }
315
316
        return $this;
317
    }
318
319
    /**
320
     * @inheritdoc
321
     */
322
    public function toNextRow()
323
    {
324
        $this->toRow(++$this->cursor);
325
326
        return $this;
327
    }
328
329
    /**
330
     * @inheritdoc
331
     */
332
    public function fetchAllAssoc()
333
    {
334
        return $this->fetchAll(true);
335
    }
336
337
    /**
338
     * @inheritdoc
339
     */
340
    public function fetchAllNum()
341
    {
342
        return $this->fetchAll(false);
343
    }
344
345
    /**
346
     * @inheritdoc
347
     */
348
    public function fetchAssoc()
349
    {
350
        return $this->fetch(true);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->fetch(true); of type array|null|boolean adds the type boolean to the return on line 350 which is incompatible with the return type declared by the interface Foolz\SphinxQL\Drivers\R...etInterface::fetchAssoc of type array|null.
Loading history...
351
    }
352
353
    /**
354
     * @inheritdoc
355
     */
356
    public function fetchNum()
357
    {
358
        return $this->fetch(false);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->fetch(false); of type array|null|boolean adds the type boolean to the return on line 358 which is incompatible with the return type declared by the interface Foolz\SphinxQL\Drivers\R...tSetInterface::fetchNum of type array|null.
Loading history...
359
    }
360
361
    /**
362
     * @param bool $assoc
363
     *
364
     * @return array|null
365
     */
366
    protected function fetch($assoc = true)
367
    {
368
        $this->cursor = $this->next_cursor;
369
370
        $row = $this->fetchFromStore($assoc);
371
372
        if ($row === false) {
373
            $row = $this->adapter->fetch($assoc);
374
        }
375
376
        $this->next_cursor++;
377
378
        return $row;
379
    }
380
381
    /**
382
     * @inheritdoc
383
     */
384
    public function freeResult()
385
    {
386
        $this->adapter->freeResult();
387
388
        return $this;
389
    }
390
}
391