Completed
Push — master ( 89387e...132c3f )
by Lars
03:04
created

Result::fetchObject()   B

Complexity

Conditions 8
Paths 12

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 8

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 16
ccs 9
cts 9
cp 1
rs 7.7777
cc 8
eloc 8
nc 12
nop 3
crap 8
1
<?php
2
3
namespace voku\db;
4
5
use Arrayy\Arrayy;
6
use voku\helper\Bootup;
7
use voku\helper\UTF8;
8
9
/**
10
 * Result: this handles the result from "DB"-Class
11
 *
12
 * @package   voku\db
13
 */
14
final class Result
15
{
16
17
  /**
18
   * @var int
19
   */
20
  public $num_rows;
21
22
  /**
23
   * @var string
24
   */
25
  public $sql;
26
27
  /**
28
   * @var \mysqli_result
29
   */
30
  private $_result;
31
32
  /**
33
   * @var string
34
   */
35
  private $_default_result_type = 'object';
36
37
  /**
38
   * Result constructor.
39
   *
40
   * @param string         $sql
41
   * @param \mysqli_result $result
42
   */
43 28
  public function __construct($sql = '', \mysqli_result $result)
44
  {
45 28
    $this->sql = $sql;
46
47 28
    $this->_result = $result;
48 28
    $this->num_rows = $this->_result->num_rows;
49 28
  }
50
51
  /**
52
   * @return string
53
   */
54 1
  public function getDefaultResultType()
55
  {
56 1
    return $this->_default_result_type;
57
  }
58
59
  /**
60
   * You can set the default result-type to 'object', 'array' or 'Arrayy'.
61
   *
62
   * INFO: used for "fetch()" and "fetchAll()"
63
   *
64
   * @param string $default_result_type
65
   */
66 2
  public function setDefaultResultType($default_result_type = 'object')
67
  {
68
    if (
69
        $default_result_type === 'object'
70 2
        ||
71
        $default_result_type === 'array'
72 2
        ||
73
        $default_result_type === 'Arrayy'
74 2
    ) {
75 2
      $this->_default_result_type = $default_result_type;
76 2
    }
77 2
  }
78
79
  /**
80
   * Fetch data as a key/value pair array.
81
   *
82
   * <p>
83
   *   <br />
84
   *   INFO: both "key" and "value" must exists in the fetched data
85
   *   the key will be the new key of the result-array
86
   *   <br /><br />
87
   * </p>
88
   *
89
   * e.g.:
90
   * <code>
91
   *    fetchArrayPair('some_id', 'some_value');
92
   *    // array(127 => 'some value', 128 => 'some other value')
93
   * </code>
94
   *
95
   * @param string $key
96
   * @param string $value
97
   *
98
   * @return array
99
   */
100 1
  public function fetchArrayPair($key, $value)
101
  {
102 1
    $arrayPair = array();
103 1
    $data = $this->fetchAllArray();
104
105 1
    foreach ($data as $_row) {
106 1
      if (isset($_row[$key], $_row[$value])) {
107 1
        $_key = $_row[$key];
108 1
        $_value = $_row[$value];
109 1
        $arrayPair[$_key] = $_value;
110 1
      }
111 1
    }
112
113 1
    return $arrayPair;
114
  }
115
116
  /**
117
   * Cast data into int, float or string.
118
   *
119
   * <p>
120
   *   <br />
121
   *   INFO: install / use "mysqlnd"-driver for better performance
122
   * </p>
123
   *
124
   * @param array|object $data
125
   *
126
   * @return array|object|false false on error
127
   */
128 24
  private function cast(&$data)
129
  {
130 24
    if (Helper::isMysqlndIsUsed() === true) {
131 24
      return $data;
132
    }
133
134
    // init
135
    if (Bootup::is_php('5.4')) {
136
      static $FIELDS = array();
137
      static $TYPES = array();
138
    } else {
139
      $FIELDS = array();
140
      $TYPES = array();
141
    }
142
143
    $result_hash = spl_object_hash($this->_result);
144
145
    if (!isset($FIELDS[$result_hash])) {
146
      $FIELDS[$result_hash] = \mysqli_fetch_fields($this->_result);
147
    }
148
149
    if ($FIELDS[$result_hash] === false) {
150
      return false;
151
    }
152
153
    if (!isset($TYPES[$result_hash])) {
154
      foreach ($FIELDS[$result_hash] as $field) {
155
        switch ($field->type) {
156
          case 3:
157
            $TYPES[$result_hash][$field->name] = 'int';
158
            break;
159
          case 4:
160
            $TYPES[$result_hash][$field->name] = 'float';
161
            break;
162
          default:
163
            $TYPES[$result_hash][$field->name] = 'string';
164
            break;
165
        }
166
      }
167
    }
168
169
    if (is_array($data) === true) {
170 View Code Duplication
      foreach ($TYPES[$result_hash] as $type_name => $type) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
        if (isset($data[$type_name])) {
172
          settype($data[$type_name], $type);
173
        }
174
      }
175
    } elseif (is_object($data)) {
176 View Code Duplication
      foreach ($TYPES[$result_hash] as $type_name => $type) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
        if (isset($data->{$type_name})) {
178
          settype($data->{$type_name}, $type);
179
        }
180
      }
181
    }
182
183
    return $data;
184
  }
185
186
  /**
187
   * Fetch all results as array.
188
   *
189
   * @return array
190
   */
191 10 View Code Duplication
  public function fetchAllArray()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
192
  {
193
    // init
194 10
    $data = array();
195
196
    if (
197 10
        $this->_result
198 10
        &&
199 10
        !$this->is_empty()
200 10
    ) {
201 10
      $this->reset();
202
203
      /** @noinspection PhpAssignmentInConditionInspection */
204 10
      while ($row = \mysqli_fetch_assoc($this->_result)) {
205 10
        $data[] = $this->cast($row);
206 10
      }
207 10
    }
208
209 10
    return $data;
210
  }
211
212
  /**
213
   * Fetch all results as "Arrayy"-object.
214
   *
215
   * @return Arrayy
216
   */
217 1 View Code Duplication
  public function fetchAllArrayy()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
218
  {
219
    // init
220 1
    $data = array();
221
222
    if (
223 1
        $this->_result
224 1
        &&
225 1
        !$this->is_empty()
226 1
    ) {
227 1
      $this->reset();
228
229
      /** @noinspection PhpAssignmentInConditionInspection */
230 1
      while ($row = \mysqli_fetch_assoc($this->_result)) {
231 1
        $data[] = $this->cast($row);
232 1
      }
233 1
    }
234
235 1
    return Arrayy::create($data);
236
  }
237
238
  /**
239
   * Check if the result is empty.
240
   *
241
   * @return bool
242
   */
243 12
  public function is_empty()
244
  {
245 12
    if ($this->num_rows > 0) {
246 12
      return false;
247
    } else {
248 1
      return true;
249
    }
250
  }
251
252
  /**
253
   * Reset the offset (data_seek) for the results.
254
   *
255
   * @return Result
256
   */
257 11
  public function reset()
258
  {
259 11
    if (!$this->is_empty()) {
260 11
      \mysqli_data_seek($this->_result, 0);
261 11
    }
262
263 11
    return $this;
264
  }
265
266
  /**
267
   * Fetch all results as "json"-string.
268
   *
269
   * @return string
270
   */
271 1
  public function json()
272
  {
273 1
    $data = $this->fetchAllArray();
274
275 1
    return UTF8::json_encode($data);
276
  }
277
278
  /**
279
   * __destruct
280
   *
281
   */
282 28
  public function __destruct()
283
  {
284 28
    $this->free();
285 28
  }
286
287
  /**
288
   * free the memory
289
   */
290 28
  public function free()
291
  {
292 28
    \mysqli_free_result($this->_result);
293 28
  }
294
295
  /**
296
   * alias for "Result->fetch()"
297
   *
298
   * @see Result::fetch()
299
   *
300
   * @return array|object|false false on error
301
   */
302 1
  public function get()
303
  {
304 1
    return $this->fetch();
305
  }
306
307
  /**
308
   * Fetch.
309
   *
310
   * <p>
311
   *   <br />
312
   *   INFO: this will return an object by default, not an array<br />
313
   *   and you can change the behaviour via "Result->setDefaultResultType()"
314
   * </p>
315
   *
316
   * @param $reset
317
   *
318
   * @return array|object|false false on error
319
   */
320 2
  public function fetch($reset = false)
321
  {
322 2
    $return = false;
323
324 2
    if ($this->_default_result_type === 'object') {
325 2
      $return = $this->fetchObject('', '', $reset);
326 2
    } elseif ($this->_default_result_type === 'array') {
327 2
      $return = $this->fetchArray($reset);
328 2
    } elseif ($this->_default_result_type === 'Arrayy') {
329
      $return = $this->fetchArrayy($reset);
330
    }
331
332 2
    return $return;
333
  }
334
335
  /**
336
   * Fetch as object.
337
   *
338
   * @param string     $class
339
   * @param null|array $params
340
   * @param bool       $reset
341
   *
342
   * @return object|false false on error
343
   */
344 7
  public function fetchObject($class = '', $params = null, $reset = false)
345
  {
346 7
    if ($reset === true) {
347 1
      $this->reset();
348 1
    }
349
350 7
    if ($class && $params) {
351 1
      return ($row = \mysqli_fetch_object($this->_result, $class, $params)) ? $row : false;
352
    }
353
354 7
    if ($class) {
355 1
      return ($row = \mysqli_fetch_object($this->_result, $class)) ? $row : false;
356
    }
357
358 7
    return ($row = \mysqli_fetch_object($this->_result)) ? $this->cast($row) : false;
359
  }
360
361
  /**
362
   * Fetch as array.
363
   *
364
   * @param bool $reset
365
   *
366
   * @return array|false false on error
367
   */
368 11 View Code Duplication
  public function fetchArray($reset = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
369
  {
370 11
    if ($reset === true) {
371 1
      $this->reset();
372 1
    }
373
374 11
    $row = \mysqli_fetch_assoc($this->_result);
375 11
    if ($row) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $row of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
376 11
      return $this->cast($row);
377
    }
378
379
    return false;
380
  }
381
382
  /**
383
   * Fetch as "Arrayy"-object.
384
   *
385
   * @param bool $reset
386
   *
387
   * @return Arrayy|false false on error
388
   */
389 1 View Code Duplication
  public function fetchArrayy($reset = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
390
  {
391 1
    if ($reset === true) {
392
      $this->reset();
393
    }
394
395 1
    $row = \mysqli_fetch_assoc($this->_result);
396 1
    if ($row) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $row of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
397 1
      return Arrayy::create($this->cast($row));
0 ignored issues
show
Bug introduced by
It seems like $this->cast($row) targeting voku\db\Result::cast() can also be of type false or object; however, Arrayy\Arrayy::create() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
398
    }
399
400
    return false;
401
  }
402
403
  /**
404
   * alias for "Result->fetchAll()"
405
   *
406
   * @see Result::fetchAll()
407
   *
408
   * @return array
409
   */
410 1
  public function getAll()
411
  {
412 1
    return $this->fetchAll();
413
  }
414
415
  /**
416
   * Fetch all results.
417
   *
418
   * <p>
419
   *   <br />
420
   *   INFO: this will return an object by default, not an array<br />
421
   *   and you can change the behaviour via "Result->setDefaultResultType()"
422
   * </p>
423
   *
424
   * @return array
425
   */
426 2
  public function fetchAll()
427
  {
428 2
    $return = array();
429
430 2
    if ($this->_default_result_type === 'object') {
431 2
      $return = $this->fetchAllObject();
432 2
    } elseif ($this->_default_result_type === 'array') {
433 1
      $return = $this->fetchAllArray();
434 1
    } elseif ($this->_default_result_type === 'Arrayy') {
435
      $return = $this->fetchAllArray();
436
    }
437
438 2
    return $return;
439
  }
440
441
  /**
442
   * Fetch all results as array with objects.
443
   *
444
   * @param string     $class
445
   * @param null|array $params
446
   *
447
   * @return array
448
   */
449 3
  public function fetchAllObject($class = '', $params = null)
450
  {
451
    // init
452 3
    $data = array();
453
454 3
    if (!$this->is_empty()) {
455 3
      $this->reset();
456
457 3
      if ($class && $params) {
458
        /** @noinspection PhpAssignmentInConditionInspection */
459 1
        while ($row = \mysqli_fetch_object($this->_result, $class, $params)) {
460 1
          $data[] = $row;
461 1
        }
462 3
      } elseif ($class) {
463
        /** @noinspection PhpAssignmentInConditionInspection */
464 1
        while ($row = \mysqli_fetch_object($this->_result, $class)) {
465 1
          $data[] = $row;
466 1
        }
467 1
      } else {
468
        /** @noinspection PhpAssignmentInConditionInspection */
469 3
        while ($row = \mysqli_fetch_object($this->_result)) {
470 3
          $data[] = $this->cast($row);
471 3
        }
472
      }
473 3
    }
474
475 3
    return $data;
476
  }
477
478
  /**
479
   * alias for "Result->fetchAllObject()"
480
   *
481
   * @see Result::fetchAllObject()
482
   *
483
   * @return array of mysql-objects
484
   */
485 1
  public function getObject()
486
  {
487 1
    return $this->fetchAllObject();
488
  }
489
490
  /**
491
   * alias for "Result->fetchAllArrayy()"
492
   *
493
   * @see Result::fetchAllArrayy()
494
   *
495
   * @return Arrayy
496
   */
497
  public function getArrayy()
498
  {
499
    return $this->fetchAllArrayy();
500
  }
501
502
  /**
503
   * alias for "Result->fetchAllArray()"
504
   *
505
   * @see Result::fetchAllArray()
506
   *
507
   * @return array
508
   */
509 1
  public function getArray()
510
  {
511 1
    return $this->fetchAllArray();
512
  }
513
514
  /**
515
   * alias for "Result->fetchColumn()"
516
   *
517
   * @see Result::fetchColumn()
518
   *
519
   * @param $key
520
   *
521
   * @return string
522
   */
523 1
  public function getColumn($key)
524
  {
525 1
    return $this->fetchColumn($key);
526
  }
527
528
  /**
529
   * Fetch a single column in an 1-dimension array.
530
   *
531
   * @param string $column
532
   *
533
   * @return string empty string if the $column wasn't found
534
   */
535 2
  public function fetchColumn($column = '')
536
  {
537 2
    $columnData = '';
538 2
    $data = $this->fetchAllArray();
539
540 2
    foreach ($data as $_row) {
541 2
      if (isset($_row[$column])) {
542 2
        $columnData = $_row[$column];
543 2
      }
544 2
    }
545
546 2
    return $columnData;
547
  }
548
549
  /**
550
   * Get the current "num_rows" as string.
551
   *
552
   * @return string
553
   */
554
  public function __toString()
555
  {
556
    return (string)$this->num_rows;
557
  }
558
}
559