Completed
Push — master ( 7d544d...db2f58 )
by Lars
02:14
created

Result::reset()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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