Completed
Push — master ( 3260db...1c6413 )
by Lars
09:14 queued 43s
created

Result::fetchColumn()   C

Complexity

Conditions 10
Paths 10

Size

Total Lines 48
Code Lines 25

Duplication

Lines 29
Ratio 60.42 %

Code Coverage

Tests 27
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 29
loc 48
ccs 27
cts 27
cp 1
rs 5.3454
c 1
b 0
f 0
cc 10
eloc 25
nc 10
nop 3
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
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 30
  public function __construct($sql = '', \mysqli_result $result)
44
  {
45 30
    $this->sql = $sql;
46
47 30
    $this->_result = $result;
48 30
    $this->num_rows = (int)$this->_result->num_rows;
49 30
  }
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
      if (
107 1
          array_key_exists($key, $_row) === true
108 1
          &&
109 1
          array_key_exists($value, $_row) === true
110 1
      ) {
111 1
        $_key = $_row[$key];
112 1
        $_value = $_row[$value];
113 1
        $arrayPair[$_key] = $_value;
114 1
      }
115 1
    }
116
117 1
    return $arrayPair;
118
  }
119
120
  /**
121
   * Cast data into int, float or string.
122
   *
123
   * <p>
124
   *   <br />
125
   *   INFO: install / use "mysqlnd"-driver for better performance
126
   * </p>
127
   *
128
   * @param array|object $data
129
   *
130
   * @return array|object|false <p><strong>false</strong> on error</p>
131
   */
132 26
  private function cast(&$data)
133
  {
134 26
    if (Helper::isMysqlndIsUsed() === true) {
135 26
      return $data;
136
    }
137
138
    // init
139
    if (Bootup::is_php('5.4')) {
140
      static $FIELDS_CACHE = array();
141
      static $TYPES_CACHE = array();
142
    } else {
143
      $FIELDS_CACHE = array();
144
      $TYPES_CACHE = array();
145
    }
146
147
    $result_hash = spl_object_hash($this->_result);
148
149
    if (!isset($FIELDS_CACHE[$result_hash])) {
150
      $FIELDS_CACHE[$result_hash] = \mysqli_fetch_fields($this->_result);
151
    }
152
153
    if ($FIELDS_CACHE[$result_hash] === false) {
154
      return false;
155
    }
156
157
    if (!isset($TYPES_CACHE[$result_hash])) {
158
      foreach ($FIELDS_CACHE[$result_hash] as $field) {
159
        switch ($field->type) {
160
          case 3:
161
            $TYPES_CACHE[$result_hash][$field->name] = 'int';
162
            break;
163
          case 4:
164
            $TYPES_CACHE[$result_hash][$field->name] = 'float';
165
            break;
166
          default:
167
            $TYPES_CACHE[$result_hash][$field->name] = 'string';
168
            break;
169
        }
170
      }
171
    }
172
173
    if (is_array($data) === true) {
174 View Code Duplication
      foreach ($TYPES_CACHE[$result_hash] as $type_name => $type) {
175
        if (isset($data[$type_name])) {
176
          settype($data[$type_name], $type);
177
        }
178
      }
179
    } elseif (is_object($data)) {
180 View Code Duplication
      foreach ($TYPES_CACHE[$result_hash] as $type_name => $type) {
181
        if (isset($data->{$type_name})) {
182
          settype($data->{$type_name}, $type);
183
        }
184
      }
185
    }
186
187
    return $data;
188
  }
189
190
  /**
191
   * Fetch all results as array.
192
   *
193
   * @return array
194
   */
195 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...
196
  {
197
    // init
198 10
    $data = array();
199
200
    if (
201 10
        $this->_result
202 10
        &&
203 10
        !$this->is_empty()
204 10
    ) {
205 10
      $this->reset();
206
207
      /** @noinspection PhpAssignmentInConditionInspection */
208 10
      while ($row = \mysqli_fetch_assoc($this->_result)) {
209 10
        $data[] = $this->cast($row);
210 10
      }
211 10
    }
212
213 10
    return $data;
214
  }
215
216
  /**
217
   * Fetch all results as "Arrayy"-object.
218
   *
219
   * @return Arrayy
220
   */
221 3 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...
222
  {
223
    // init
224 3
    $data = array();
225
226
    if (
227 3
        $this->_result
228 3
        &&
229 3
        !$this->is_empty()
230 3
    ) {
231 3
      $this->reset();
232
233
      /** @noinspection PhpAssignmentInConditionInspection */
234 3
      while ($row = \mysqli_fetch_assoc($this->_result)) {
235 3
        $data[] = $this->cast($row);
236 3
      }
237 3
    }
238
239 3
    return Arrayy::create($data);
240
  }
241
242
  /**
243
   * Check if the result is empty.
244
   *
245
   * @return bool
246
   */
247 12
  public function is_empty()
248
  {
249 12
    if ($this->num_rows > 0) {
250 12
      return false;
251
    }
252
253 1
    return true;
254
  }
255
256
  /**
257
   * Reset the offset (data_seek) for the results.
258
   *
259
   * @return Result
260
   */
261 11
  public function reset()
262
  {
263 11
    if (!$this->is_empty()) {
264 11
      \mysqli_data_seek($this->_result, 0);
265 11
    }
266
267 11
    return $this;
268
  }
269
270
  /**
271
   * Fetch all results as "json"-string.
272
   *
273
   * @return string
274
   */
275 1
  public function json()
276
  {
277 1
    $data = $this->fetchAllArray();
278
279 1
    return UTF8::json_encode($data);
280
  }
281
282
  /**
283
   * __destruct
284
   *
285
   */
286 30
  public function __destruct()
287
  {
288 30
    $this->free();
289 30
  }
290
291
  /**
292
   * free the memory
293
   */
294 30
  public function free()
295
  {
296 30
    \mysqli_free_result($this->_result);
297 30
  }
298
299
  /**
300
   * alias for "Result->fetch()"
301
   *
302
   * @see Result::fetch()
303
   *
304
   * @return array|object|false <p><strong>false</strong> on error</p>
305
   */
306 1
  public function get()
307
  {
308 1
    return $this->fetch();
309
  }
310
311
  /**
312
   * Fetch.
313
   *
314
   * <p>
315
   *   <br />
316
   *   INFO: this will return an object by default, not an array<br />
317
   *   and you can change the behaviour via "Result->setDefaultResultType()"
318
   * </p>
319
   *
320
   * @param $reset
321
   *
322
   * @return array|object|false <p><strong>false</strong> on error</p>
323
   */
324 2
  public function fetch($reset = false)
325
  {
326 2
    $return = false;
327
328 2
    if ($this->_default_result_type === 'object') {
329 2
      $return = $this->fetchObject('', '', $reset);
330 2
    } elseif ($this->_default_result_type === 'array') {
331 2
      $return = $this->fetchArray($reset);
332 2
    } elseif ($this->_default_result_type === 'Arrayy') {
333
      $return = $this->fetchArrayy($reset);
334
    }
335
336 2
    return $return;
337
  }
338
339
  /**
340
   * Fetch as object.
341
   *
342
   * @param string     $class
343
   * @param null|array $params
344
   * @param bool       $reset
345
   *
346
   * @return object|false <p><strong>false</strong> on error</p>
347
   */
348 7
  public function fetchObject($class = '', $params = null, $reset = false)
349
  {
350 7
    if ($reset === true) {
351 1
      $this->reset();
352 1
    }
353
354 7
    if ($class && $params) {
355 1
      return ($row = \mysqli_fetch_object($this->_result, $class, $params)) ? $row : false;
356
    }
357
358 7
    if ($class) {
359 1
      return ($row = \mysqli_fetch_object($this->_result, $class)) ? $row : false;
360
    }
361
362 7
    return ($row = \mysqli_fetch_object($this->_result)) ? $this->cast($row) : false;
363
  }
364
365
  /**
366
   * Fetch as array.
367
   *
368
   * @param bool $reset
369
   *
370
   * @return array|false <p><strong>false</strong> on error</p>
371
   */
372 14 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...
373
  {
374 14
    if ($reset === true) {
375 1
      $this->reset();
376 1
    }
377
378 14
    $row = \mysqli_fetch_assoc($this->_result);
379 14
    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...
380 13
      return $this->cast($row);
381
    }
382
383 3
    if ($row === null) {
384 3
      return array();
385
    }
386
387
    return false;
388
  }
389
390
  /**
391
   * Fetch as "Arrayy"-object.
392
   *
393
   * @param bool $reset
394
   *
395
   * @return Arrayy|false <p><strong>false</strong> on error</p>
396
   */
397 2 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...
398
  {
399 2
    if ($reset === true) {
400
      $this->reset();
401
    }
402
403 2
    $row = \mysqli_fetch_assoc($this->_result);
404 2
    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...
405 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...
406
    }
407
408 1
    if ($row === null) {
409 1
      return Arrayy::create();
410
    }
411
412
    return false;
413
  }
414
415
  /**
416
   * alias for "Result->fetchAll()"
417
   *
418
   * @see Result::fetchAll()
419
   *
420
   * @return array
421
   */
422 1
  public function getAll()
423
  {
424 1
    return $this->fetchAll();
425
  }
426
427
  /**
428
   * Fetch all results.
429
   *
430
   * <p>
431
   *   <br />
432
   *   INFO: this will return an object by default, not an array<br />
433
   *   and you can change the behaviour via "Result->setDefaultResultType()"
434
   * </p>
435
   *
436
   * @return array
437
   */
438 2
  public function fetchAll()
439
  {
440 2
    $return = array();
441
442 2
    if ($this->_default_result_type === 'object') {
443 2
      $return = $this->fetchAllObject();
444 2
    } elseif ($this->_default_result_type === 'array') {
445 1
      $return = $this->fetchAllArray();
446 1
    } elseif ($this->_default_result_type === 'Arrayy') {
447
      $return = $this->fetchAllArray();
448
    }
449
450 2
    return $return;
451
  }
452
453
  /**
454
   * Fetch all results as array with objects.
455
   *
456
   * @param string     $class
457
   * @param null|array $params
458
   *
459
   * @return array
460
   */
461 3
  public function fetchAllObject($class = '', $params = null)
462
  {
463
    // init
464 3
    $data = array();
465
466 3
    if (!$this->is_empty()) {
467 3
      $this->reset();
468
469 3
      if ($class && $params) {
470
        /** @noinspection PhpAssignmentInConditionInspection */
471 1
        while ($row = \mysqli_fetch_object($this->_result, $class, $params)) {
472 1
          $data[] = $row;
473 1
        }
474 3
      } elseif ($class) {
475
        /** @noinspection PhpAssignmentInConditionInspection */
476 1
        while ($row = \mysqli_fetch_object($this->_result, $class)) {
477 1
          $data[] = $row;
478 1
        }
479 1
      } else {
480
        /** @noinspection PhpAssignmentInConditionInspection */
481 3
        while ($row = \mysqli_fetch_object($this->_result)) {
482 3
          $data[] = $this->cast($row);
483 3
        }
484
      }
485 3
    }
486
487 3
    return $data;
488
  }
489
490
  /**
491
   * alias for "Result->fetchAllObject()"
492
   *
493
   * @see Result::fetchAllObject()
494
   *
495
   * @return array of mysql-objects
496
   */
497 1
  public function getObject()
498
  {
499 1
    return $this->fetchAllObject();
500
  }
501
502
  /**
503
   * alias for "Result->fetchAllArrayy()"
504
   *
505
   * @see Result::fetchAllArrayy()
506
   *
507
   * @return Arrayy
508
   */
509
  public function getArrayy()
510
  {
511
    return $this->fetchAllArrayy();
512
  }
513
514
  /**
515
   * alias for "Result->fetchAllArray()"
516
   *
517
   * @see Result::fetchAllArray()
518
   *
519
   * @return array
520
   */
521 1
  public function getArray()
522
  {
523 1
    return $this->fetchAllArray();
524
  }
525
526
  /**
527
   * Fetch a single column as an 1-dimension array.
528
   *
529
   * @param string $column
530
   * @param bool   $skipNullValues <p>Skip "NULL"-values. | default: false</p>
531
   *
532
   * @return array <p>Return an empty array if the "$column" wasn't found</p>
533
   */
534 1
  public function fetchAllColumn($column, $skipNullValues = false)
535
  {
536 1
    return $this->fetchColumn($column, $skipNullValues, true);
537
  }
538
539
  /**
540
   * alias for "Result->fetchAllColumn()"
541
   *
542
   * @see Result::fetchAllColumn()
543
   *
544
   * @param string $column
545
   * @param bool   $skipNullValues
546
   *
547
   * @return array
548
   */
549
  public function getAllColumn($column, $skipNullValues = false)
550
  {
551
    return $this->fetchAllColumn($column, $skipNullValues);
552
  }
553
554
  /**
555
   * alias for "Result->fetchColumn()"
556
   *
557
   * @see Result::fetchColumn()
558
   *
559
   * @param $column
560
   * @param $asArray
561
   * @param $skipNullValues
562
   *
563
   * @return string|array <p>Return a empty string or an empty array if the "$column" wasn't found, depend on
564
   *                      "$asArray"</p>
565
   */
566 1
  public function getColumn($column, $skipNullValues = true, $asArray = false)
567
  {
568 1
    return $this->fetchColumn($column, $skipNullValues, $asArray);
569
  }
570
571
  /**
572
   * Fetch a single column as string (or as 1-dimension array).
573
   *
574
   * @param string $column
575
   * @param bool   $skipNullValues <p>Skip "NULL"-values. | default: true</p>
576
   * @param bool   $asArray        <p>Get all values and not only the last one. | default: false</p>
577
   *
578
   * @return string|array <p>Return a empty string or an empty array if the "$column" wasn't found, depend on
579
   *                      "$asArray"</p>
580
   */
581 2
  public function fetchColumn($column = '', $skipNullValues = true, $asArray = false)
582
  {
583 2
    if ($asArray === false) {
584 2
      $columnData = '';
585
586 2
      $data = $this->fetchAllArrayy()->reverse();
587 2 View Code Duplication
      foreach ($data as $_row) {
588
589 2
        if ($skipNullValues === true) {
590 2
          if (isset($_row[$column]) === false) {
591 1
            continue;
592
          }
593 2
        } else {
594 1
          if (array_key_exists($column, $_row) === false) {
595 1
            break;
596
          }
597
        }
598
599 2
        $columnData = $_row[$column];
600 2
        break;
601 2
      }
602
603 2
      return $columnData;
604
    }
605
606
    // -- return as array -->
607
608 1
    $columnData = array();
609
610 1
    $data = $this->fetchAllArray();
611
612 1 View Code Duplication
    foreach ($data as $_row) {
613
614 1
      if ($skipNullValues === true) {
615 1
        if (isset($_row[$column]) === false) {
616 1
          continue;
617
        }
618 1
      } else {
619 1
        if (array_key_exists($column, $_row) === false) {
620 1
          break;
621
        }
622
      }
623
624 1
      $columnData[] = $_row[$column];
625 1
    }
626
627 1
    return $columnData;
628
  }
629
630
  /**
631
   * Get the current "num_rows" as string.
632
   *
633
   * @return string
634
   */
635
  public function __toString()
636
  {
637
    return (string)$this->num_rows;
638
  }
639
}
640