Completed
Push — master ( 67271f...f4054d )
by Lars
03:38 queued 01:21
created

Arrayy::getRandomKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Arrayy;
4
5
use ArrayAccess;
6
use Closure;
7
use voku\helper\UTF8;
8
9
/**
10
 * Methods to manage arrays.
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
class Arrayy extends \ArrayObject implements \Countable, \IteratorAggregate, \ArrayAccess, \Serializable
16
{
17
  /**
18
   * @var array
19
   */
20
  protected $array = array();
21
22
  /**
23
   * Initializes
24
   *
25
   * @param array $array
26
   */
27 667
  public function __construct($array = array())
28
  {
29 667
    $array = $this->fallbackForArray($array);
30
31 665
    $this->array = $array;
32 665
  }
33
34
  /**
35
   * create a fallback for array
36
   *
37
   * 1. fallback to empty array, if there is nothing
38
   * 2. cast a String or Object with "__toString" into an array
39
   * 3. call "__toArray" on Object, if the method exists
40
   * 4. throw a "InvalidArgumentException"-Exception
41
   *
42
   * @param $array
43
   *
44
   * @return array
45
   */
46 667
  protected function fallbackForArray(&$array)
47
  {
48 667
    if (is_array($array)) {
49 665
      return $array;
50
    }
51
52 5
    if ($array instanceof self) {
53 1
      return $array->getArray();
54
    }
55
56 4
    if (!$array) {
57 1
      return array();
58
    }
59
60
    if (
61 3
        is_string($array)
62
        ||
63 2
        (is_object($array) && method_exists($array, '__toString'))
64 3
    ) {
65 1
      return (array)$array;
66
    }
67
68 2
    if (is_object($array) && method_exists($array, '__toArray')) {
69
      return (array)$array->__toArray();
70
    }
71
72 2
    throw new \InvalidArgumentException(
73
        'Passed value must be a array'
74 2
    );
75
  }
76
77
  /**
78
   * Get the current array from the "Arrayy"-object
79
   *
80
   * @return array
81
   */
82 466
  public function getArray()
83
  {
84 466
    return $this->array;
85
  }
86
87
  /**
88
   * Create a new Arrayy object via string.
89
   *
90
   * @param string      $str       The input string.
91
   * @param string|null $delimiter The boundary string.
92
   * @param string|null $regEx     Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be used.
93
   *
94
   * @return Arrayy Returns created instance
95
   */
96 8
  public static function createFromString($str, $delimiter, $regEx = null)
97
  {
98 8
    if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
99 1
      preg_match_all($regEx, $str, $array);
100
101 1
      if (count($array) > 0) {
102 1
        $array = $array[0];
103 1
      }
104
105 1
    } else {
106 7
      $array = explode($delimiter, $str);
107
    }
108
109
    // trim all string in the array
110 8
    array_walk(
111 8
        $array,
112
        function (&$val) {
113 8
          if (is_string($val)) {
114 8
            $val = trim($val);
115 8
          }
116 8
        }
117 8
    );
118
119 8
    return static::create($array);
120
  }
121
122
  /**
123
   * Creates a Arrayy object.
124
   *
125
   * @param array $array
126
   *
127
   * @return Arrayy Returns created instance
128
   */
129 429
  public static function create($array = array())
130
  {
131 429
    return new static($array);
132
  }
133
134
  /**
135
   * create a new Arrayy object via JSON,
136
   *
137
   * @param string $json
138
   *
139
   * @return Arrayy Returns created instance
140
   */
141 5
  public static function createFromJson($json)
142
  {
143 5
    $array = UTF8::json_decode($json, true);
144
145 5
    return static::create($array);
146
  }
147
148
  /**
149
   * Create a new instance filled with values from an object implementing ArrayAccess.
150
   *
151
   * @param ArrayAccess $elements Object that implements ArrayAccess
152
   *
153
   * @return Arrayy Returns created instance
154
   */
155 4
  public static function createFromObject(ArrayAccess $elements)
156
  {
157 4
    $array = new static();
158 4
    foreach ($elements as $key => $value) {
159
      /** @noinspection OffsetOperationsInspection */
160 3
      $array[$key] = $value;
161 4
    }
162
163 4
    return $array;
164
  }
165
166
  /**
167
   * Create a new instance containing a range of elements.
168
   *
169
   * @param mixed $low  First value of the sequence
170
   * @param mixed $high The sequence is ended upon reaching the end value
171
   * @param int   $step Used as the increment between elements in the sequence
172
   *
173
   * @return Arrayy The created array
174
   */
175 1
  public static function createWithRange($low, $high, $step = 1)
176
  {
177 1
    return static::create(range($low, $high, $step));
178
  }
179
180
  /**
181
   * alias: for "Arrayy->random()"
182
   *
183
   * @return Arrayy
184
   */
185 3
  public function getRandom()
186
  {
187 3
    return $this->random();
188
  }
189
190
  /**
191
   * Get a random value from the current array.
192
   *
193
   * @param null|int $number how many values you will take?
194
   *
195
   * @return Arrayy
196
   */
197 27
  public function random($number = null)
198
  {
199 27
    if ($this->count() === 0) {
200
      return static::create();
201
    }
202
203 27
    if ($number === null) {
204 15
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
205
206 15
      return static::create($arrayRandValue);
207
    }
208
209 14
    shuffle($this->array);
210
211 14
    return $this->first($number);
212
  }
213
214
  /**
215
   * Count the values from the current array.
216
   *
217
   * INFO: only a alias for "$arrayy->size()"
218
   *
219
   * @return int
220
   */
221 102
  public function count()
222
  {
223 102
    return $this->size();
224
  }
225
226
  /**
227
   * Get the size of an array.
228
   *
229
   * @return int
230
   */
231 102
  public function size()
232
  {
233 102
    return count($this->array);
234
  }
235
236
  /**
237
   * Get the first value(s) from the current array.
238
   *
239
   * @param int|null $number how many values you will take?
240
   *
241
   * @return Arrayy
242
   */
243 43
  public function first($number = null)
244
  {
245 43
    if ($number === null) {
246 12
      $array = (array)array_shift($this->array);
247 12
    } else {
248 31
      $number = (int)$number;
249 31
      $array = array_splice($this->array, 0, $number, true);
250
    }
251
252 43
    return static::create($array);
253
  }
254
255
  /**
256
   * Append a value to an array.
257
   *
258
   * @param mixed $value
259
   *
260
   * @return Arrayy
261
   */
262 8
  public function append($value)
263
  {
264 8
    $this->array[] = $value;
265
266 8
    return static::create($this->array);
267
  }
268
269
  /**
270
   * @return mixed
271
   */
272
  public function serialize()
273
  {
274
    return serialize($this->array);
275
  }
276
277
  /**
278
   * @param string $array
279
   */
280
  public function unserialize($array)
281
  {
282
    $this->array = unserialize($array);
283
  }
284
285
  /**
286
   * Assigns a value to the specified offset.
287
   *
288
   * @param mixed $offset
289
   * @param mixed $value
290
   */
291 13
  public function offsetSet($offset, $value)
292
  {
293 13
    if (null === $offset) {
294 4
      $this->array[] = $value;
295 4
    } else {
296 9
      $this->array[$offset] = $value;
297
    }
298 13
  }
299
300
  /**
301
   * alias: for "Arrayy->randomValue()"
302
   *
303
   * @return mixed get a random value or null if there wasn't a value
304
   */
305
  public function getRandomValue()
306
  {
307
    return $this->randomValue();
308
  }
309
310
  /**
311
   * Pick a random value from the values of this array.
312
   *
313
   * @return mixed get a random value or null if there wasn't a value
314
   */
315 View Code Duplication
  public function randomValue()
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...
316
  {
317
    $result = $this->random(1);
318
319
    if (!isset($result[0])) {
320
      $result[0] = null;
321
    }
322
323
    return $result[0];
324
  }
325
326
  /**
327
   * alias: for "Arrayy->randomValues()"
328
   *
329
   * @param int $number
330
   *
331
   * @return Arrayy
332
   */
333 6
  public function getRandomValues($number)
334
  {
335 6
    return $this->randomValues($number);
336
  }
337
338
  /**
339
   * Pick a given number of random values out of this array.
340
   *
341
   * @param int $number
342
   *
343
   * @return Arrayy
344
   */
345 6
  public function randomValues($number)
346
  {
347 6
    $number = (int)$number;
348
349 6
    return $this->random($number);
350
  }
351
352
  /**
353
   * alias: for "Arrayy->randomKey()"
354
   *
355
   * @return mixed get a key/index or null if there wasn't a key/index
356
   */
357 3
  public function getRandomKey()
358
  {
359 3
    return $this->randomKey();
360
  }
361
362
  /**
363
   * Pick a random key/index from the keys of this array.
364
   *
365
   *
366
   * @return mixed get a key/index or null if there wasn't a key/index
367
   *
368
   * @throws \RangeException If array is empty
369
   */
370 3 View Code Duplication
  public function randomKey()
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...
371
  {
372 3
    $result = $this->randomKeys(1);
373
374 3
    if (!isset($result[0])) {
375
      $result[0] = null;
376
    }
377
378 3
    return $result[0];
379
  }
380
381
  /**
382
   * Pick a given number of random keys/indexes out of this array.
383
   *
384
   * @param int $number The number of keys/indexes (should be <= $this->count())
385
   *
386
   * @return Arrayy
387
   *
388
   * @throws \RangeException If array is empty
389
   */
390 12
  public function randomKeys($number)
391
  {
392 12
    $number = (int)$number;
393 12
    $count = $this->count();
394
395 12
    if ($number === 0 || $number > $count) {
396 3
      throw new \RangeException(
397 3
          sprintf(
398 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
399 3
              $number,
400
              $count
401 3
          )
402 3
      );
403
    }
404
405 9
    $result = (array)array_rand($this->array, $number);
406
407 9
    return static::create($result);
408
  }
409
410
  /**
411
   * alias: for "Arrayy->randomKeys()"
412
   *
413
   * @param int $number
414
   *
415
   * @return Arrayy
416
   */
417 9
  public function getRandomKeys($number)
418
  {
419 9
    return $this->randomKeys($number);
420
  }
421
422
  /**
423
   * find by ...
424
   *
425
   * @param        $property
426
   * @param        $value
427
   * @param string $comparisonOp
428
   *
429
   * @return Arrayy
430
   */
431
  public function findBy($property, $value, $comparisonOp = 'eq')
432
  {
433
    $array = $this->filterBy($property, $value, $comparisonOp);
434
435
    return static::create($array);
0 ignored issues
show
Documentation introduced by
$array is of type object<Arrayy\Arrayy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
436
  }
437
438
  /**
439
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
440
   * within that.
441
   *
442
   * @param        $property
443
   * @param        $value
444
   * @param string $comparisonOp
445
   *
446
   * @return Arrayy
447
   */
448 1
  public function filterBy($property, $value, $comparisonOp = null)
449
  {
450 1
    if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
451 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
452 1
    }
453
454
    $ops = array(
455
        'eq'          => function ($item, $prop, $value) {
456 1
          return $item[$prop] === $value;
457 1
        },
458
        'gt'          => function ($item, $prop, $value) {
459
          return $item[$prop] > $value;
460 1
        },
461
        'gte'         => function ($item, $prop, $value) {
462
          return $item[$prop] >= $value;
463 1
        },
464
        'lt'          => function ($item, $prop, $value) {
465 1
          return $item[$prop] < $value;
466 1
        },
467
        'lte'         => function ($item, $prop, $value) {
468
          return $item[$prop] <= $value;
469 1
        },
470
        'ne'          => function ($item, $prop, $value) {
471
          return $item[$prop] !== $value;
472 1
        },
473
        'contains'    => function ($item, $prop, $value) {
474 1
          return in_array($item[$prop], (array)$value, true);
475 1
        },
476
        'notContains' => function ($item, $prop, $value) {
477
          return !in_array($item[$prop], (array)$value, true);
478 1
        },
479
        'newer'       => function ($item, $prop, $value) {
480
          return strtotime($item[$prop]) > strtotime($value);
481 1
        },
482
        'older'       => function ($item, $prop, $value) {
483
          return strtotime($item[$prop]) < strtotime($value);
484 1
        },
485 1
    );
486
487 1
    $result = array_values(
488 1
        array_filter(
489 1
            (array)$this->array,
490
            function ($item) use (
491 1
                $property,
492 1
                $value,
493 1
                $ops,
494 1
                $comparisonOp
495
            ) {
496 1
              $item = (array)$item;
497 1
              $itemArrayy = new Arrayy($item);
498 1
              $item[$property] = $itemArrayy->get($property, array());
499
500 1
              return $ops[$comparisonOp]($item, $property, $value);
501
            }
502 1
        )
503 1
    );
504
505 1
    return static::create($result);
506
  }
507
508
  /**
509
   * Get a value from an array (optional using dot-notation).
510
   *
511
   * @param string $key     The key to look for
512
   * @param mixed  $default Default value to fallback to
513
   * @param array  $array   The array to get from,
514
   *                        if it's set to "null" we use the current array from the class
515
   *
516
   * @return mixed
517
   */
518 31
  public function get($key, $default = null, $array = null)
519
  {
520 31
    if (is_array($array) === true) {
521 3
      $usedArray = $array;
522 3
    } else {
523 29
      $usedArray = $this->array;
524
    }
525
526 31
    if (null === $key) {
527 1
      return $usedArray;
528
    }
529
530 31
    if (isset($usedArray[$key])) {
531 22
      return $usedArray[$key];
532
    }
533
534
    // Crawl through array, get key according to object or not
535 16
    foreach (explode('.', $key) as $segment) {
536 16
      if (!isset($usedArray[$segment])) {
537 16
        return $default instanceof Closure ? $default() : $default;
538
      }
539
540
      $usedArray = $usedArray[$segment];
541
    }
542
543
    return $usedArray;
544
  }
545
546
  /**
547
   * WARNING: Creates a Arrayy object by reference.
548
   *
549
   * @param array $array
550
   *
551
   * @return $this
552
   */
553
  public function createByReference(&$array = array())
554
  {
555
    $array = $this->fallbackForArray($array);
556
557
    $this->array = &$array;
558
559
    return $this;
560
  }
561
562
  /**
563
   * Get all values from a array.
564
   *
565
   * @return Arrayy
566
   */
567 1
  public function values()
568
  {
569 1
    $array = array_values((array)$this->array);
570
571 1
    return static::create($array);
572
  }
573
574
  /**
575
   * Group values from a array according to the results of a closure.
576
   *
577
   * @param string $grouper a callable function name
578
   * @param bool   $saveKeys
579
   *
580
   * @return Arrayy
581
   */
582 3
  public function group($grouper, $saveKeys = false)
583
  {
584 3
    $array = (array)$this->array;
585 3
    $result = array();
586
587
    // Iterate over values, group by property/results from closure
588 3
    foreach ($array as $key => $value) {
589 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
590 3
      $newValue = $this->get($groupKey, null, $result);
591
592
      // Add to results
593 3
      if ($groupKey !== null) {
594 2
        if ($saveKeys) {
595 1
          $result[$groupKey] = $newValue;
596 1
          $result[$groupKey][$key] = $value;
597 1
        } else {
598 1
          $result[$groupKey] = $newValue;
599 1
          $result[$groupKey][] = $value;
600
        }
601 2
      }
602
603 3
    }
604
605 3
    return static::create($result);
606
  }
607
608
  /**
609
   * Given a list and an iterate-function that returns
610
   * a key for each element in the list (or a property name),
611
   * returns an object with an index of each item.
612
   *
613
   * Just like groupBy, but for when you know your keys are unique.
614
   *
615
   * @param mixed $key
616
   *
617
   * @return Arrayy
618
   */
619 3
  public function indexBy($key)
620
  {
621 3
    $results = array();
622
623 3
    foreach ($this->array as $a) {
624 3
      if (isset($a[$key])) {
625 2
        $results[$a[$key]] = $a;
626 2
      }
627 3
    }
628
629 3
    return static::create($results);
630
  }
631
632
  /**
633
   * magic to string
634
   *
635
   * @return string
636
   */
637 17
  public function __toString()
638
  {
639 17
    return $this->toString();
640
  }
641
642
  /**
643
   * Implodes array to a string with specified separator.
644
   *
645
   * @param string $separator The element's separator
646
   *
647
   * @return string The string representation of array, separated by ","
648
   */
649 17
  public function toString($separator = ',')
650
  {
651 17
    return $this->implode($separator);
652
  }
653
654
  /**
655
   * Implodes an array.
656
   *
657
   * @param string $with What to implode it with
658
   *
659
   * @return string
660
   */
661 25
  public function implode($with = '')
662
  {
663 25
    return implode($with, $this->array);
664
  }
665
666
  /**
667
   * Push one or more values onto the end of array at once.
668
   *
669
   * @return $this An Arrayy object with pushed elements to the end of array
670
   */
671 4 View Code Duplication
  public function push(/* variadic arguments allowed */)
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...
672
  {
673 4
    if (func_num_args()) {
674 4
      $args = array_merge(array(&$this->array), func_get_args());
675 4
      call_user_func_array('array_push', $args);
676 4
    }
677
678 4
    return $this;
679
  }
680
681
  /**
682
   * Shifts a specified value off the beginning of array.
683
   *
684
   * @return mixed A shifted element from the current array.
685
   */
686 4
  public function shift()
687
  {
688 4
    return array_shift($this->array);
689
  }
690
691
  /**
692
   * Prepends one or more values to the beginning of array at once.
693
   *
694
   * @return Arrayy Array object with prepended elements to the beginning of array
695
   */
696 4 View Code Duplication
  public function unshift(/* variadic arguments allowed */)
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...
697
  {
698 4
    if (func_num_args()) {
699 4
      $args = array_merge(array(&$this->array), func_get_args());
700 4
      call_user_func_array('array_unshift', $args);
701 4
    }
702
703 4
    return $this;
704
  }
705
706
  /**
707
   * Get a value by key.
708
   *
709
   * @param $key
710
   *
711
   * @return mixed
712
   */
713
  public function &__get($key)
714
  {
715
    return $this->array[$key];
716
  }
717
718
  /**
719
   * Assigns a value to the specified element.
720
   *
721
   * @param $key
722
   * @param $value
723
   */
724
  public function __set($key, $value)
725
  {
726
    $this->array[$key] = $value;
727
  }
728
729
  /**
730
   * Whether or not an element exists by key.
731
   *
732
   * @param $key
733
   *
734
   * @return bool
735
   */
736
  public function __isset($key)
737
  {
738
    return isset($this->array[$key]);
739
  }
740
741
  /**
742
   * Unset element by key
743
   *
744
   * @param mixed $key
745
   */
746
  public function __unset($key)
747
  {
748
    unset($this->array[$key]);
749
  }
750
  /**
751
   * Call object as function.
752
   *
753
   * @param mixed $key
754
   *
755
   * @return mixed
756
   */
757
  public function __invoke($key = null)
758
  {
759
    if ($key !== null) {
760
      if (isset($this->array[$key])) {
761
        return $this->array[$key];
762
      } else {
763
        return false;
764
      }
765
    }
766
767
    return (array)$this->array;
768
  }/**
769
   * Whether or not an offset exists.
770
   *
771
   * @param mixed $offset
772
   *
773
   * @return bool
774
   */
775 24
  public function offsetExists($offset)
776
  {
777 24
    return isset($this->array[$offset]);
778
  }
779
780
  /**
781
   * Search for the value of the current array via $index.
782
   *
783
   * @param mixed $index
784
   *
785
   * @return Arrayy will return a empty Arrayy if the value wasn't found
786
   */
787 7
  public function searchValue($index)
788
  {
789
    // init
790 7
    $return = array();
791
792 7
    if (null !== $index) {
793 7
      $keyExists = isset($this->array[$index]);
794
795 7
      if ($keyExists !== false) {
796 5
        $return = array($this->array[$index]);
797 5
      }
798 7
    }
799
800 7
    return static::create($return);
801
  }
802
803
  /**
804
   * Check if all items in current array match a truth test.
805
   *
806
   * @param \Closure $closure
807
   *
808
   * @return bool
809
   */
810 9 View Code Duplication
  public function matches(\Closure $closure)
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...
811
  {
812
    // Reduce the array to only booleans
813 9
    $array = $this->each($closure);
814
815
    // Check the results
816 9
    if (count($array) === 0) {
817 2
      return true;
818
    }
819
820 7
    $array = array_search(false, $array->toArray(), false);
821
822 7
    return is_bool($array);
823
  }
824
825
  /**
826
   * Iterate over the current array and modify the array's value.
827
   *
828
   * @param \Closure $closure
829
   *
830
   * @return Arrayy
831
   */
832 22 View Code Duplication
  public function each(\Closure $closure)
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...
833
  {
834 22
    $array = $this->array;
835
836 22
    foreach ($array as $key => &$value) {
837 18
      $value = $closure($value, $key);
838 22
    }
839
840 22
    return static::create($array);
841
  }
842
843
  /**
844
   * alias: for "Arrayy->getArray()"
845
   */
846 153
  public function toArray()
847
  {
848 153
    return $this->getArray();
849
  }
850
851
  /**
852
   * Check if any item in the current array matches a truth test.
853
   *
854
   * @param \Closure $closure
855
   *
856
   * @return bool
857
   */
858 9 View Code Duplication
  public function matchesAny(\Closure $closure)
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...
859
  {
860
    // Reduce the array to only booleans
861 9
    $array = $this->each($closure);
862
863
    // Check the results
864 9
    if (count($array) === 0) {
865 2
      return true;
866
    }
867
868 7
    $array = array_search(true, $array->toArray(), false);
869
870 7
    return is_int($array);
871
  }
872
873
  /**
874
   * Check whether array is associative or not.
875
   *
876
   * @return bool Returns true if associative, false otherwise
877
   */
878 14
  public function isAssoc()
879
  {
880 14
    if ($this->isEmpty()) {
881 2
      return false;
882
    }
883
884 12
    foreach ($this->getKeys()->getArray() as $key) {
885 12
      if (!is_string($key)) {
886 10
        return false;
887
      }
888 2
    }
889
890 2
    return true;
891
  }
892
893
  /**
894
   * Check whether the array is empty or not.
895
   *
896
   * @return bool Returns true if empty, false otherwise
897
   */
898 22
  public function isEmpty()
899
  {
900 22
    return !$this->array;
901
  }
902
903
/**
904
   * alias: for "Arrayy->keys()"
905
   *
906
   * @return Arrayy
907
   */
908 15
  public function getKeys()
909
  {
910 15
    return $this->keys();
911
  }
912
913
    /**
914
   * Get all keys from the current array.
915
   *
916
   * @return Arrayy
917
   */
918 20
  public function keys()
919
  {
920 20
    $array = array_keys((array)$this->array);
921
922 20
    return static::create($array);
923
  }
924
  /**
925
   * Check whether array is numeric or not.
926
   *
927
   * @return bool Returns true if numeric, false otherwise
928
   */
929 4
  public function isNumeric()
930
  {
931 4
    if ($this->isEmpty()) {
932 1
      return false;
933
    }
934
935 3
    foreach ($this->getKeys() as $key) {
936 3
      if (!is_int($key)) {
937 2
        return false;
938
      }
939 2
    }
940
941 1
    return true;
942
  }/**
943
   * Unset an offset.
944
   *
945
   * @param mixed $offset
946
   */
947 5
  public function offsetUnset($offset)
948
  {
949 5
    if ($this->offsetExists($offset)) {
950 3
      unset($this->array[$offset]);
951 3
    }
952 5
  }
953
954
  /**
955
   * Check if the current array is a multi-array.
956
   *
957
   * @return bool
958
   */
959 13
  public function isMultiArray()
960
  {
961 13
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
962
  }
963
964
  /**
965
   * Check if an item is in the current array.
966
   *
967
   * @param mixed $value
968
   *
969
   * @return bool
970
   */
971 13
  public function contains($value)
972
  {
973 13
    return in_array($value, $this->array, true);
974
  }
975
976
  /**
977
   * Check if the given key/index exists in the array.
978
   *
979
   * @param mixed $key Key/index to search for
980
   *
981
   * @return bool Returns true if the given key/index exists in the array, false otherwise
982
   */
983 4
  public function containsKey($key)
984
  {
985 4
    return array_key_exists($key, $this->array);
986
  }
987
988
  /**
989
   * Returns the average value of the current array.
990
   *
991
   * @param int $decimals The number of decimals to return
992
   *
993
   * @return int|double The average value
994
   */
995 10
  public function average($decimals = null)
996
  {
997 10
    $count = $this->count();
998
999 10
    if (!$count) {
1000 2
      return 0;
1001
    }
1002
1003 8
    if (!is_int($decimals)) {
1004 3
      $decimals = null;
1005 3
    }
1006
1007 8
    return round(array_sum($this->array) / $count, $decimals);
1008
  }
1009
1010
  /**
1011
   * Count the values from the current array.
1012
   *
1013
   * INFO: only a alias for "$arrayy->size()"
1014
   *
1015
   * @return int
1016
   */
1017 10
  public function length()
1018
  {
1019 10
    return $this->size();
1020
  }
1021
1022
  /**
1023
   * Get the max value from an array.
1024
   *
1025
   * @return mixed
1026
   */
1027 10
  public function max()
1028
  {
1029 10
    if ($this->count() === 0) {
1030 1
      return false;
1031
    }
1032
1033 9
    return max($this->array);
1034
  }
1035
1036
/**
1037
   * Get the min value from an array.
1038
   *
1039
   * @return mixed
1040
   */
1041 10
  public function min()
1042
  {
1043 10
    if ($this->count() === 0) {
1044 1
      return false;
1045
    }
1046
1047 9
    return min($this->array);
1048
  }
1049
1050
  /**
1051
   * Find the first item in an array that passes the truth test,
1052
   *  otherwise return false
1053
   *
1054
   * @param \Closure $closure
1055
   *
1056
   * @return mixed|false false if we did not find the value
1057
   */
1058 8
  public function find(\Closure $closure)
1059
  {
1060 8
    foreach ($this->array as $key => $value) {
1061 6
      if ($closure($value, $key)) {
1062 5
        return $value;
1063
      }
1064 5
    }
1065
1066 3
    return false;
1067
  }
1068
1069
    /**
1070
   * WARNING!!! -> Clear the current array.
1071
   *
1072
   * @return $this will always return an empty Arrayy object
1073
   */
1074 4
  public function clear()
1075
  {
1076 4
    $this->array = array();
1077
1078 4
    return $this;
1079
  }
1080
  /**
1081
   * Clean all falsy values from an array.
1082
   *
1083
   * @return Arrayy
1084
   */
1085 8
  public function clean()
1086
  {
1087 8
    return $this->filter(
1088
        function ($value) {
1089 7
          return (bool)$value;
1090
        }
1091 8
    );
1092
  }/**
1093
   * Returns the value at specified offset.
1094
   *
1095
   * @param mixed $offset
1096
   *
1097
   * @return mixed return null if the offset did not exists
1098
   */
1099 15
  public function offsetGet($offset)
1100
  {
1101 15
    return $this->offsetExists($offset) ? $this->array[$offset] : null;
1102
  }
1103
1104
  /**
1105
   * Find all items in an array that pass the truth test.
1106
   *
1107
   * @param \Closure|null $closure
1108
   *
1109
   * @return Arrayy
1110
   */
1111 8
  public function filter($closure = null)
1112
  {
1113 8
    if (!$closure) {
1114 1
      return $this->clean();
1115
    }
1116
1117 8
    $array = array_filter($this->array, $closure);
1118
1119 8
    return static::create($array);
1120
  }
1121
1122
  /**
1123
   * Get a random value from an array, with the ability to skew the results.
1124
   *
1125
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
1126
   *
1127
   * @param array    $array
1128
   * @param null|int $number how many values you will take?
1129
   *
1130
   * @return Arrayy
1131
   */
1132 9
  public function randomWeighted(array $array, $number = null)
1133
  {
1134 9
    $options = array();
1135 9
    foreach ($array as $option => $weight) {
1136 9
      if ($this->searchIndex($option) !== false) {
1137 2
        for ($i = 0; $i < $weight; ++$i) {
1138 1
          $options[] = $option;
1139 1
        }
1140 2
      }
1141 9
    }
1142
1143 9
    return $this->mergeAppendKeepIndex($options)->random($number);
1144
  }
1145
1146
  /**
1147
   * Search for the first index of the current array via $value.
1148
   *
1149
   * @param mixed $value
1150
   *
1151
   * @return mixed
1152
   */
1153 20
  public function searchIndex($value)
1154
  {
1155 20
    return array_search($value, $this->array, true);
1156
  }
1157
1158
  /**
1159
   * Merge the new $array into the current array.
1160
   *
1161
   * - keep key,value from the current array, also if the index is in the new $array
1162
   *
1163
   * @param array $array
1164
   * @param bool  $recursive
1165
   *
1166
   * @return Arrayy
1167
   */
1168 25 View Code Duplication
  public function mergeAppendKeepIndex(array $array = array(), $recursive = 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...
1169
  {
1170 25
    if (true === $recursive) {
1171 4
      $result = array_replace_recursive($this->array, $array);
1172 4
    } else {
1173 21
      $result = array_replace($this->array, $array);
1174
    }
1175
1176 25
    return static::create($result);
1177
  }
1178
1179
  /**
1180
   * alias: for "Arrayy->searchIndex()"
1181
   *
1182
   * @param mixed $value Value to search for
1183
   *
1184
   * @return mixed
1185
   */
1186 4
  public function indexOf($value)
1187
  {
1188 4
    return $this->searchIndex($value);
1189
  }
1190
1191
/**
1192
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1193
   *
1194
   * @param array $search
1195
   *
1196
   * @return bool
1197
   */
1198 1
  public function intersects(array $search)
1199
  {
1200 1
    return count($this->intersection($search)->array) > 0;
1201
  }
1202
1203
  /**
1204
   * Return an array with all elements found in input array.
1205
   *
1206
   * @param array $search
1207
   *
1208
   * @return Arrayy
1209
   */
1210 2
  public function intersection(array $search)
1211
  {
1212 2
    $result = array_values(array_intersect($this->array, $search));
1213
1214 2
    return static::create($result);
1215
  }
1216
1217
  /**
1218
   * Get the last value from the current array.
1219
   *
1220
   * @return mixed return null if there wasn't a element.
1221
   */
1222 4
  public function last()
1223
  {
1224 4
    $result = $this->pop();
1225
1226 4
    if (null === $result) {
1227 1
      return false;
1228
    } else {
1229 3
      return $result;
1230
    }
1231
  }
1232
1233
  /**
1234
   * Get the last value(s) from the current array.
1235
   *
1236
   * @param int|null $number
1237
   *
1238
   * @return Arrayy
1239
   */
1240 11
  public function lasts($number = null)
1241
  {
1242 11
    if ($number === null) {
1243 7
      $poppedValue = (array)$this->pop();
1244 7
      $arrayy = static::create($poppedValue);
1245 7
    } else {
1246 4
      $number = (int)$number;
1247 4
      $arrayy = $this->rest(-$number);
1248
    }
1249
1250 11
    return $arrayy;
1251
  }
1252
1253
    /**
1254
   * Pop a specified value off the end of the current array.
1255
   *
1256
   * @return mixed The popped element from the current array.
1257
   */
1258 15
  public function pop()
1259
  {
1260 15
    return array_pop($this->array);
1261
  }
1262
  /**
1263
   * Get the last elements from index $from until the end of this array.
1264
   *
1265
   * @param int $from
1266
   *
1267
   * @return Arrayy
1268
   */
1269 16
  public function rest($from = 1)
1270
  {
1271 16
    $result = array_splice($this->array, $from);
1272
1273 16
    return static::create($result);
1274
  }/**
1275
   * Returns a new ArrayIterator, thus implementing the IteratorAggregate interface.
1276
   *
1277
   * @return \ArrayIterator An iterator for the values in the array.
1278
   */
1279 16
  public function getIterator()
1280
  {
1281 16
    return new \ArrayIterator($this->array);
1282
  }
1283
1284
  /**
1285
   * Get everything but the last..$to items.
1286
   *
1287
   * @param int $to
1288
   *
1289
   * @return Arrayy
1290
   */
1291 12
  public function initial($to = 1)
1292
  {
1293 12
    $slice = count($this->array) - $to;
1294
1295 12
    return $this->first($slice);
1296
  }
1297
1298
  /**
1299
   * Extract a slice of the array.
1300
   *
1301
   * @param int      $offset       Slice begin index
1302
   * @param int|null $length       Length of the slice
1303
   * @param bool     $preserveKeys Whether array keys are preserved or no
1304
   *
1305
   * @return static A slice of the original array with length $length
1306
   */
1307 4
  public function slice($offset, $length = null, $preserveKeys = false)
1308
  {
1309 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
1310
1311 4
    return static::create($result);
1312
  }
1313
1314
  /**
1315
   * Iterate over an array and execute a callback for each loop.
1316
   *
1317
   * @param \Closure $closure
1318
   *
1319
   * @return Arrayy
1320
   */
1321 2 View Code Duplication
  public function at(\Closure $closure)
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...
1322
  {
1323 2
    $array = $this->array;
1324
1325 2
    foreach ($array as $key => $value) {
1326 2
      $closure($value, $key);
1327 2
    }
1328
1329 2
    return static::create($array);
1330
  }
1331
1332
  /**
1333
   * Merge the new $array into the current array.
1334
   *
1335
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1336
   * - create new indexes
1337
   *
1338
   * @param array $array
1339
   * @param bool  $recursive
1340
   *
1341
   * @return Arrayy
1342
   */
1343 16 View Code Duplication
  public function mergeAppendNewIndex(array $array = array(), $recursive = 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...
1344
  {
1345 16
    if (true === $recursive) {
1346 4
      $result = array_merge_recursive($this->array, $array);
1347 4
    } else {
1348 12
      $result = array_merge($this->array, $array);
1349
    }
1350
1351 16
    return static::create($result);
1352
  }
1353
1354
  /**
1355
   * Merge the current array into the new $array.
1356
   *
1357
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1358
   * - create new indexes
1359
   *
1360
   * @param array $array
1361
   * @param bool  $recursive
1362
   *
1363
   * @return Arrayy
1364
   */
1365 16 View Code Duplication
  public function mergePrependNewIndex(array $array = array(), $recursive = 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...
1366
  {
1367 16
    if (true === $recursive) {
1368 4
      $result = array_merge_recursive($array, $this->array);
1369 4
    } else {
1370 12
      $result = array_merge($array, $this->array);
1371
    }
1372
1373 16
    return static::create($result);
1374
  }
1375
1376
  /**
1377
   * Merge the the current array into the $array.
1378
   *
1379
   * - use key,value from the new $array, also if the index is in the current array
1380
   *
1381
   * @param array $array
1382
   * @param bool  $recursive
1383
   *
1384
   * @return Arrayy
1385
   */
1386 16 View Code Duplication
  public function mergePrependKeepIndex(array $array = array(), $recursive = 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...
1387
  {
1388 16
    if (true === $recursive) {
1389 4
      $result = array_replace_recursive($array, $this->array);
1390 4
    } else {
1391 12
      $result = array_replace($array, $this->array);
1392
    }
1393
1394 16
    return static::create($result);
1395
  }
1396
1397
  /**
1398
   * Return values that are only in the current array.
1399
   *
1400
   * @param array $array
1401
   *
1402
   * @return Arrayy
1403
   */
1404 12
  public function diff(array $array = array())
1405
  {
1406 12
    $result = array_diff($this->array, $array);
1407
1408 12
    return static::create($result);
1409
  }
1410
1411
  /**
1412
   * Return values that are only in the new $array.
1413
   *
1414
   * @param array $array
1415
   *
1416
   * @return Arrayy
1417
   */
1418 8
  public function diffReverse(array $array = array())
1419
  {
1420 8
    $result = array_diff($array, $this->array);
1421
1422 8
    return static::create($result);
1423
  }
1424
1425
  /**
1426
   * Replace the first matched value in an array.
1427
   *
1428
   * @param mixed $search
1429
   * @param mixed $replacement
1430
   *
1431
   * @return Arrayy
1432
   */
1433 3
  public function replaceOneValue($search, $replacement = '')
1434
  {
1435 3
    $array = $this->array;
1436 3
    $key = array_search($search, $array, true);
1437
1438 3
    if ($key !== false) {
1439 3
      $array[$key] = $replacement;
1440 3
    }
1441
1442 3
    return static::create($array);
1443
  }
1444
1445
  /**
1446
   * Replace values in the current array.
1447
   *
1448
   * @param string $search      The string to replace.
1449
   * @param string $replacement What to replace it with.
1450
   *
1451
   * @return Arrayy
1452
   */
1453 1
  public function replaceValues($search, $replacement = '')
1454
  {
1455 1
    $array = $this->each(
1456
        function ($value) use ($search, $replacement) {
1457 1
          return UTF8::str_replace($search, $replacement, $value);
1458
        }
1459 1
    );
1460
1461 1
    return static::create($array);
0 ignored issues
show
Documentation introduced by
$array is of type object<Arrayy\Arrayy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1462
  }
1463
1464
  /**
1465
   * Replace the keys in an array with another set.
1466
   *
1467
   * @param array $keys An array of keys matching the array's size
1468
   *
1469
   * @return Arrayy
1470
   */
1471 1
  public function replaceKeys(array $keys)
1472
  {
1473 1
    $values = array_values($this->array);
1474 1
    $result = array_combine($keys, $values);
1475
1476 1
    return static::create($result);
1477
  }
1478
1479
  /**
1480
   * Create an array using the current array as keys and the other array as values.
1481
   *
1482
   * @param array $array Values array
1483
   *
1484
   * @return Arrayy Arrayy object with values from the other array.
1485
   */
1486 1
  public function replaceAllValues(array $array)
1487
  {
1488 1
    $result = array_combine($this->array, $array);
1489
1490 1
    return static::create($result);
1491
  }
1492
1493
  /**
1494
   * Create an array using the current array as values and the other array as keys.
1495
   *
1496
   * @param array $keys Keys array
1497
   *
1498
   * @return Arrayy Arrayy object with keys from the other array.
1499
   */
1500 1
  public function replaceAllKeys(array $keys)
1501
  {
1502 1
    $result = array_combine($keys, $this->array);
1503
1504 1
    return static::create($result);
1505
  }
1506
1507
  /**
1508
   * Shuffle the current array.
1509
   *
1510
   * @return Arrayy
1511
   */
1512 1
  public function shuffle()
1513
  {
1514 1
    $array = $this->array;
1515
1516 1
    shuffle($array);
1517
1518 1
    return static::create($array);
1519
  }
1520
1521
  /**
1522
   * Split an array in the given amount of pieces.
1523
   *
1524
   * @param int  $numberOfPieces
1525
   * @param bool $keepKeys
1526
   *
1527
   * @return array
1528
   */
1529 1
  public function split($numberOfPieces = 2, $keepKeys = false)
1530
  {
1531 1
    if (count($this->array) === 0) {
1532 1
      $result = array();
1533 1
    } else {
1534 1
      $numberOfPieces = (int)$numberOfPieces;
1535 1
      $splitSize = ceil(count($this->array) / $numberOfPieces);
1536 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
1537
    }
1538
1539 1
    return static::create($result);
1540
  }
1541
1542
  /**
1543
   * Create a chunked version of this array.
1544
   *
1545
   * @param int  $size         Size of each chunk
1546
   * @param bool $preserveKeys Whether array keys are preserved or no
1547
   *
1548
   * @return static A new array of chunks from the original array
1549
   */
1550 4
  public function chunk($size, $preserveKeys = false)
1551
  {
1552 4
    $result = array_chunk($this->array, $size, $preserveKeys);
1553
1554 4
    return static::create($result);
1555
  }
1556
1557
  /**
1558
   * Returns the values from a single column of the input array, identified by
1559
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1560
   *
1561
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1562
   * array by the values from the $indexKey column in the input array.
1563
   *
1564
   * @param mixed $columnKey
1565
   * @param mixed $indexKey
1566
   *
1567
   * @return Arrayy
1568
   */
1569 1
  public function getColumn($columnKey = null, $indexKey = null)
1570
  {
1571 1
    $result = array_column($this->array, $columnKey, $indexKey);
1572
1573 1
    return static::create($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by array_column($this->array, $columnKey, $indexKey) on line 1571 can also be of type false or null; however, Arrayy\Arrayy::create() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1574
  }
1575
1576
  /**
1577
   * Invoke a function on all of an array's values.
1578
   *
1579
   * @param mixed $callable
1580
   * @param array $arguments
1581
   *
1582
   * @return Arrayy
1583
   */
1584 1
  public function invoke($callable, $arguments = array())
1585
  {
1586
    // If one argument given for each iteration, create an array for it.
1587 1
    if (!is_array($arguments)) {
1588 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1589 1
    }
1590
1591
    // If the callable has arguments, pass them.
1592 1
    if ($arguments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arguments 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...
1593 1
      $array = array_map($callable, $this->array, $arguments);
1594 1
    } else {
1595 1
      $array = array_map($callable, $this->array);
1596
    }
1597
1598 1
    return static::create($array);
1599
  }
1600
1601
  /**
1602
   * Apply the given function to the every element of the array,
1603
   * collecting the results.
1604
   *
1605
   * @param callable $callable
1606
   *
1607
   * @return Arrayy Arrayy object with modified elements
1608
   */
1609 4
  public function map($callable)
1610
  {
1611 4
    $result = array_map($callable, $this->array);
1612
1613 4
    return static::create($result);
1614
  }
1615
1616
  /**
1617
   * Check if a value is in the current array using a closure.
1618
   *
1619
   * @param \Closure $closure
1620
   *
1621
   * @return bool Returns true if the given value is found, false otherwise
1622
   */
1623 4
  public function exists(\Closure $closure)
1624
  {
1625 4
    $isExists = false;
1626 4
    foreach ($this->array as $key => $value) {
1627 3
      if ($closure($value, $key)) {
1628 1
        $isExists = true;
1629 1
        break;
1630
      }
1631 4
    }
1632
1633 4
    return $isExists;
1634
  }
1635
1636
  /**
1637
   * Return all items that fail the truth test.
1638
   *
1639
   * @param \Closure $closure
1640
   *
1641
   * @return Arrayy
1642
   */
1643 1 View Code Duplication
  public function reject(\Closure $closure)
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...
1644
  {
1645 1
    $filtered = array();
1646
1647 1
    foreach ($this->array as $key => $value) {
1648 1
      if (!$closure($value, $key)) {
1649 1
        $filtered[$key] = $value;
1650 1
      }
1651 1
    }
1652
1653 1
    return static::create($filtered);
1654
  }
1655
1656
  /**
1657
   * Replace a key with a new key/value pair.
1658
   *
1659
   * @param $replace
1660
   * @param $key
1661
   * @param $value
1662
   *
1663
   * @return Arrayy
1664
   */
1665 1
  public function replace($replace, $key, $value)
1666
  {
1667 1
    $this->remove($replace);
1668
1669 1
    return $this->set($key, $value);
1670
  }
1671
1672
  /**
1673
   * Remove a value from the current array (optional using dot-notation).
1674
   *
1675
   * @param mixed $key
1676
   *
1677
   * @return Arrayy
1678
   */
1679 17
  public function remove($key)
1680
  {
1681
    // Recursive call
1682 17
    if (is_array($key)) {
1683
      foreach ($key as $k) {
1684
        $this->internalRemove($k);
1685
      }
1686
1687
      return static::create($this->array);
1688
    }
1689
1690 17
    $this->internalRemove($key);
1691
1692 17
    return static::create($this->array);
1693
  }
1694
1695
  /**
1696
   * Internal mechanics of remove method.
1697
   *
1698
   * @param $key
1699
   *
1700
   * @return boolean
1701
   */
1702 17
  protected function internalRemove($key)
1703
  {
1704
    // Explode keys
1705 17
    $keys = explode('.', $key);
1706
1707
    // Crawl though the keys
1708 17 View Code Duplication
    while (count($keys) > 1) {
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...
1709
      $key = array_shift($keys);
1710
1711
      if (!$this->has($key)) {
1712
        return false;
1713
      }
1714
1715
      $this->array = &$this->array[$key];
1716
    }
1717
1718 17
    $key = array_shift($keys);
1719
1720 17
    unset($this->array[$key]);
1721
1722 17
    return true;
1723
  }
1724
1725
  /**
1726
   * Check if an array has a given key.
1727
   *
1728
   * @param mixed $key
1729
   *
1730
   * @return bool
1731
   */
1732 18
  public function has($key)
1733
  {
1734
    // Generate unique string to use as marker.
1735 18
    $unFound = (string)uniqid('arrayy', true);
1736
1737 18
    return $this->get($key, $unFound) !== $unFound;
1738
  }
1739
1740
  /**
1741
   * Set a value for the current array (optional using dot-notation).
1742
   *
1743
   * @param string $key   The key to set
1744
   * @param mixed  $value Its value
1745
   *
1746
   * @return Arrayy
1747
   */
1748 14
  public function set($key, $value)
1749
  {
1750 14
    $this->internalSet($key, $value);
1751
1752 14
    return static::create($this->array);
1753
  }
1754
1755
  /**
1756
   * Internal mechanic of set method.
1757
   *
1758
   * @param mixed $key
1759
   * @param mixed $value
1760
   *
1761
   * @return bool
1762
   */
1763 14
  protected function internalSet($key, $value)
1764
  {
1765 14
    if (null === $key) {
1766
      return false;
1767
    }
1768
1769
    // Explode the keys
1770 14
    $keys = explode('.', $key);
1771
1772
    // Crawl through the keys
1773 14 View Code Duplication
    while (count($keys) > 1) {
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...
1774
      $key = array_shift($keys);
1775
1776
      $this->array[$key] = $this->get(array(), null, $key);
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1777
      $this->array = &$this->array[$key];
1778
    }
1779
1780
    // Bind final tree on the array
1781 14
    $key = array_shift($keys);
1782
1783 14
    $this->array[$key] = $value;
1784
1785 14
    return true;
1786
  }
1787
1788
  /**
1789
   * Get a value from a array and set it if it was not.
1790
   *
1791
   * WARNING: this method only set the value, if the $key is not already set
1792
   *
1793
   * @param string $key     The key
1794
   * @param mixed  $default The default value to set if it isn't
1795
   *
1796
   * @return mixed
1797
   */
1798 9
  public function setAndGet($key, $default = null)
1799
  {
1800
    // If the key doesn't exist, set it
1801 9
    if (!$this->has($key)) {
1802 4
      $this->array = $this->set($key, $default)->getArray();
1803 4
    }
1804
1805 9
    return $this->get($key);
1806
  }
1807
1808
  /**
1809
   * Remove the first value from the current array.
1810
   *
1811
   * @return Arrayy
1812
   */
1813 7
  public function removeFirst()
1814
  {
1815 7
    array_shift($this->array);
1816
1817 7
    return static::create($this->array);
1818
  }
1819
1820
  /**
1821
   * Remove the last value from the current array.
1822
   *
1823
   * @return Arrayy
1824
   */
1825 7
  public function removeLast()
1826
  {
1827 7
    array_pop($this->array);
1828
1829 7
    return static::create($this->array);
1830
  }
1831
1832
  /**
1833
   * Removes a particular value from an array (numeric or associative).
1834
   *
1835
   * @param mixed $value
1836
   *
1837
   * @return Arrayy
1838
   */
1839 7
  public function removeValue($value)
1840
  {
1841 7
    $isNumericArray = true;
1842 7
    foreach ($this->array as $key => $item) {
1843 6
      if ($item === $value) {
1844 6
        if (!is_int($key)) {
1845
          $isNumericArray = false;
1846
        }
1847 6
        unset($this->array[$key]);
1848 6
      }
1849 7
    }
1850
1851 7
    if ($isNumericArray) {
1852 7
      $this->array = array_values($this->array);
1853 7
    }
1854
1855 7
    return static::create($this->array);
1856
  }
1857
1858
  /**
1859
   * Pad array to the specified size with a given value.
1860
   *
1861
   * @param int   $size  Size of the result array
1862
   * @param mixed $value Empty value by default
1863
   *
1864
   * @return Arrayy Arrayy object padded to $size with $value
1865
   */
1866 4
  public function pad($size, $value)
1867
  {
1868 4
    $result = array_pad($this->array, $size, $value);
1869
1870 4
    return static::create($result);
1871
  }
1872
1873
  /**
1874
   * Prepend a value to an array.
1875
   *
1876
   * @param mixed $value
1877
   *
1878
   * @return Arrayy
1879
   */
1880 7
  public function prepend($value)
1881
  {
1882 7
    array_unshift($this->array, $value);
1883
1884 7
    return static::create($this->array);
1885
  }
1886
1887
  /**
1888
   * alias: for "Arrayy->append()"
1889
   *
1890
   * @param $value
1891
   *
1892
   * @return $this
1893
   */
1894 1
  public function add($value)
1895
  {
1896 1
    $this->array[] = $value;
1897
1898 1
    return $this;
1899
  }
1900
1901
  /**
1902
   * Create a numerically re-indexed Arrayy object.
1903
   *
1904
   * @return Arrayy The new instance with re-indexed array-elements
1905
   */
1906 8
  public function reindex()
1907
  {
1908 8
    $this->array = array_values($this->array);
1909
1910 8
    return static::create($this->array);
1911
  }
1912
1913
  /**
1914
   * Return the array in the reverse order.
1915
   *
1916
   * @return Arrayy
1917
   */
1918 7
  public function reverse()
1919
  {
1920 7
    $this->array = array_reverse($this->array);
1921
1922 7
    return static::create($this->array);
1923
  }
1924
1925
  /**
1926
   * Custom sort by value via "usort"
1927
   *
1928
   * @link http://php.net/manual/en/function.usort.php
1929
   *
1930
   * @param callable $func
1931
   *
1932
   * @return $this
1933
   */
1934 4
  public function customSortValues($func)
1935
  {
1936 4
    usort($this->array, $func);
1937
1938 4
    return $this;
1939
  }
1940
1941
  /**
1942
   * Custom sort by index via "uksort"
1943
   *
1944
   * @link http://php.net/manual/en/function.uksort.php
1945
   *
1946
   * @param callable $func
1947
   *
1948
   * @return $this
1949
   */
1950 4
  public function customSortKeys($func)
1951
  {
1952 4
    uksort($this->array, $func);
1953
1954 4
    return $this;
1955
  }
1956
1957
  /**
1958
   * Sort the current array by key.
1959
   *
1960
   * @link http://php.net/manual/en/function.ksort.php
1961
   * @link http://php.net/manual/en/function.krsort.php
1962
   *
1963
   * @param int|string $direction use SORT_ASC or SORT_DESC
1964
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
1965
   *
1966
   * @return $this
1967
   */
1968 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
1969
  {
1970 18
    $this->sorterKeys($this->array, $direction, $strategy);
1971
1972 18
    return $this;
1973
  }
1974
1975
  /**
1976
   * sorting keys
1977
   *
1978
   * @param array $elements
1979
   * @param int   $direction
1980
   * @param int   $strategy
1981
   */
1982 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
1983
  {
1984 18
    $direction = $this->getDirection($direction);
1985
1986
    switch ($direction) {
1987 18
      case 'desc':
1988 18
      case SORT_DESC:
1989 6
        krsort($elements, $strategy);
1990 6
        break;
1991 13
      case 'asc':
1992 13
      case SORT_ASC:
1993 13
      default:
1994 13
        ksort($elements, $strategy);
1995 13
    }
1996 18
  }
1997
1998
  /**
1999
   * Get correct PHP constant for direction.
2000
   *
2001
   * @param int|string $direction
2002
   *
2003
   * @return int
2004
   */
2005 38
  protected function getDirection($direction)
2006
  {
2007 38
    if (is_string($direction)) {
2008 10
      $direction = strtolower($direction);
2009
2010 10
      if ($direction === 'desc') {
2011 2
        $direction = SORT_DESC;
2012 2
      } else {
2013 8
        $direction = SORT_ASC;
2014
      }
2015 10
    }
2016
2017
    if (
2018
        $direction !== SORT_DESC
2019 38
        &&
2020
        $direction !== SORT_ASC
2021 38
    ) {
2022
      $direction = SORT_ASC;
2023
    }
2024
2025 38
    return $direction;
2026
  }
2027
2028
  /**
2029
   * Sort the current array by value.
2030
   *
2031
   * @param int $direction use SORT_ASC or SORT_DESC
2032
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2033
   *
2034
   * @return Arrayy
2035
   */
2036 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2037
  {
2038 1
    return $this->sort($direction, $strategy, true);
2039
  }
2040
2041
  /**
2042
   * Sort the current array and optional you can keep the keys.
2043
   *
2044
   * @param string|int $direction use SORT_ASC or SORT_DESC
2045
   * @param int|string $strategy
2046
   * @param bool       $keepKeys
2047
   *
2048
   * @return Arrayy
2049
   */
2050 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2051
  {
2052 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2053
2054 19
    return $this;
2055
  }
2056
2057
  /**
2058
   * @param array      &$elements
2059
   * @param int|string $direction
2060
   * @param int        $strategy
2061
   * @param bool       $keepKeys
2062
   */
2063 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2064
  {
2065 19
    $direction = $this->getDirection($direction);
2066
2067 19
    if (!$strategy) {
2068 19
      $strategy = SORT_REGULAR;
2069 19
    }
2070
2071
    switch ($direction) {
2072 19
      case 'desc':
2073 19
      case SORT_DESC:
2074 9
        if ($keepKeys) {
2075 5
          arsort($elements, $strategy);
2076 5
        } else {
2077 4
          rsort($elements, $strategy);
2078
        }
2079 9
        break;
2080 10
      case 'asc':
2081 10
      case SORT_ASC:
2082 10
      default:
2083 10
        if ($keepKeys) {
2084 4
          asort($elements, $strategy);
2085 4
        } else {
2086 6
          sort($elements, $strategy);
2087
        }
2088 10
    }
2089 19
  }
2090
2091
  /**
2092
   * Sort the current array by value.
2093
   *
2094
   * @param int $direction use SORT_ASC or SORT_DESC
2095
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2096
   *
2097
   * @return Arrayy
2098
   */
2099 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2100
  {
2101 1
    return $this->sort($direction, $strategy, false);
2102
  }
2103
2104
  /**
2105
   * Sort a array by value, by a closure or by a property.
2106
   *
2107
   * - If the sorter is null, the array is sorted naturally.
2108
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2109
   *
2110
   * @param null       $sorter
2111
   * @param string|int $direction
2112
   * @param int        $strategy
2113
   *
2114
   * @return Arrayy
2115
   */
2116 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2117
  {
2118 1
    $array = (array)$this->array;
2119 1
    $direction = $this->getDirection($direction);
2120
2121
    // Transform all values into their results.
2122 1
    if ($sorter) {
2123 1
      $arrayy = new self($array);
2124
2125 1
      $that = $this;
2126 1
      $results = $arrayy->each(
2127
          function ($value) use ($sorter, $that) {
2128 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2129
          }
2130 1
      );
2131
2132 1
      $results = $results->getArray();
2133 1
    } else {
2134 1
      $results = $array;
2135
    }
2136
2137
    // Sort by the results and replace by original values
2138 1
    array_multisort($results, $direction, $strategy, $array);
2139
2140 1
    return static::create($array);
2141
  }
2142
2143
  /**
2144
   * Exchanges all keys with their associated values in an array.
2145
   *
2146
   * @return Arrayy
2147
   */
2148 1
  public function flip()
2149
  {
2150 1
    $this->array = array_flip($this->array);
2151
2152 1
    return static::create($this->array);
2153
  }
2154
2155
  /**
2156
   * Apply the given function to every element in the array,
2157
   * discarding the results.
2158
   *
2159
   * @param callable $callable
2160
   * @param bool     $recursive Whether array will be walked recursively or no
2161
   *
2162
   * @return Arrayy An Arrayy object with modified elements
2163
   */
2164 8
  public function walk($callable, $recursive = false)
2165
  {
2166 8
    if (true === $recursive) {
2167 4
      array_walk_recursive($this->array, $callable);
2168 4
    } else {
2169 4
      array_walk($this->array, $callable);
2170
    }
2171
2172 8
    return $this;
2173
  }
2174
2175
  /**
2176
   * Reduce the current array via callable e.g. anonymous-function.
2177
   *
2178
   * @param mixed $callable
2179
   * @param array $init
2180
   *
2181
   * @return Arrayy
2182
   */
2183 2
  public function reduce($callable, array $init = array())
2184
  {
2185 2
    $this->array = array_reduce($this->array, $callable, $init);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce($this->array, $callable, $init) of type * is incompatible with the declared type array of property $array.

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...
2186
2187 2
    return static::create($this->array);
2188
  }
2189
2190
  /**
2191
   * Return a duplicate free copy of the current array.
2192
   *
2193
   * @return Arrayy
2194
   */
2195 7
  public function unique()
2196
  {
2197 7
    $this->array = array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce($this->arra...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

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...
2198 7
        $this->array,
2199 7
        function ($resultArray, $value) {
2200 6
          if (in_array($value, $resultArray, true) === false) {
2201 6
            $resultArray[] = $value;
2202 6
          }
2203
2204 6
          return $resultArray;
2205 7
        },
2206 7
        array()
2207 7
    );
2208
2209 7
    return static::create($this->array);
2210
  }
2211
2212
  /**
2213
   * Convert the current array to JSON.
2214
   *
2215
   * @param null $options e.g. JSON_PRETTY_PRINT
2216
   *
2217
   * @return string
2218
   */
2219 5
  public function toJson($options = null)
2220
  {
2221 5
    return UTF8::json_encode($this->array, $options);
2222
  }
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
}
2242