Completed
Push — master ( 8a455a...31a839 )
by Lars
02:13
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 0
CRAP Score 110

Importance

Changes 0
Metric Value
dl 29
loc 48
ccs 0
cts 0
cp 0
rs 5.3454
c 0
b 0
f 0
cc 10
eloc 25
nc 10
nop 3
crap 110

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 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 = (int)$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 (
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
        $_value = $_row[$value];
113 1
        $arrayPair[$_key] = $_value;
114
      }
115
    }
116
117
    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 24
   * @param array|object $data
129
   *
130 24
   * @return array|object|false <p><strong>false</strong> on error</p>
131 24
   */
132
  private function cast(&$data)
133
  {
134
    if (Helper::isMysqlndIsUsed() === true) {
135
      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) {
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...
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) {
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...
181
        if (isset($data->{$type_name})) {
182
          settype($data->{$type_name}, $type);
183
        }
184
      }
185
    }
186
187
    return $data;
188
  }
189
190
  /**
191 10
   * Fetch all results as array.
192
   *
193
   * @return array
194 10
   */
195 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 10
    // init
198 10
    $data = array();
199 10
200 10
    if (
201 10
        $this->_result
202
        &&
203
        !$this->is_empty()
204 10
    ) {
205 10
      $this->reset();
206 10
207 10
      /** @noinspection PhpAssignmentInConditionInspection */
208
      while ($row = \mysqli_fetch_assoc($this->_result)) {
209 10
        $data[] = $this->cast($row);
210
      }
211
    }
212
213
    return $data;
214
  }
215
216
  /**
217 1
   * Fetch all results as "Arrayy"-object.
218
   *
219
   * @return Arrayy
220 1
   */
221 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 1
    // init
224 1
    $data = array();
225 1
226 1
    if (
227 1
        $this->_result
228
        &&
229
        !$this->is_empty()
230 1
    ) {
231 1
      $this->reset();
232 1
233 1
      /** @noinspection PhpAssignmentInConditionInspection */
234
      while ($row = \mysqli_fetch_assoc($this->_result)) {
235 1
        $data[] = $this->cast($row);
236
      }
237
    }
238
239
    return Arrayy::create($data);
240
  }
241
242
  /**
243 12
   * Check if the result is empty.
244
   *
245 12
   * @return bool
246 12
   */
247
  public function is_empty()
248
  {
249 1
    if ($this->num_rows > 0) {
250
      return false;
251
    }
252
253
    return true;
254
  }
255
256
  /**
257 11
   * Reset the offset (data_seek) for the results.
258
   *
259 11
   * @return Result
260 11
   */
261 11
  public function reset()
262
  {
263 11
    if (!$this->is_empty()) {
264
      \mysqli_data_seek($this->_result, 0);
265
    }
266
267
    return $this;
268
  }
269
270
  /**
271 1
   * Fetch all results as "json"-string.
272
   *
273 1
   * @return string
274
   */
275 1
  public function json()
276
  {
277
    $data = $this->fetchAllArray();
278
279
    return UTF8::json_encode($data);
280
  }
281
282 28
  /**
283
   * __destruct
284 28
   *
285 28
   */
286
  public function __destruct()
287
  {
288
    $this->free();
289
  }
290 28
291
  /**
292 28
   * free the memory
293 28
   */
294
  public function free()
295
  {
296
    \mysqli_free_result($this->_result);
297
  }
298
299
  /**
300
   * alias for "Result->fetch()"
301
   *
302 1
   * @see Result::fetch()
303
   *
304 1
   * @return array|object|false <p><strong>false</strong> on error</p>
305
   */
306
  public function get()
307
  {
308
    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 2
   * @param $reset
321
   *
322 2
   * @return array|object|false <p><strong>false</strong> on error</p>
323
   */
324 2
  public function fetch($reset = false)
325 2
  {
326 2
    $return = false;
327 2
328 2
    if ($this->_default_result_type === 'object') {
329
      $return = $this->fetchObject('', '', $reset);
330
    } elseif ($this->_default_result_type === 'array') {
331
      $return = $this->fetchArray($reset);
332 2
    } elseif ($this->_default_result_type === 'Arrayy') {
333
      $return = $this->fetchArrayy($reset);
334
    }
335
336
    return $return;
337
  }
338
339
  /**
340
   * Fetch as object.
341
   *
342
   * @param string     $class
343
   * @param null|array $params
344 7
   * @param bool       $reset
345
   *
346 7
   * @return object|false <p><strong>false</strong> on error</p>
347 1
   */
348 1
  public function fetchObject($class = '', $params = null, $reset = false)
349
  {
350 7
    if ($reset === true) {
351 1
      $this->reset();
352
    }
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
      return ($row = \mysqli_fetch_object($this->_result, $class)) ? $row : false;
360
    }
361
362
    return ($row = \mysqli_fetch_object($this->_result)) ? $this->cast($row) : false;
363
  }
364
365
  /**
366
   * Fetch as array.
367
   *
368 11
   * @param bool $reset
369
   *
370 11
   * @return array|false <p><strong>false</strong> on error</p>
371 1
   */
372 1 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 11
    if ($reset === true) {
375 11
      $this->reset();
376 11
    }
377
378
    $row = \mysqli_fetch_assoc($this->_result);
379
    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
      return $this->cast($row);
381
    }
382
383
    return false;
384
  }
385
386
  /**
387
   * Fetch as "Arrayy"-object.
388
   *
389 1
   * @param bool $reset
390
   *
391 1
   * @return Arrayy|false <p><strong>false</strong> on error</p>
392
   */
393 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...
394
  {
395 1
    if ($reset === true) {
396 1
      $this->reset();
397 1
    }
398
399
    $row = \mysqli_fetch_assoc($this->_result);
400
    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...
401
      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...
402
    }
403
404
    return false;
405
  }
406
407
  /**
408
   * alias for "Result->fetchAll()"
409
   *
410 1
   * @see Result::fetchAll()
411
   *
412 1
   * @return array
413
   */
414
  public function getAll()
415
  {
416
    return $this->fetchAll();
417
  }
418
419
  /**
420
   * Fetch all results.
421
   *
422
   * <p>
423
   *   <br />
424
   *   INFO: this will return an object by default, not an array<br />
425
   *   and you can change the behaviour via "Result->setDefaultResultType()"
426 2
   * </p>
427
   *
428 2
   * @return array
429
   */
430 2
  public function fetchAll()
431 2
  {
432 2
    $return = array();
433 1
434 1
    if ($this->_default_result_type === 'object') {
435
      $return = $this->fetchAllObject();
436
    } elseif ($this->_default_result_type === 'array') {
437
      $return = $this->fetchAllArray();
438 2
    } elseif ($this->_default_result_type === 'Arrayy') {
439
      $return = $this->fetchAllArray();
440
    }
441
442
    return $return;
443
  }
444
445
  /**
446
   * Fetch all results as array with objects.
447
   *
448
   * @param string     $class
449 3
   * @param null|array $params
450
   *
451
   * @return array
452 3
   */
453
  public function fetchAllObject($class = '', $params = null)
454 3
  {
455 3
    // init
456
    $data = array();
457 3
458
    if (!$this->is_empty()) {
459 1
      $this->reset();
460 1
461 1
      if ($class && $params) {
462 3
        /** @noinspection PhpAssignmentInConditionInspection */
463
        while ($row = \mysqli_fetch_object($this->_result, $class, $params)) {
464 1
          $data[] = $row;
465 1
        }
466 1
      } elseif ($class) {
467 1
        /** @noinspection PhpAssignmentInConditionInspection */
468
        while ($row = \mysqli_fetch_object($this->_result, $class)) {
469 3
          $data[] = $row;
470 3
        }
471 3
      } else {
472
        /** @noinspection PhpAssignmentInConditionInspection */
473 3
        while ($row = \mysqli_fetch_object($this->_result)) {
474
          $data[] = $this->cast($row);
475 3
        }
476
      }
477
    }
478
479
    return $data;
480
  }
481
482
  /**
483
   * alias for "Result->fetchAllObject()"
484
   *
485 1
   * @see Result::fetchAllObject()
486
   *
487 1
   * @return array of mysql-objects
488
   */
489
  public function getObject()
490
  {
491
    return $this->fetchAllObject();
492
  }
493
494
  /**
495
   * alias for "Result->fetchAllArrayy()"
496
   *
497
   * @see Result::fetchAllArrayy()
498
   *
499
   * @return Arrayy
500
   */
501
  public function getArrayy()
502
  {
503
    return $this->fetchAllArrayy();
504
  }
505
506
  /**
507
   * alias for "Result->fetchAllArray()"
508
   *
509 1
   * @see Result::fetchAllArray()
510
   *
511 1
   * @return array
512
   */
513
  public function getArray()
514
  {
515
    return $this->fetchAllArray();
516
  }
517
518
  /**
519
   * Fetch a single column as an 1-dimension array.
520
   *
521
   * @param string $column
522
   * @param bool   $skipNullValues <p>Skip "NULL"-values. | default: false</p>
523 1
   *
524
   * @return array <p>Return an empty array if the "$column" wasn't found</p>
525 1
   */
526
  public function fetchAllColumn($column, $skipNullValues = false)
527
  {
528
    return $this->fetchColumn($column, $skipNullValues, true);
529
  }
530
531
  /**
532
   * alias for "Result->fetchAllColumn()"
533
   *
534
   * @see Result::fetchAllColumn()
535 2
   *
536
   * @param string $column
537 2
   * @param bool   $skipNullValues
538 2
   *
539
   * @return array
540 2
   */
541 2
  public function getAllColumn($column, $skipNullValues = false)
542 2
  {
543 2
    return $this->fetchAllColumn($column, $skipNullValues);
544 2
  }
545
546 2
  /**
547
   * alias for "Result->fetchColumn()"
548
   *
549
   * @see Result::fetchColumn()
550
   *
551
   * @param $column
552
   * @param $asArray
553
   * @param $skipNullValues
554
   *
555
   * @internal
556
   *
557
   * @return string|array <p>Return a empty string or an empty array if the "$column" wasn't found, depend on
558
   *                      "$asArray"</p>
559
   */
560
  public function getColumn($column, $skipNullValues = true, $asArray = false)
561
  {
562
    return $this->fetchColumn($column, $skipNullValues, $asArray);
563
  }
564
565
  /**
566
   * Fetch a single column as string (or as 1-dimension array).
567
   *
568
   * @param string $column
569
   * @param bool   $skipNullValues <p>Skip "NULL"-values. | default: true</p>
570
   * @param bool   $asArray        <p>Get all values and not only the last one. | default: false</p>
571
   *
572
   * @internal
573
   *
574
   * @return string|array <p>Return a empty string or an empty array if the "$column" wasn't found, depend on
575
   *                      "$asArray"</p>
576
   */
577
  public function fetchColumn($column = '', $skipNullValues = true, $asArray = false)
578
  {
579
    if ($asArray === false) {
580
      $columnData = '';
581
582
      $data = $this->fetchAllArrayy()->reverse();
583 View Code Duplication
      foreach ($data as $_row) {
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...
584
585
        if ($skipNullValues === true) {
586
          if (isset($_row[$column]) === false) {
587
            continue;
588
          }
589
        } else {
590
          if (array_key_exists($column, $_row) === false) {
591
            break;
592
          }
593
        }
594
595
        $columnData = $_row[$column];
596
        break;
597
      }
598
599
      return $columnData;
600
    }
601
602
    // -- return as array -->
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
603
604
    $columnData = array();
605
606
    $data = $this->fetchAllArray();
607
608 View Code Duplication
    foreach ($data as $_row) {
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...
609
610
      if ($skipNullValues === true) {
611
        if (isset($_row[$column]) === false) {
612
          continue;
613
        }
614
      } else {
615
        if (array_key_exists($column, $_row) === false) {
616
          break;
617
        }
618
      }
619
620
      $columnData[] = $_row[$column];
621
    }
622
623
    return $columnData;
624
  }
625
626
  /**
627
   * Get the current "num_rows" as string.
628
   *
629
   * @return string
630
   */
631
  public function __toString()
632
  {
633
    return (string)$this->num_rows;
634
  }
635
}
636