Completed
Push — master ( 1b0693...30a120 )
by Lars
03:05
created

Arrayy::shuffle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 8
ccs 0
cts 0
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Arrayy;
4
5
use voku\helper\UTF8;
6
7
/**
8
 * Methods to manage arrays.
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
class Arrayy extends \ArrayObject implements \ArrayAccess, \Serializable, \Countable
14
{
15
  /**
16
   * @var array
17
   */
18
  protected $array = array();
19
20
  /**
21
   * @var string
22
   */
23
  protected $pathSeparator = '.';
24
25
  /** @noinspection MagicMethodsValidityInspection */
26
  /**
27
   * Initializes
28
   *
29
   * @param array $array
30
   */
31 758
  public function __construct($array = array())
32
  {
33 758
    $array = $this->fallbackForArray($array);
34
35 756
    $this->array = $array;
36 756
  }
37
38
  /**
39
   * Get a value by key.
40
   *
41
   * @param $key
42
   *
43
   * @return mixed <p>Get a Value from the current array.</p>
44
   */
45 1
  public function __get($key)
46
  {
47 1
    $return = $this->get($key);
48
49 1
    if (is_array($return)) {
50
      return static::create($return);
51
    }
52
53 1
    return $return;
54
  }
55
56
  /**
57
   * Call object as function.
58
   *
59
   * @param mixed $key
60
   *
61
   * @return mixed
62
   */
63
  public function __invoke($key = null)
64
  {
65
    if ($key !== null) {
66
      if (isset($this->array[$key])) {
67
        return $this->array[$key];
68
      }
69
70
      return false;
71
    }
72
73
    return (array)$this->array;
74
  }
75
76
  /**
77
   * Whether or not an element exists by key.
78
   *
79
   * @param mixed $key
80
   *
81
   * @return bool <p>True is the key/index exists, otherwise false.</p>
82
   */
83
  public function __isset($key)
84
  {
85
    return $this->offsetExists($key);
86
  }
87
88
  /**
89
   * Assigns a value to the specified element.
90
   *
91
   * @param mixed $key
92
   * @param mixed $value
93
   */
94 2
  public function __set($key, $value)
95
  {
96 2
    $this->internalSet($key, $value);
97 2
  }
98
99
  /**
100
   * magic to string
101
   *
102
   * @return string
103
   */
104 16
  public function __toString()
105
  {
106 16
    return $this->toString();
107
  }
108
109
  /**
110
   * Unset element by key.
111
   *
112
   * @param mixed $key
113
   */
114
  public function __unset($key)
115
  {
116
    unset($this->array[$key]);
117
  }
118
119
  /**
120
   * alias: for "Arrayy->append()"
121
   *
122
   * @see Arrayy::append()
123
   *
124
   * @param mixed $value
125
   *
126
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
127
   */
128 1
  public function add($value)
129
  {
130 1
    return $this->append($value);
131
  }
132
133
  /**
134
   * Append a value to the current array.
135
   *
136
   * @param mixed $value
137
   *
138
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
139
   */
140 9
  public function append($value)
141
  {
142 9
    $this->array[] = $value;
143
144 9
    return $this;
145
  }
146
147
  /**
148
   * Count the values from the current array.
149
   *
150
   * alias: for "Arrayy->size()"
151
   *
152
   * @see Arrayy::size()
153
   *
154
   * @return int
155
   */
156 93
  public function count()
157
  {
158 93
    return $this->size();
159
  }
160
161
  /**
162
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
163
   *
164
   * @return ArrayyIterator <p>An iterator for the values in the array.</p>
165
   */
166 19
  public function getIterator()
167
  {
168 19
    return new ArrayyIterator($this->array);
169
  }
170
171
  /**
172
   * Whether or not an offset exists.
173
   *
174
   * @param int|float|string $offset
175
   *
176
   * @return bool
177
   */
178 38
  public function offsetExists($offset)
179
  {
180 38
    if ($this->isEmpty()) {
181 4
      return false;
182
    }
183
184
    // php cast "bool"-index into "int"-index
185 34
    if ((bool)$offset === $offset) {
186 1
      $offset = (int)$offset;
187 1
    }
188
189 34
    $tmpReturn = \array_key_exists($offset, $this->array);
190
191
    if (
192
        $tmpReturn === true
193 34
        ||
194
        (
195
            $tmpReturn === false
196 11
            &&
197 11
            strpos((string)$offset, $this->pathSeparator) === false
198 11
        )
199 34
    ) {
200 32
      return $tmpReturn;
201
    }
202
203 2
    $offsetExists = false;
204
205 2
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
206
207 2
      $offsetExists = false;
208 2
      $explodedPath = explode($this->pathSeparator, (string)$offset);
209 2
      $lastOffset = \array_pop($explodedPath);
210 2
      $containerPath = implode($this->pathSeparator, $explodedPath);
211
212 2
      $this->callAtPath(
213 2
          $containerPath,
214
          function ($container) use ($lastOffset, &$offsetExists) {
215 2
            $offsetExists = \array_key_exists($lastOffset, $container);
216 2
          }
217 2
      );
218 2
    }
219
220 2
    return $offsetExists;
221
  }
222
223
  /**
224
   * Returns the value at specified offset.
225
   *
226
   * @param mixed $offset
227
   *
228
   * @return mixed <p>Will return null if the offset did not exists.</p>
229
   */
230 24
  public function offsetGet($offset)
231
  {
232 24
    return $this->offsetExists($offset) ? $this->get($offset) : null;
233
  }
234
235
  /**
236
   * Assigns a value to the specified offset.
237
   *
238
   * @param mixed $offset
239
   * @param mixed $value
240
   */
241 15
  public function offsetSet($offset, $value)
242
  {
243 15
    if ($offset === null) {
244 4
      $this->array[] = $value;
245 4
    } else {
246 11
      $this->internalSet($offset, $value);
247
    }
248 15
  }
249
250
  /**
251
   * Unset an offset.
252
   *
253
   * @param mixed $offset
254
   */
255 6
  public function offsetUnset($offset)
256
  {
257 6
    if ($this->isEmpty()) {
258 1
      return;
259
    }
260
261 5
    if (\array_key_exists($offset, $this->array)) {
262 3
      unset($this->array[$offset]);
263
264 3
      return;
265
    }
266
267 2
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
268
269 1
      $path = explode($this->pathSeparator, (string)$offset);
270 1
      $pathToUnset = \array_pop($path);
271
272 1
      $this->callAtPath(
273 1
          implode($this->pathSeparator, $path),
274
          function (&$offset) use ($pathToUnset) {
275 1
            unset($offset[$pathToUnset]);
276 1
          }
277 1
      );
278
279 1
    }
280 2
  }
281
282
  /**
283
   * Serialize the current array.
284
   *
285
   * @return string
286
   */
287 2
  public function serialize()
288
  {
289 2
    return serialize($this->array);
290
  }
291
292
  /**
293
   * Unserialize an string and return this object.
294
   *
295
   * @param string $string
296
   *
297
   * @return static <p>(Mutable)</p>
298
   */
299 2
  public function unserialize($string)
300
  {
301 2
    $this->array = unserialize($string);
302
303 2
    return $this;
304
  }
305
306
  /**
307
   * Iterate over the current array and execute a callback for each loop.
308
   *
309
   * @param \Closure $closure
310
   *
311
   * @return static <p>(Immutable)</p>
312
   */
313 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...
314
  {
315 2
    $array = $this->array;
316
317 2
    foreach ($array as $key => $value) {
318 2
      $closure($value, $key);
319 2
    }
320
321 2
    return static::create($array);
322
  }
323
324
  /**
325
   * Returns the average value of the current array.
326
   *
327
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
328
   *
329
   * @return int|double <p>The average value.</p>
330
   */
331 10
  public function average($decimals = 0)
332
  {
333 10
    $count = $this->count();
334
335 10
    if (!$count) {
336 2
      return 0;
337
    }
338
339 8
    if (!is_int($decimals)) {
340 3
      $decimals = 0;
341 3
    }
342
343 8
    return round(\array_sum($this->array) / $count, $decimals);
344
  }
345
346
  /**
347
   * @param mixed      $path
348
   * @param callable   $callable
349
   * @param null|array $currentOffset
350
   */
351 2
  protected function callAtPath($path, $callable, &$currentOffset = null)
352
  {
353 2
    if ($currentOffset === null) {
354 2
      $currentOffset = &$this->array;
355 2
    }
356
357 2
    $explodedPath = explode($this->pathSeparator, $path);
358 2
    $nextPath = \array_shift($explodedPath);
359
360 2
    if (!isset($currentOffset[$nextPath])) {
361
      return;
362
    }
363
364 2
    if (!empty($explodedPath)) {
365
      $this->callAtPath(
366
          implode($this->pathSeparator, $explodedPath),
367
          $callable,
368
          $currentOffset[$nextPath]
369
      );
370
    } else {
371 2
      $callable($currentOffset[$nextPath]);
372
    }
373 2
  }
374
375
  /**
376
   * Change the path separator of the array wrapper.
377
   *
378
   * By default, the separator is: "."
379
   *
380
   * @param string $separator <p>Separator to set.</p>
381
   *
382
   * @return static <p>Mutable</p>
383
   */
384
  public function changeSeparator($separator)
385
  {
386
    $this->pathSeparator = $separator;
387
388
    return $this;
389
  }
390
391
  /**
392
   * Create a chunked version of the current array.
393
   *
394
   * @param int  $size         <p>Size of each chunk.</p>
395
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
396
   *
397
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
398
   */
399 4
  public function chunk($size, $preserveKeys = false)
400
  {
401 4
    $result = \array_chunk($this->array, $size, $preserveKeys);
402
403 4
    return static::create($result);
404
  }
405
406
  /**
407
   * Clean all falsy values from the current array.
408
   *
409
   * @return static <p>(Immutable)</p>
410
   */
411 8
  public function clean()
412
  {
413 8
    return $this->filter(
414
        function ($value) {
415 7
          return (bool)$value;
416
        }
417 8
    );
418
  }
419
420
  /**
421
   * WARNING!!! -> Clear the current array.
422
   *
423
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
424
   */
425 4
  public function clear()
426
  {
427 4
    $this->array = array();
428
429 4
    return $this;
430
  }
431
432
  /**
433
   * Check if an item is in the current array.
434
   *
435
   * @param string|int|float $value
436
   *
437
   * @return bool
438
   */
439 13
  public function contains($value)
440
  {
441 13
    return in_array($value, $this->array, true);
442
  }
443
444
  /**
445
   * Check if an (case-insensitive) string is in the current array.
446
   *
447
   * @param string $value
448
   *
449
   * @return bool
450
   */
451 13
  public function containsCaseInsensitive($value)
452
  {
453 13
    return in_array(
454 13
        UTF8::strtolower($value),
455 13
        \array_map(
456
            array(
457 13
                new UTF8(),
458 13
                'strtolower',
459 13
            ),
460 13
            $this->array
461 13
        ),
462
        true
463 13
    );
464
  }
465
466
  /**
467
   * Check if the given key/index exists in the array.
468
   *
469
   * @param string|int|float $key <p>key/index to search for</p>
470
   *
471
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
472
   */
473 4
  public function containsKey($key)
474
  {
475 4
    return $this->offsetExists($key);
476
  }
477
478
  /**
479
   * Check if all given needles are present in the array as key/index.
480
   *
481
   * @param array $needles
482
   *
483
   * @return bool <p>Returns true if the given keys/indexes exists in the array, false otherwise.</p>
484
   */
485 1
  public function containsKeys(array $needles)
486
  {
487 1
    return count(\array_intersect($needles, $this->keys()->getArray())) === count($needles);
488
  }
489
490
  /**
491
   * alias: for "Arrayy->contains()"
492
   *
493
   * @see Arrayy::contains()
494
   *
495
   * @param string|int|float $value
496
   *
497
   * @return bool
498
   */
499
  public function containsValue($value)
500
  {
501
    return $this->contains($value);
502
  }
503
504
  /**
505
   * Check if all given needles are present in the array.
506
   *
507
   * @param array $needles
508
   *
509
   * @return bool <p>Returns true if the given values exists in the array, false otherwise.</p>
510
   */
511 1
  public function containsValues(array $needles)
512
  {
513 1
    return count(\array_intersect($needles, $this->array)) === count($needles);
514
  }
515
516
  /**
517
   * Creates an Arrayy object.
518
   *
519
   * @param array $array
520
   *
521
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
522
   */
523 478
  public static function create($array = array())
524
  {
525 478
    return new static($array);
526
  }
527
528
  /**
529
   * Generate array of repeated arrays.
530
   *
531
   * @param int $times <p>How many times has to be repeated.</p>
532
   *
533
   * @return Arrayy
534
   */
535
  public function repeat($times)
536
  {
537
    if ($times === 0) {
538
      return new static();
539
    }
540
541
    return static::create(\array_fill(0, (int)$times, $this->array));
542
  }
543
544
545
  /**
546
   * WARNING: Creates an Arrayy object by reference.
547
   *
548
   * @param array $array
549
   *
550
   * @return static <p>(Mutable) Return this Arrayy object.</p>
551 5
   */
552
  public function createByReference(&$array = array())
553 5
  {
554
    $array = $this->fallbackForArray($array);
555 5
556
    $this->array = &$array;
557
558
    return $this;
559
  }
560
561
  /**
562
   * Create an new Arrayy object via JSON.
563
   *
564
   * @param string $json
565 4
   *
566
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
567 4
   */
568 4
  public static function createFromJson($json)
569
  {
570 3
    $array = UTF8::json_decode($json, true);
571 4
572
    return static::create($array);
573 4
  }
574
575
  /**
576
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
577
   *
578
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
579
   *
580
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
581
   */
582
  public static function createFromObject(\ArrayAccess $object)
583
  {
584
    $array = new static();
585
    foreach ($object as $key => $value) {
586 8
      /** @noinspection OffsetOperationsInspection */
587
      $array[$key] = $value;
588 8
    }
589 1
590
    return $array;
591 1
  }
592 1
593 1
  /**
594
   * Create an new Arrayy object via string.
595 1
   *
596 7
   * @param string      $str       <p>The input string.</p>
597
   * @param string|null $delimiter <p>The boundary string.</p>
598
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
599
   *                               used.</p>
600 8
   *
601 8
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
602
   */
603
  public static function createFromString($str, $delimiter, $regEx = null)
604 8
  {
605 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...
606 8
      preg_match_all($regEx, $str, $array);
607 8
608 8
      if (!empty($array)) {
609
        $array = $array[0];
610 8
      }
611
612
    } else {
613
      $array = explode($delimiter, $str);
614
    }
615
616
    // trim all string in the array
617
    \array_walk(
618
        $array,
619
        function (&$val) {
620
          /** @noinspection ReferenceMismatchInspection */
621
          if (is_string($val)) {
622 1
            $val = trim($val);
623
          }
624 1
        }
625
    );
626
627
    return static::create($array);
628
  }
629
630
  /**
631
   * Create an new instance containing a range of elements.
632
   *
633
   * @param mixed $low  <p>First value of the sequence.</p>
634
   * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
635
   * @param int   $step <p>Used as the increment between elements in the sequence.</p>
636 5
   *
637
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
638 5
   */
639
  public static function createWithRange($low, $high, $step = 1)
640 5
  {
641
    return static::create(range($low, $high, $step));
642
  }
643
644
  /**
645
   * Custom sort by index via "uksort".
646
   *
647
   * @link http://php.net/manual/en/function.uksort.php
648
   *
649
   * @param callable $function
650
   *
651
   * @return static <p>(Mutable) Return this Arrayy object.</p>
652 4
   */
653
  public function customSortKeys($function)
654 4
  {
655
    uksort($this->array, $function);
656 4
657
    return $this;
658
  }
659
660
  /**
661
   * Custom sort by value via "usort".
662
   *
663
   * @link http://php.net/manual/en/function.usort.php
664
   *
665
   * @param callable $function
666 12
   *
667
   * @return static <p>(Mutable) Return this Arrayy object.</p>
668 12
   */
669
  public function customSortValues($function)
670 12
  {
671
    usort($this->array, $function);
672
673
    return $this;
674
  }
675
676
  /**
677
   * Return values that are only in the current array.
678
   *
679
   * @param array $array
680
   *
681 1
   * @return static <p>(Immutable)</p>
682
   */
683 1
  public function diff(array $array = array())
684
  {
685
    $result = \array_diff($this->array, $array);
686
687 1
    return static::create($result);
688 1
  }
689 1
690 1
  /**
691 1
   * Return values that are only in the current multi-dimensional array.
692 1
   *
693
   * @param array      $array
694
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
695 1
   *
696 1
   * @return static <p>(Immutable)</p>
697 1
   */
698 1
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
699 1
  {
700 1
    $result = array();
701 1
702 1
    if (
703 1
        $helperVariableForRecursion !== null
704 1
        &&
705 1
        is_array($helperVariableForRecursion)
706
    ) {
707 1
      $arrayForTheLoop = $helperVariableForRecursion;
708 1
    } else {
709
      $arrayForTheLoop = $this->array;
710 1
    }
711
712 1
    foreach ($arrayForTheLoop as $key => $value) {
713
      if (\array_key_exists($key, $array)) {
714
        if (is_array($value)) {
715
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
716
          if (!empty($recursiveDiff)) {
717
            $result[$key] = $recursiveDiff;
718
          }
719
        } else {
720
          if ($value != $array[$key]) {
721
            $result[$key] = $value;
722 8
          }
723
        }
724 8
      } else {
725
        $result[$key] = $value;
726 8
      }
727
    }
728
729
    return static::create($result);
730
  }
731
732
  /**
733
   * Return values that are only in the new $array.
734 1
   *
735
   * @param array $array
736 1
   *
737
   * @return static <p>(Immutable)</p>
738 1
   */
739 1
  public function diffReverse(array $array = array())
740
  {
741 1
    $result = \array_diff($array, $this->array);
742
743
    return static::create($result);
744
  }
745
746
  /**
747
   * Divide an array into two arrays. One with keys and the other with values.
748
   *
749
   * @return static <p>(Immutable)</p>
750
   */
751 4
  public function divide()
752
  {
753 4
    return static::create(
754
        array(
755 4
            $this->keys(),
756 4
            $this->values(),
757 4
        )
758
    );
759 4
  }
760
761
  /**
762
   * Iterate over the current array and modify the array's value.
763
   *
764
   * @param \Closure $closure
765
   *
766
   * @return static <p>(Immutable)</p>
767
   */
768 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...
769 4
  {
770
    $array = $this->array;
771 4
772 4
    foreach ($array as $key => $value) {
773 3
      $array[$key] = $closure($value, $key);
774 1
    }
775 1
776
    return static::create($array);
777 4
  }
778
779 4
  /**
780
   * Check if a value is in the current array using a closure.
781
   *
782
   * @param \Closure $closure
783
   *
784
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
785
   */
786
  public function exists(\Closure $closure)
787
  {
788
    $isExists = false;
789
    foreach ($this->array as $key => $value) {
790
      if ($closure($value, $key)) {
791
        $isExists = true;
792
        break;
793
      }
794
    }
795
796
    return $isExists;
797
  }
798
799 758
  /**
800
   * create a fallback for array
801 758
   *
802 755
   * 1. use the current array, if it's a array
803
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
804
   * 3. fallback to empty array, if there is nothing
805 10
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
806 1
   * 5. call "__toArray()" on object, if the method exists
807
   * 6. cast a string or object with "__toString()" into an array
808
   * 7. throw a "InvalidArgumentException"-Exception
809 9
   *
810 6
   * @param $array
811
   *
812
   * @return array
813 8
   *
814
   * @throws \InvalidArgumentException
815
   */
816
  protected function fallbackForArray(&$array)
817
  {
818 8
    if (is_array($array)) {
819
      return $array;
820
    }
821
822
    if ($array instanceof self) {
823
      return $array->getArray();
824 8
    }
825
826 2
    if (!$array) {
827 8
      return array();
828 6
    }
829
830
    if ($array instanceof \ArrayAccess) {
831 2
      /** @noinspection ReferenceMismatchInspection */
832
      return static::createFromObject($array)->getArray();
833 2
    }
834
835
    if (is_object($array) && method_exists($array, '__toArray')) {
836
      return (array)$array->__toArray();
837
    }
838
839
    /** @noinspection ReferenceMismatchInspection */
840
    if (
841
        is_string($array)
842
        ||
843 9
        (is_object($array) && method_exists($array, '__toString'))
844
    ) {
845 9
      return array((string)$array);
846 1
    }
847
848
    throw new \InvalidArgumentException(
849 9
        'Passed value should be a array'
850
    );
851 9
  }
852
853
  /**
854
   * Find all items in an array that pass the truth test.
855
   *
856
   * @param \Closure|null $closure
857
   *
858
   * @return static <p>(Immutable)</p>
859
   */
860
  public function filter($closure = null)
861
  {
862
    if (!$closure) {
863
      return $this->clean();
864
    }
865
866
    $array = \array_filter($this->array, $closure);
867
868
    return static::create($array);
869
  }
870
871
  /**
872
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
873
   * within that.
874
   *
875
   * @param string $property
876 1
   * @param string $value
877
   * @param string $comparisonOp
878 1
   *                            <p>
879 1
   *                            'eq' (equals),<br />
880 1
   *                            'gt' (greater),<br />
881
   *                            'gte' || 'ge' (greater or equals),<br />
882
   *                            'lt' (less),<br />
883
   *                            'lte' || 'le' (less or equals),<br />
884 1
   *                            'ne' (not equals),<br />
885 1
   *                            'contains',<br />
886
   *                            'notContains',<br />
887
   *                            'newer' (via strtotime),<br />
888 1
   *                            'older' (via strtotime),<br />
889
   *                            </p>
890
   *
891 1
   * @return static <p>(Immutable)</p>
892
   */
893
  public function filterBy($property, $value, $comparisonOp = null)
894 1
  {
895
    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...
896 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
897 1
    }
898
899
    $ops = array(
900 1
        'eq'          => function ($item, $prop, $value) {
901
          return $item[$prop] === $value;
902
        },
903 1
        'gt'          => function ($item, $prop, $value) {
904
          return $item[$prop] > $value;
905
        },
906 1
        'ge'          => function ($item, $prop, $value) {
907
          return $item[$prop] >= $value;
908 1
        },
909 1
        'gte'         => function ($item, $prop, $value) {
910
          return $item[$prop] >= $value;
911
        },
912 1
        'lt'          => function ($item, $prop, $value) {
913
          return $item[$prop] < $value;
914
        },
915 1
        'le'          => function ($item, $prop, $value) {
916
          return $item[$prop] <= $value;
917
        },
918 1
        'lte'         => function ($item, $prop, $value) {
919 1
          return $item[$prop] <= $value;
920
        },
921 1
        'ne'          => function ($item, $prop, $value) {
922 1
          return $item[$prop] !== $value;
923 1
        },
924
        'contains'    => function ($item, $prop, $value) {
925 1
          return in_array($item[$prop], (array)$value, true);
926 1
        },
927 1
        'notContains' => function ($item, $prop, $value) {
928 1
          return !in_array($item[$prop], (array)$value, true);
929
        },
930 1
        'newer'       => function ($item, $prop, $value) {
931 1
          return strtotime($item[$prop]) > strtotime($value);
932 1
        },
933
        'older'       => function ($item, $prop, $value) {
934 1
          return strtotime($item[$prop]) < strtotime($value);
935
        },
936 1
    );
937 1
938
    $result = \array_values(
939 1
        \array_filter(
940
            (array)$this->array,
941
            function ($item) use (
942
                $property,
943
                $value,
944
                $ops,
945
                $comparisonOp
946
            ) {
947
              $item = (array)$item;
948
              $itemArrayy = new Arrayy($item);
949
              $item[$property] = $itemArrayy->get($property, array());
950 8
951
              return $ops[$comparisonOp]($item, $property, $value);
952 8
            }
953 6
        )
954 5
    );
955
956 5
    return static::create($result);
957
  }
958 3
959
  /**
960
   * Find the first item in an array that passes the truth test,
961
   *  otherwise return false
962
   *
963
   * @param \Closure $closure
964
   *
965
   * @return mixed|false <p>Return false if we did not find the value.</p>
966
   */
967
  public function find(\Closure $closure)
968
  {
969
    foreach ($this->array as $key => $value) {
970
      if ($closure($value, $key)) {
971
        return $value;
972
      }
973
    }
974
975
    return false;
976
  }
977
978
  /**
979
   * find by ...
980 13
   *
981
   * @param string $property
982 13
   * @param string $value
983 13
   * @param string $comparisonOp
984
   *
985 13
   * @return static <p>(Immutable)</p>
986 3
   */
987
  public function findBy($property, $value, $comparisonOp = 'eq')
988
  {
989 10
    return $this->filterBy($property, $value, $comparisonOp);
990
  }
991
992
  /**
993
   * Get the first value from the current array.
994
   *
995
   * @return mixed <p>Return null if there wasn't a element.</p>
996
   */
997
  public function first()
998
  {
999 28
    $tmpArray = $this->array;
1000
    $result = \array_shift($tmpArray);
1001 28
1002 7
    if ($result === null) {
1003 7
      return null;
1004 7
    }
1005 21
1006 21
    return $result;
1007 21
  }
1008
1009
  /**
1010 28
   * Get the first value(s) from the current array.
1011
   *
1012
   * @param int|null $number <p>How many values you will take?</p>
1013
   *
1014
   * @return static <p>(Immutable)</p>
1015
   */
1016
  public function firstsImmutable($number = null)
1017
  {
1018
    if ($number === null) {
1019
      $arrayTmp = $this->array;
1020 26
      $array = (array)\array_shift($arrayTmp);
1021
    } else {
1022 26
      $number = (int)$number;
1023 11
      $arrayTmp = $this->array;
1024 11
      $array = \array_splice($arrayTmp, 0, $number, true);
1025 15
    }
1026 15
1027
    return static::create($array);
1028
  }
1029 26
1030
  /**
1031
   * Get the first value(s) from the current array.
1032
   *
1033
   * @param int|null $number <p>How many values you will take?</p>
1034
   *
1035
   * @return static <p>(Mutable)</p>
1036
   */
1037 1
  public function firstsMutable($number = null)
1038
  {
1039 1
    if ($number === null) {
1040
      $this->array = (array)\array_shift($this->array);
1041 1
    } else {
1042
      $number = (int)$number;
1043
      $this->array = \array_splice($this->array, 0, $number, true);
1044
    }
1045
1046
    return $this;
1047
  }
1048
1049
  /**
1050
   * Exchanges all keys with their associated values in an array.
1051
   *
1052
   * @return static <p>(Immutable)</p>
1053
   */
1054 58
  public function flip()
1055
  {
1056
    $result = \array_flip($this->array);
1057
1058 58
    return static::create($result);
1059 3
  }
1060 58
1061 3
  /**
1062 3
   * Get a value from an array (optional using dot-notation).
1063 56
   *
1064
   * @param string $key      <p>The key to look for.</p>
1065
   * @param mixed  $fallback <p>Value to fallback to.</p>
1066 58
   * @param array  $array    <p>The array to get from, if it's set to "null" we use the current array from the
1067 1
   *                         class.</p>
1068
   *
1069
   * @return mixed
1070
   */
1071 58
  public function get($key, $fallback = null, $array = null)
1072 2
  {
1073 2
    if (
1074
        $array !== null
1075 58
        &&
1076 48
        is_array($array)
1077 5
    ) {
1078
      $usedArray = $array;
1079
    } else {
1080 45
      $usedArray = $this->array;
1081
    }
1082
1083
    if ($key === null) {
1084 19
      return static::create($usedArray);
1085 19
    }
1086 19
1087
    // php cast "bool"-index into "int"-index
1088
    if ((bool)$key === $key) {
1089 4
      $key = (int)$key;
1090 4
    }
1091
1092 4
    if (\array_key_exists($key, $usedArray) === true) {
1093
      if (is_array($usedArray[$key])) {
1094
        return static::create($usedArray[$key]);
1095
      }
1096 4
1097
      return $usedArray[$key];
1098
    }
1099
1100
    // Crawl through array, get key according to object or not
1101
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1102
      if (!isset($usedArray[$segment])) {
1103
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1104 483
      }
1105
1106 483
      $usedArray = $usedArray[$segment];
1107
    }
1108 483
1109
    if (is_array($usedArray)) {
1110
      return static::create($usedArray);
1111
    }
1112
1113
    return $usedArray;
1114 398
  }
1115
1116 398
  /**
1117
   * Get the current array from the "Arrayy"-object.
1118
   *
1119 398
   * @return array
1120
   */
1121
  public function getArray()
1122
  {
1123
    \array_map(array('self', 'internalGetArray'), $this->array);
1124
1125
    return $this->array;
1126
  }
1127
1128
  /**
1129
   * @param mixed $value
1130
   */
1131
  protected function internalGetArray(&$value)
1132
  {
1133 1
    if ($value instanceof self) {
1134
      $value &= $value->getArray();
1135 1
    }
1136
  }
1137 1
1138
  /**
1139
   * Returns the values from a single column of the input array, identified by
1140
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1141
   *
1142
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1143
   * array by the values from the $indexKey column in the input array.
1144
   *
1145
   * @param mixed $columnKey
1146
   * @param mixed $indexKey
1147 38
   *
1148
   * @return static <p>(Immutable)</p>
1149 38
   */
1150 10
  public function getColumn($columnKey = null, $indexKey = null)
1151
  {
1152 10
    $result = \array_column($this->array, $columnKey, $indexKey);
1153 2
1154 2
    return static::create($result);
1155 8
  }
1156
1157 10
  /**
1158
   * Get correct PHP constant for direction.
1159
   *
1160
   * @param int|string $direction
1161 38
   *
1162
   * @return int
1163 38
   */
1164
  protected function getDirection($direction)
1165
  {
1166
    if (is_string($direction)) {
1167 38
      $direction = strtolower($direction);
1168
1169
      if ($direction === 'desc') {
1170
        $direction = SORT_DESC;
1171
      } else {
1172
        $direction = SORT_ASC;
1173
      }
1174
    }
1175
1176
    if (
1177 1
        $direction !== SORT_DESC
1178
        &&
1179 1
        $direction !== SORT_ASC
1180
    ) {
1181
      $direction = SORT_ASC;
1182
    }
1183
1184
    return $direction;
1185
  }
1186
1187
  /**
1188
   * alias: for "Arrayy->keys()"
1189 3
   *
1190
   * @see Arrayy::keys()
1191 3
   *
1192
   * @return static <p>(Immutable)</p>
1193
   */
1194
  public function getKeys()
1195
  {
1196
    return $this->keys();
1197
  }
1198
1199
  /**
1200
   * alias: for "Arrayy->randomImmutable()"
1201 3
   *
1202
   * @see Arrayy::randomImmutable()
1203 3
   *
1204
   * @return static <p>(Immutable)</p>
1205
   */
1206
  public function getRandom()
1207
  {
1208
    return $this->randomImmutable();
1209
  }
1210
1211
  /**
1212
   * alias: for "Arrayy->randomKey()"
1213
   *
1214
   * @see Arrayy::randomKey()
1215 9
   *
1216
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1217 9
   */
1218
  public function getRandomKey()
1219
  {
1220
    return $this->randomKey();
1221
  }
1222
1223
  /**
1224
   * alias: for "Arrayy->randomKeys()"
1225
   *
1226
   * @see Arrayy::randomKeys()
1227 3
   *
1228
   * @param int $number
1229 3
   *
1230
   * @return static <p>(Immutable)</p>
1231
   */
1232
  public function getRandomKeys($number)
1233
  {
1234
    return $this->randomKeys($number);
1235
  }
1236
1237
  /**
1238
   * alias: for "Arrayy->randomValue()"
1239
   *
1240
   * @see Arrayy::randomValue()
1241 6
   *
1242
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1243 6
   */
1244
  public function getRandomValue()
1245
  {
1246
    return $this->randomValue();
1247
  }
1248
1249
  /**
1250
   * alias: for "Arrayy->randomValues()"
1251
   *
1252
   * @see Arrayy::randomValues()
1253
   *
1254 3
   * @param int $number
1255
   *
1256 3
   * @return static <p>(Immutable)</p>
1257 3
   */
1258
  public function getRandomValues($number)
1259
  {
1260 3
    return $this->randomValues($number);
1261
  }
1262 3
1263 3
  /**
1264
   * Group values from a array according to the results of a closure.
1265 3
   *
1266
   * @param string $grouper <p>A callable function name.</p>
1267
   * @param bool   $saveKeys
1268
   *
1269 3
   * @return static <p>(Immutable)</p>
1270 3
   */
1271 3
  public function group($grouper, $saveKeys = false)
1272
  {
1273
    $array = (array)$this->array;
1274 3
    $result = array();
1275 2
1276 1
    // Iterate over values, group by property/results from closure
1277 1
    foreach ($array as $key => $value) {
1278 1
1279 1
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1280 1
      $newValue = $this->get($groupKey, null, $result);
1281
1282 2
      if ($groupKey instanceof self) {
1283
        $groupKey = $groupKey->getArray();
1284 3
      }
1285
1286 3
      if ($newValue instanceof self) {
1287
        $newValue = $newValue->getArray();
1288
      }
1289
1290
      // Add to results
1291
      if ($groupKey !== null) {
1292
        if ($saveKeys) {
1293
          $result[$groupKey] = $newValue;
1294
          $result[$groupKey][$key] = $value;
1295
        } else {
1296 22
          $result[$groupKey] = $newValue;
1297
          $result[$groupKey][] = $value;
1298
        }
1299 22
      }
1300
1301 22
    }
1302
1303
    return static::create($result);
1304
  }
1305
1306
  /**
1307
   * Check if an array has a given key.
1308
   *
1309
   * @param mixed $key
1310
   *
1311 27
   * @return bool
1312
   */
1313 27
  public function has($key)
1314
  {
1315
    // Generate unique string to use as marker.
1316
    $unFound = (string)uniqid('arrayy', true);
1317
1318
    return $this->get($key, $unFound) !== $unFound;
1319
  }
1320
1321
  /**
1322
   * Implodes an array.
1323
   *
1324
   * @param string $glue
1325
   *
1326
   * @return string
1327 3
   */
1328
  public function implode($glue = '')
1329 3
  {
1330
    return implode($glue, $this->array);
1331 3
  }
1332 3
1333 2
  /**
1334 2
   * Given a list and an iterate-function that returns
1335 3
   * a key for each element in the list (or a property name),
1336
   * returns an object with an index of each item.
1337 3
   *
1338
   * Just like groupBy, but for when you know your keys are unique.
1339
   *
1340
   * @param mixed $key
1341
   *
1342
   * @return static <p>(Immutable)</p>
1343
   */
1344
  public function indexBy($key)
1345
  {
1346
    $results = array();
1347
1348
    foreach ($this->array as $a) {
1349 4
      if (\array_key_exists($key, $a) === true) {
1350
        $results[$a[$key]] = $a;
1351 4
      }
1352
    }
1353
1354
    return static::create($results);
1355
  }
1356
1357
  /**
1358
   * alias: for "Arrayy->searchIndex()"
1359
   *
1360
   * @see Arrayy::searchIndex()
1361 12
   *
1362
   * @param mixed $value <p>The value to search for.</p>
1363 12
   *
1364
   * @return mixed
1365 12
   */
1366
  public function indexOf($value)
1367
  {
1368
    return $this->searchIndex($value);
1369
  }
1370
1371
  /**
1372
   * Get everything but the last..$to items.
1373
   *
1374
   * @param int $to
1375 18
   *
1376
   * @return static <p>(Immutable)</p>
1377 18
   */
1378
  public function initial($to = 1)
1379
  {
1380 18
    $slice = count($this->array) - $to;
1381
1382
    return $this->firstsImmutable($slice);
1383
  }
1384
1385
  /**
1386
   * Internal mechanics of remove method.
1387
   *
1388
   * @param string $key
1389
   *
1390 18
   * @return boolean
1391
   */
1392 18
  protected function internalRemove($key)
1393
  {
1394 18
    $path = explode($this->pathSeparator, (string)$key);
1395
1396
    // Crawl though the keys
1397
    while (count($path) > 1) {
1398
      $key = \array_shift($path);
1399
1400
      if (!$this->has($key)) {
1401
        return false;
1402
      }
1403
1404
      $this->array = &$this->array[$key];
1405 28
    }
1406
1407 28
    $key = \array_shift($path);
1408
1409
    unset($this->array[$key]);
1410
1411
    return true;
1412 28
  }
1413 28
1414
  /**
1415
   * Internal mechanic of set method.
1416 28
   *
1417 2
   * @param string $key
1418
   * @param mixed  $value
1419
   *
1420
   * @return bool
1421
   */
1422 2
  protected function internalSet($key, $value)
1423
  {
1424
    if ($key === null) {
1425
      return false;
1426 2
    }
1427 2
1428
    // init
1429 28
    $array =& $this->array;
1430
    $path = explode($this->pathSeparator, (string)$key);
1431 28
1432
    // Crawl through the keys
1433
    while (count($path) > 1) {
1434
      $key = \array_shift($path);
1435
1436
      // If the key doesn't exist at this depth, we will just create an empty array
1437
      // to hold the next value, allowing us to create the arrays to hold final
1438
      // values at the correct depth. Then we'll keep digging into the array.
1439
      if (!isset($array[$key]) || !is_array($array[$key])) {
1440
        $array[$key] = static::create(array());
1441 2
      }
1442
1443 2
      $array =& $array[$key];
1444
    }
1445
1446
    $array[\array_shift($path)] = $value;
1447
1448
    return true;
1449
  }
1450
1451
  /**
1452
   * Return an array with all elements found in input array.
1453 1
   *
1454
   * @param array $search
1455 1
   *
1456
   * @return static <p>(Immutable)</p>
1457
   */
1458
  public function intersection(array $search)
1459
  {
1460
    return static::create(\array_values(\array_intersect($this->array, $search)));
1461
  }
1462
1463
  /**
1464
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1465
   *
1466 1
   * @param array $search
1467
   *
1468
   * @return bool
1469 1
   */
1470 1
  public function intersects(array $search)
1471 1
  {
1472
    return count($this->intersection($search)->array) > 0;
1473
  }
1474 1
1475 1
  /**
1476 1
   * Invoke a function on all of an array's values.
1477 1
   *
1478
   * @param mixed $callable
1479
   * @param mixed $arguments
1480 1
   *
1481
   * @return static <p>(Immutable)</p>
1482
   */
1483
  public function invoke($callable, $arguments = array())
1484
  {
1485
    // If one argument given for each iteration, create an array for it.
1486
    if (!is_array($arguments)) {
1487
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1488 15
    }
1489
1490 15
    // If the callable has arguments, pass them.
1491 3
    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...
1492
      $array = \array_map($callable, $this->array, $arguments);
1493
    } else {
1494 13
      $array = \array_map($callable, $this->array);
1495 13
    }
1496 11
1497
    return static::create($array);
1498 3
  }
1499
1500 3
  /**
1501
   * Check whether array is associative or not.
1502
   *
1503
   * @return bool <p>Returns true if associative, false otherwise.</p>
1504
   */
1505
  public function isAssoc()
1506
  {
1507
    if ($this->isEmpty()) {
1508 85
      return false;
1509
    }
1510 85
1511
    foreach ($this->keys()->getArray() as $key) {
1512
      if (!is_string($key)) {
1513
        return false;
1514
      }
1515
    }
1516
1517
    return true;
1518
  }
1519
1520
  /**
1521
   * Check whether the array is empty or not.
1522
   *
1523
   * @return bool <p>Returns true if empty, false otherwise.</p>
1524
   */
1525
  public function isEmpty()
1526
  {
1527
    return !$this->array;
1528
  }
1529
1530 14
  /**
1531
   * Check if the current array is equal to the given "$array" or not.
1532 14
   *
1533
   * @param array $array
1534
   *
1535
   * @return bool
1536
   */
1537
  public function isEqual(array $array)
1538
  {
1539
    return ($this->array === $array);
1540 5
  }
1541
1542 5
  /**
1543 2
   * Check if the current array is a multi-array.
1544
   *
1545
   * @return bool
1546 4
   */
1547 4
  public function isMultiArray()
1548 2
  {
1549
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1550 3
  }
1551
1552 2
  /**
1553
   * Check whether array is numeric or not.
1554
   *
1555
   * @return bool <p>Returns true if numeric, false otherwise.</p>
1556
   */
1557
  public function isNumeric()
1558
  {
1559
    if ($this->isEmpty()) {
1560 1
      return false;
1561
    }
1562 1
1563
    foreach ($this->keys() as $key) {
1564
      if (!is_int($key)) {
1565
        return false;
1566
      }
1567
    }
1568
1569
    return true;
1570 25
  }
1571
1572 25
  /**
1573
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1574
   *
1575
   * @return bool
1576
   */
1577
  public function isSequential()
1578
  {
1579
    return \array_keys($this->array) === range(0, count($this->array) - 1);
1580 4
  }
1581
1582 4
  /**
1583
   * Get all keys from the current array.
1584
   *
1585
   * @return static <p>(Immutable)</p>
1586
   */
1587
  public function keys()
1588
  {
1589
    return static::create(\array_keys($this->array));
1590
  }
1591
1592 13
  /**
1593
   * Get the last value from the current array.
1594 13
   *
1595 1
   * @return mixed <p>Return null if there wasn't a element.</p>
1596
   */
1597
  public function last()
1598 12
  {
1599 8
    return $this->pop();
1600
  }
1601 8
1602 1
  /**
1603 1
   * Get the last value(s) from the current array.
1604 7
   *
1605
   * @param int|null $number
1606
   *
1607 8
   * @return static <p>(Immutable)</p>
1608 8
   */
1609 4
  public function lastsImmutable($number = null)
1610 4
  {
1611
    if ($this->isEmpty()) {
1612
      return static::create();
1613 12
    }
1614
1615
    if ($number === null) {
1616
      $poppedValue = $this->pop();
1617
1618
      if ($poppedValue === null) {
1619
        $poppedValue = array($poppedValue);
1620
      } else {
1621
        $poppedValue = (array)$poppedValue;
1622
      }
1623 13
1624
      $arrayy = static::create($poppedValue);
1625 13
    } else {
1626 1
      $number = (int)$number;
1627
      $arrayy = $this->rest(-$number);
1628
    }
1629 12
1630 8
    return $arrayy;
1631
  }
1632 8
1633 1
  /**
1634 1
   * Get the last value(s) from the current array.
1635 7
   *
1636
   * @param int|null $number
1637
   *
1638 8
   * @return static <p>(Mutable)</p>
1639 8
   */
1640 4
  public function lastsMutable($number = null)
1641 4
  {
1642
    if ($this->isEmpty()) {
1643
      return $this;
1644 12
    }
1645
1646
    if ($number === null) {
1647
      $poppedValue = $this->pop();
1648
1649
      if ($poppedValue === null) {
1650
        $poppedValue = array($poppedValue);
1651
      } else {
1652
        $poppedValue = (array)$poppedValue;
1653
      }
1654
1655
      $this->array = static::create($poppedValue)->array;
1656 10
    } else {
1657
      $number = (int)$number;
1658 10
      $this->array = $this->rest(-$number)->array;
1659
    }
1660
1661
    return $this;
1662
  }
1663
1664
  /**
1665
   * Count the values from the current array.
1666
   *
1667
   * alias: for "Arrayy->size()"
1668
   *
1669 4
   * @see Arrayy::size()
1670
   *
1671 4
   * @return int
1672
   */
1673 4
  public function length()
1674
  {
1675
    return $this->size();
1676
  }
1677
1678
  /**
1679
   * Apply the given function to the every element of the array,
1680
   * collecting the results.
1681
   *
1682
   * @param callable $callable
1683 15
   *
1684
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
1685 15
   */
1686 2
  public function map($callable)
1687
  {
1688
    $result = \array_map($callable, $this->array);
1689
1690 13
    return static::create($result);
1691
  }
1692 13
1693 13
  /**
1694
   * Check if all items in current array match a truth test.
1695 13
   *
1696 7
   * @param \Closure $closure
1697
   *
1698 9
   * @return bool
1699
   */
1700 7 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...
1701
  {
1702
    if (count($this->array) === 0) {
1703
      return false;
1704
    }
1705
1706
    // init
1707
    $array = $this->array;
1708
1709
    foreach ($array as $key => $value) {
1710 14
      $value = $closure($value, $key);
1711
1712 14
      if ($value === false) {
1713 2
        return false;
1714
      }
1715
    }
1716
1717 12
    return true;
1718
  }
1719 12
1720 12
  /**
1721
   * Check if any item in the current array matches a truth test.
1722 12
   *
1723 9
   * @param \Closure $closure
1724
   *
1725 5
   * @return bool
1726
   */
1727 4 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...
1728
  {
1729
    if (count($this->array) === 0) {
1730
      return false;
1731
    }
1732
1733
    // init
1734
    $array = $this->array;
1735 10
1736
    foreach ($array as $key => $value) {
1737 10
      $value = $closure($value, $key);
1738 1
1739
      if ($value === true) {
1740
        return true;
1741 9
      }
1742
    }
1743
1744
    return false;
1745
  }
1746
1747
  /**
1748
   * Get the max value from an array.
1749
   *
1750
   * @return mixed
1751
   */
1752
  public function max()
1753
  {
1754 25
    if ($this->count() === 0) {
1755
      return false;
1756 25
    }
1757 4
1758 4
    return max($this->array);
1759 21
  }
1760
1761
  /**
1762 25
   * Merge the new $array into the current array.
1763
   *
1764
   * - keep key,value from the current array, also if the index is in the new $array
1765
   *
1766
   * @param array $array
1767
   * @param bool  $recursive
1768
   *
1769
   * @return static <p>(Immutable)</p>
1770
   */
1771 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...
1772
  {
1773
    if (true === $recursive) {
1774
      $result = \array_replace_recursive($this->array, $array);
1775
    } else {
1776 16
      $result = \array_replace($this->array, $array);
1777
    }
1778 16
1779 4
    return static::create($result);
1780 4
  }
1781 12
1782
  /**
1783
   * Merge the new $array into the current array.
1784 16
   *
1785
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1786
   * - create new indexes
1787
   *
1788
   * @param array $array
1789
   * @param bool  $recursive
1790
   *
1791
   * @return static <p>(Immutable)</p>
1792
   */
1793 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...
1794
  {
1795
    if (true === $recursive) {
1796
      $result = \array_merge_recursive($this->array, $array);
1797 16
    } else {
1798
      $result = \array_merge($this->array, $array);
1799 16
    }
1800 4
1801 4
    return static::create($result);
1802 12
  }
1803
1804
  /**
1805 16
   * Merge the the current array into the $array.
1806
   *
1807
   * - use key,value from the new $array, also if the index is in the current array
1808
   *
1809
   * @param array $array
1810
   * @param bool  $recursive
1811
   *
1812
   * @return static <p>(Immutable)</p>
1813
   */
1814 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...
1815
  {
1816
    if (true === $recursive) {
1817
      $result = \array_replace_recursive($array, $this->array);
1818
    } else {
1819 16
      $result = \array_replace($array, $this->array);
1820
    }
1821 16
1822 4
    return static::create($result);
1823 4
  }
1824 12
1825
  /**
1826
   * Merge the current array into the new $array.
1827 16
   *
1828
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1829
   * - create new indexes
1830
   *
1831
   * @param array $array
1832
   * @param bool  $recursive
1833
   *
1834
   * @return static <p>(Immutable)</p>
1835 10
   */
1836 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...
1837 10
  {
1838 1
    if (true === $recursive) {
1839
      $result = \array_merge_recursive($array, $this->array);
1840
    } else {
1841 9
      $result = \array_merge($array, $this->array);
1842
    }
1843
1844
    return static::create($result);
1845
  }
1846
1847
  /**
1848
   * Get the min value from an array.
1849
   *
1850
   * @return mixed
1851
   */
1852
  public function min()
1853
  {
1854
    if ($this->count() === 0) {
1855
      return false;
1856
    }
1857
1858
    return min($this->array);
1859
  }
1860
1861
  /**
1862
   * Get a subset of the items from the given array.
1863
   *
1864
   * @param mixed[] $keys
1865
   *
1866 4
   * @return static <p>(Immutable)</p>
1867
   */
1868 4
  public function only(array $keys)
1869
  {
1870 4
    $array = $this->array;
1871
1872
    return static::create(\array_intersect_key($array, \array_flip($keys)));
1873
  }
1874
1875
  /**
1876
   * Pad array to the specified size with a given value.
1877
   *
1878 16
   * @param int   $size  <p>Size of the result array.</p>
1879
   * @param mixed $value <p>Empty value by default.</p>
1880 16
   *
1881
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
1882
   */
1883
  public function pad($size, $value)
1884
  {
1885
    $result = \array_pad($this->array, $size, $value);
1886
1887
    return static::create($result);
1888
  }
1889
1890
  /**
1891 8
   * Pop a specified value off the end of the current array.
1892
   *
1893 8
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
1894 8
   */
1895 8
  public function pop()
1896
  {
1897 1
    return \array_pop($this->array);
1898
  }
1899
1900 8
  /**
1901
   * Prepend a value to the current array.
1902
   *
1903
   * @param mixed $value
1904
   * @param mixed $key
1905
   *
1906
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
1907
   */
1908 4
  public function prepend($value, $key = null)
1909
  {
1910 4
    if ($key === null) {
1911 4
      \array_unshift($this->array, $value);
1912 4
    } else {
1913 4
      /** @noinspection AdditionOperationOnArraysInspection */
1914
      $this->array = array($key => $value) + $this->array;
1915 4
    }
1916
1917
    return $this;
1918
  }
1919
1920
  /**
1921
   * Push one or more values onto the end of array at once.
1922
   *
1923
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
1924
   */
1925 17 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...
1926
  {
1927 17
    if (func_num_args()) {
1928
      $args = \array_merge(array(&$this->array), func_get_args());
1929
      call_user_func_array('array_push', $args);
1930
    }
1931 17
1932 14
    return $this;
1933
  }
1934 14
1935
  /**
1936
   * Get a random value from the current array.
1937 5
   *
1938 5
   * @param null|int $number <p>How many values you will take?</p>
1939
   *
1940 5
   * @return static <p>(Immutable)</p>
1941
   */
1942
  public function randomImmutable($number = null)
1943
  {
1944
    if ($this->count() === 0) {
1945
      return static::create();
1946
    }
1947
1948 View Code Duplication
    if ($number === null) {
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...
1949
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
1950 4
1951
      return static::create($arrayRandValue);
1952 4
    }
1953
1954 4
    $arrayTmp = $this->array;
1955
    shuffle($arrayTmp);
1956
1957
    return static::create($arrayTmp)->firstsImmutable($number);
1958 4
  }
1959
1960
  /**
1961
   * Pick a random key/index from the keys of this array.
1962
   *
1963
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1964
   *
1965
   * @throws \RangeException If array is empty
1966
   */
1967
  public function randomKey()
1968
  {
1969
    $result = $this->randomKeys(1);
1970 14
1971
    if (!isset($result[0])) {
1972 14
      $result[0] = null;
1973 14
    }
1974
1975 14
    return $result[0];
1976 3
  }
1977 3
1978 3
  /**
1979 3
   * Pick a given number of random keys/indexes out of this array.
1980
   *
1981 3
   * @param int $number <p>The number of keys/indexes (should be <= $this->count())</p>
1982 3
   *
1983
   * @return static <p>(Immutable)</p>
1984
   *
1985 11
   * @throws \RangeException If array is empty
1986
   */
1987 11
  public function randomKeys($number)
1988
  {
1989
    $number = (int)$number;
1990
    $count = $this->count();
1991
1992
    if ($number === 0 || $number > $count) {
1993
      throw new \RangeException(
1994
          sprintf(
1995
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1996
              $number,
1997 17
              $count
1998
          )
1999 17
      );
2000
    }
2001
2002
    $result = (array)\array_rand($this->array, $number);
2003 17
2004 7
    return static::create($result);
2005 7
  }
2006
2007 7
  /**
2008
   * Get a random value from the current array.
2009
   *
2010 11
   * @param null|int $number <p>How many values you will take?</p>
2011
   *
2012 11
   * @return static <p>(Mutable)</p>
2013
   */
2014
  public function randomMutable($number = null)
2015
  {
2016
    if ($this->count() === 0) {
2017
      return static::create();
2018
    }
2019
2020 4 View Code Duplication
    if ($number === null) {
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...
2021
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2022 4
      $this->array = $arrayRandValue;
2023
2024 4
      return $this;
2025
    }
2026
2027
    shuffle($this->array);
2028 4
2029
    return $this->firstsMutable($number);
2030
  }
2031
2032
  /**
2033
   * Pick a random value from the values of this array.
2034
   *
2035
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2036
   */
2037
  public function randomValue()
2038 7
  {
2039
    $result = $this->randomImmutable();
2040 7
2041
    if (!isset($result[0])) {
2042 7
      $result[0] = null;
2043
    }
2044
2045
    return $result[0];
2046
  }
2047
2048
  /**
2049
   * Pick a given number of random values out of this array.
2050
   *
2051
   * @param int $number
2052
   *
2053
   * @return static <p>(Mutable)</p>
2054
   */
2055 9
  public function randomValues($number)
2056
  {
2057 9
    $number = (int)$number;
2058 9
2059 9
    return $this->randomMutable($number);
2060 2
  }
2061 1
2062 1
  /**
2063 2
   * Get a random value from an array, with the ability to skew the results.
2064 9
   *
2065
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2066 9
   *
2067
   * @param array    $array
2068
   * @param null|int $number <p>How many values you will take?</p>
2069
   *
2070
   * @return static <p>(Immutable)</p>
2071
   */
2072
  public function randomWeighted(array $array, $number = null)
2073
  {
2074
    $options = array();
2075
    foreach ($array as $option => $weight) {
2076
      if ($this->searchIndex($option) !== false) {
2077 3
        for ($i = 0; $i < $weight; ++$i) {
2078
          $options[] = $option;
2079 3
        }
2080
      }
2081 3
    }
2082
2083
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2084 3
  }
2085
2086
  /**
2087 3
   * Reduce the current array via callable e.g. anonymous-function.
2088
   *
2089
   * @param mixed $callable
2090
   * @param array $init
2091
   *
2092
   * @return static <p>(Immutable)</p>
2093
   */
2094
  public function reduce($callable, array $init = array())
2095 9
  {
2096
    $result = \array_reduce($this->array, $callable, $init);
2097 9
2098
    if ($result === null) {
2099 9
      $this->array = array();
2100
    } else {
2101
      $this->array = (array)$result;
2102
    }
2103
2104
    return static::create($this->array);
2105
  }
2106
2107
  /**
2108
   * Create a numerically re-indexed Arrayy object.
2109 1
   *
2110
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2111 1
   */
2112
  public function reindex()
2113 1
  {
2114 1
    $this->array = \array_values($this->array);
2115 1
2116 1
    return $this;
2117 1
  }
2118
2119 1
  /**
2120
   * Return all items that fail the truth test.
2121
   *
2122
   * @param \Closure $closure
2123
   *
2124
   * @return static <p>(Immutable)</p>
2125
   */
2126 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...
2127
  {
2128
    $filtered = array();
2129 18
2130
    foreach ($this->array as $key => $value) {
2131
      if (!$closure($value, $key)) {
2132 18
        $filtered[$key] = $value;
2133
      }
2134
    }
2135
2136
    return static::create($filtered);
2137
  }
2138
2139
  /**
2140 18
   * Remove a value from the current array (optional using dot-notation).
2141
   *
2142 18
   * @param mixed $key
2143
   *
2144
   * @return static <p>(Immutable)</p>
2145
   */
2146
  public function remove($key)
2147
  {
2148
    // Recursive call
2149
    if (is_array($key)) {
2150 7
      foreach ($key as $k) {
2151
        $this->internalRemove($k);
2152 7
      }
2153 7
2154
      return static::create($this->array);
2155 7
    }
2156
2157
    $this->internalRemove($key);
2158
2159
    return static::create($this->array);
2160
  }
2161
2162
  /**
2163 7
   * Remove the first value from the current array.
2164
   *
2165 7
   * @return static <p>(Immutable)</p>
2166 7
   */
2167
  public function removeFirst()
2168 7
  {
2169
    $tmpArray = $this->array;
2170
    \array_shift($tmpArray);
2171
2172
    return static::create($tmpArray);
2173
  }
2174
2175
  /**
2176
   * Remove the last value from the current array.
2177
   *
2178 7
   * @return static <p>(Immutable)</p>
2179
   */
2180 7
  public function removeLast()
2181 7
  {
2182 6
    $tmpArray = $this->array;
2183 6
    \array_pop($tmpArray);
2184
2185
    return static::create($tmpArray);
2186 6
  }
2187 6
2188 7
  /**
2189
   * Removes a particular value from an array (numeric or associative).
2190 7
   *
2191 7
   * @param mixed $value
2192 7
   *
2193
   * @return static <p>(Immutable)</p>
2194 7
   */
2195
  public function removeValue($value)
2196
  {
2197
    $isNumericArray = true;
2198
    foreach ($this->array as $key => $item) {
2199
      if ($item === $value) {
2200
        if (!is_int($key)) {
2201
          $isNumericArray = false;
2202
        }
2203
        unset($this->array[$key]);
2204
      }
2205
    }
2206 2
2207
    if ($isNumericArray) {
2208 2
      $this->array = \array_values($this->array);
2209
    }
2210 2
2211
    return static::create($this->array);
2212
  }
2213
2214
  /**
2215
   * Replace a key with a new key/value pair.
2216
   *
2217
   * @param $replace
2218
   * @param $key
2219
   * @param $value
2220 2
   *
2221
   * @return static <p>(Immutable)</p>
2222 2
   */
2223
  public function replace($replace, $key, $value)
2224 2
  {
2225
    $this->remove($replace);
2226
2227
    return $this->set($key, $value);
2228
  }
2229
2230
  /**
2231
   * Create an array using the current array as values and the other array as keys.
2232
   *
2233
   * @param array $keys <p>An array of keys.</p>
2234 2
   *
2235
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
2236 2
   */
2237
  public function replaceAllKeys(array $keys)
2238 2
  {
2239
    $result = \array_combine($keys, $this->array);
2240
2241
    return static::create($result);
2242
  }
2243
2244
  /**
2245
   * Create an array using the current array as keys and the other array as values.
2246
   *
2247
   * @param array $array <p>An array o values.</p>
2248 1
   *
2249
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
2250 1
   */
2251 1
  public function replaceAllValues(array $array)
2252
  {
2253 1
    $result = \array_combine($this->array, $array);
2254
2255
    return static::create($result);
2256
  }
2257
2258
  /**
2259
   * Replace the keys in an array with another set.
2260
   *
2261
   * @param array $keys <p>An array of keys matching the array's size</p>
2262
   *
2263
   * @return static <p>(Immutable)</p>
2264 3
   */
2265
  public function replaceKeys(array $keys)
2266 3
  {
2267 3
    $values = \array_values($this->array);
2268
    $result = \array_combine($keys, $values);
2269 3
2270 3
    return static::create($result);
2271 3
  }
2272
2273 3
  /**
2274
   * Replace the first matched value in an array.
2275
   *
2276
   * @param mixed $search
2277
   * @param mixed $replacement
2278
   *
2279
   * @return static <p>(Immutable)</p>
2280
   */
2281
  public function replaceOneValue($search, $replacement = '')
2282
  {
2283
    $array = $this->array;
2284 1
    $key = \array_search($search, $array, true);
2285
2286 1
    if ($key !== false) {
2287
      $array[$key] = $replacement;
2288 1
    }
2289
2290 1
    return static::create($array);
2291
  }
2292 1
2293
  /**
2294
   * Replace values in the current array.
2295
   *
2296
   * @param string $search      <p>The string to replace.</p>
2297
   * @param string $replacement <p>What to replace it with.</p>
2298
   *
2299
   * @return static <p>(Immutable)</p>
2300
   */
2301
  public function replaceValues($search, $replacement = '')
2302 15
  {
2303
    $array = $this->each(
2304 15
        function ($value) use ($search, $replacement) {
2305
          return UTF8::str_replace($search, $replacement, $value);
2306 15
        }
2307
    );
2308
2309
    return $array;
2310
  }
2311
2312
  /**
2313
   * Get the last elements from index $from until the end of this array.
2314
   *
2315
   * @param int $from
2316
   *
2317
   * @return static <p>(Immutable)</p>
2318
   */
2319 1
  public function rest($from = 1)
2320
  {
2321 1
    $tmpArray = $this->array;
2322
2323 1
    return static::create(\array_splice($tmpArray, $from));
2324 1
  }
2325 1
2326 1
  /**
2327 1
   * Move an array element to a new index.
2328 1
   *
2329 1
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2330 1
   *
2331 1
   * @param int|string $from
2332 1
   * @param int|string $to
2333 1
   *
2334 1
   * @return static <p>(Immutable)</p>
2335 1
   */
2336 1
  public function moveElement($from, $to)
2337 1
  {
2338 1
    $array = $this->array;
2339 1
2340 1
    if (is_int($from)) {
2341
      $tmp = \array_splice($array, $from, 1);
2342
      \array_splice($array, $to, 0, $tmp);
2343
      $output = $array;
2344 1
    } elseif (is_string($from)) {
2345
      $indexToMove = \array_search($from, \array_keys($array), true);
2346
      $itemToMove = $array[$from];
2347
      \array_splice($array, $indexToMove, 1);
2348
      $i = 0;
2349
      $output = array();
2350
      foreach ($array as $key => $item) {
2351
        if ($i == $to) {
2352 7
          $output[$from] = $itemToMove;
2353
        }
2354 7
        $output[$key] = $item;
2355
        $i++;
2356 7
      }
2357
    } else {
2358
      $output = array();
2359
    }
2360
2361
    return static::create($output);
2362
  }
2363
2364
  /**
2365
   * Return the array in the reverse order.
2366 20
   *
2367
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2368 20
   */
2369
  public function reverse()
2370
  {
2371
    $this->array = \array_reverse($this->array);
2372
2373
    return $this;
2374
  }
2375
2376
  /**
2377
   * Search for the first index of the current array via $value.
2378 9
   *
2379
   * @param mixed $value
2380
   *
2381 9
   * @return int|float|string
2382
   */
2383 9
  public function searchIndex($value)
2384
  {
2385
    return \array_search($value, $this->array, true);
2386
  }
2387
2388 9
  /**
2389 1
   * Search for the value of the current array via $index.
2390 1
   *
2391
   * @param mixed $index
2392 9
   *
2393 7
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
2394 7
   */
2395
  public function searchValue($index)
2396
  {
2397 9
    // init
2398
    $return = array();
2399
2400
    if ($this->isEmpty()) {
2401
      return static::create();
2402
    }
2403
2404
    // php cast "bool"-index into "int"-index
2405
    if ((bool)$index === $index) {
2406
      $index = (int)$index;
2407
    }
2408 17
2409
    if (\array_key_exists($index, $this->array) === true) {
2410 17
      $return = array($this->array[$index]);
2411
    }
2412 17
2413
2414
    return static::create($return);
2415
  }
2416
2417
  /**
2418
   * Set a value for the current array (optional using dot-notation).
2419
   *
2420
   * @param string $key   <p>The key to set.</p>
2421
   * @param mixed  $value <p>Its value.</p>
2422
   *
2423
   * @return static <p>(Immutable)</p>
2424
   */
2425 11
  public function set($key, $value)
2426
  {
2427
    $this->internalSet($key, $value);
2428 11
2429 4
    return static::create($this->array);
2430 4
  }
2431
2432 11
  /**
2433
   * Get a value from a array and set it if it was not.
2434
   *
2435
   * WARNING: this method only set the value, if the $key is not already set
2436
   *
2437
   * @param string $key      <p>The key</p>
2438
   * @param mixed  $fallback <p>The default value to set if it isn't.</p>
2439
   *
2440 4
   * @return mixed <p>(Mutable)</p>
2441
   */
2442 4
  public function setAndGet($key, $fallback = null)
2443
  {
2444
    // If the key doesn't exist, set it.
2445
    if (!$this->has($key)) {
2446
      $this->array = $this->set($key, $fallback)->getArray();
2447
    }
2448
2449
    return $this->get($key);
2450 1
  }
2451
2452 1
  /**
2453
   * Shifts a specified value off the beginning of array.
2454 1
   *
2455
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
2456 1
   */
2457
  public function shift()
2458
  {
2459
    return \array_shift($this->array);
2460
  }
2461
2462
  /**
2463
   * Shuffle the current array.
2464 93
   *
2465
   * @return static <p>(Immutable)</p>
2466 93
   */
2467
  public function shuffle()
2468
  {
2469
    $array = $this->array;
2470
2471
    shuffle($array);
2472
2473
    return static::create($array);
2474
  }
2475
2476
  /**
2477
   * Get the size of an array.
2478 4
   *
2479
   * @return int
2480 4
   */
2481
  public function size()
2482 4
  {
2483
    return count($this->array);
2484
  }
2485
2486
  /**
2487
   * Extract a slice of the array.
2488
   *
2489
   * @param int      $offset       <p>Slice begin index.</p>
2490
   * @param int|null $length       <p>Length of the slice.</p>
2491
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
2492
   *
2493
   * @return static <p>A slice of the original array with length $length.</p>
2494 19
   */
2495
  public function slice($offset, $length = null, $preserveKeys = false)
2496 19
  {
2497
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
2498 19
2499
    return static::create($result);
2500
  }
2501
2502
  /**
2503
   * Sort the current array and optional you can keep the keys.
2504
   *
2505
   * @param integer $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2506
   * @param integer $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2507
   * @param bool    $keepKeys
2508
   *
2509
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2510
   */
2511
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2512
  {
2513 18
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2514
2515 18
    return $this;
2516
  }
2517 18
2518
  /**
2519
   * Sort the current array by key.
2520
   *
2521
   * @link http://php.net/manual/en/function.ksort.php
2522
   * @link http://php.net/manual/en/function.krsort.php
2523
   *
2524
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2525
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2526
   *                              <strong>SORT_NATURAL</strong></p>
2527
   *
2528 1
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2529
   */
2530 1
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2531
  {
2532
    $this->sorterKeys($this->array, $direction, $strategy);
2533
2534
    return $this;
2535
  }
2536
2537
  /**
2538
   * Sort the current array by value.
2539
   *
2540
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2541 1
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2542
   *
2543 1
   * @return static <p>(Immutable)</p>
2544
   */
2545
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2546
  {
2547
    return $this->sort($direction, $strategy, true);
2548
  }
2549
2550
  /**
2551
   * Sort the current array by value.
2552
   *
2553
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2554
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2555
   *
2556
   * @return static <p>(Immutable)</p>
2557
   */
2558
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2559 1
  {
2560
    return $this->sort($direction, $strategy, false);
2561 1
  }
2562 1
2563
  /**
2564
   * Sort a array by value, by a closure or by a property.
2565 1
   *
2566 1
   * - If the sorter is null, the array is sorted naturally.
2567
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2568 1
   *
2569 1
   * @param null       $sorter
2570
   * @param string|int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2571 1
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2572
   *                              <strong>SORT_NATURAL</strong></p>
2573 1
   *
2574
   * @return static <p>(Immutable)</p>
2575 1
   */
2576 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2577 1
  {
2578
    $array = (array)$this->array;
2579
    $direction = $this->getDirection($direction);
2580
2581 1
    // Transform all values into their results.
2582
    if ($sorter) {
2583 1
      $arrayy = static::create($array);
2584
2585
      $that = $this;
2586
      $results = $arrayy->each(
2587
          function ($value) use ($sorter, $that) {
2588
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2589
          }
2590
      );
2591
2592
      $results = $results->getArray();
2593
    } else {
2594
      $results = $array;
2595 18
    }
2596
2597 18
    // Sort by the results and replace by original values
2598
    \array_multisort($results, $direction, $strategy, $array);
2599
2600 18
    return static::create($array);
2601 18
  }
2602 6
2603 6
  /**
2604 13
   * sorting keys
2605 13
   *
2606 13
   * @param array $elements
2607 13
   * @param int   $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2608 13
   * @param int   $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2609 18
   *
2610
   * @return void <p>Mutable</p>
2611
   */
2612
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2613
  {
2614
    $direction = $this->getDirection($direction);
2615
2616
    switch ($direction) {
2617
      case 'desc':
2618
      case SORT_DESC:
2619
        krsort($elements, $strategy);
2620 19
        break;
2621
      case 'asc':
2622 19
      case SORT_ASC:
2623
      default:
2624 19
        ksort($elements, $strategy);
2625 19
    }
2626 19
  }
2627
2628
  /**
2629 19
   * @param array      &$elements
2630 19
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2631 9
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2632 5
   *                              <strong>SORT_NATURAL</strong></p>
2633 5
   * @param bool       $keepKeys
2634 4
   *
2635
   * @return void <p>Mutable</p>
2636 9
   */
2637 10
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2638 10
  {
2639 10
    $direction = $this->getDirection($direction);
2640 10
2641 4
    if (!$strategy) {
2642 4
      $strategy = SORT_REGULAR;
2643 6
    }
2644
2645 10
    switch ($direction) {
2646 19
      case 'desc':
2647
      case SORT_DESC:
2648
        if ($keepKeys) {
2649
          arsort($elements, $strategy);
2650
        } else {
2651
          rsort($elements, $strategy);
2652
        }
2653
        break;
2654
      case 'asc':
2655
      case SORT_ASC:
2656 1
      default:
2657
        if ($keepKeys) {
2658 1
          asort($elements, $strategy);
2659
        } else {
2660 1
          sort($elements, $strategy);
2661 1
        }
2662 1
    }
2663 1
  }
2664 1
2665 1
  /**
2666
   * Split an array in the given amount of pieces.
2667
   *
2668 1
   * @param int  $numberOfPieces
2669
   * @param bool $keepKeys
2670
   *
2671
   * @return static <p>(Immutable)</p>
2672
   */
2673
  public function split($numberOfPieces = 2, $keepKeys = false)
2674
  {
2675
    $arrayCount = $this->count();
2676 1
2677
    if ($arrayCount === 0) {
2678 1
      $result = array();
2679
    } else {
2680 1
      $numberOfPieces = (int)$numberOfPieces;
2681 1
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
2682
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
2683
    }
2684 1
2685
    return static::create($result);
2686 1
  }
2687
2688
  /**
2689
   * Stripe all empty items.
2690
   *
2691
   * @return static <p>(Immutable)</p>
2692
   */
2693
  public function stripEmpty()
2694
  {
2695
    return $this->filter(
2696
        function ($item) {
2697 1
          if ($item === null) {
2698
            return false;
2699 1
          }
2700
2701 1
          return (bool)trim((string)$item);
2702
        }
2703 1
    );
2704
  }
2705
2706
  /**
2707
   * Swap two values between positions by key.
2708
   *
2709
   * @param string|int $swapA <p>a key in the array</p>
2710
   * @param string|int $swapB <p>a key in the array</p>
2711 141
   *
2712
   * @return static <p>(Immutable)</p>
2713 141
   */
2714
  public function swap($swapA, $swapB)
2715
  {
2716
    $array = $this->array;
2717
2718
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
2719
2720
    return static::create($array);
2721
  }
2722
2723 5
  /**
2724
   * alias: for "Arrayy->getArray()"
2725 5
   *
2726
   * @see Arrayy::getArray()
2727
   */
2728
  public function toArray()
2729
  {
2730
    return $this->getArray();
2731
  }
2732
2733
  /**
2734
   * Convert the current array to JSON.
2735 19
   *
2736
   * @param null|int $options <p>e.g. JSON_PRETTY_PRINT</p>
2737 19
   *
2738
   * @return string
2739
   */
2740
  public function toJson($options = null)
2741
  {
2742
    return UTF8::json_encode($this->array, $options);
2743
  }
2744
2745
  /**
2746
   * Implodes array to a string with specified separator.
2747 9
   *
2748
   * @param string $separator <p>The element's separator.</p>
2749 9
   *
2750
   * @return string <p>The string representation of array, separated by ",".</p>
2751
   */
2752
  public function toString($separator = ',')
2753
  {
2754
    return $this->implode($separator);
2755
  }
2756
2757 9
  /**
2758
   * alias: for "Arrayy->unique()"
2759 9
   *
2760 9
   * @see Arrayy::unique()
2761
   *
2762 8
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
2763 8
   */
2764 8
  public function uniqueNewIndex()
2765
  {
2766 8
    return $this->unique();
2767 9
  }
2768 9
2769 9
  /**
2770
   * Return a duplicate free copy of the current array.
2771 9
   *
2772
   * @return static <p>(Mutable)</p>
2773
   */
2774 9
  public function unique()
2775
  {
2776
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce($this->arr...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...
2777 9
        $this->array,
2778
        function ($resultArray, $value) {
2779
          if (!in_array($value, $resultArray, true)) {
2780
            $resultArray[] = $value;
2781
          }
2782
2783
          return $resultArray;
2784
        },
2785 9
        array()
2786
    );
2787
2788 9 View Code Duplication
    if ($this->array === null) {
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...
2789
      $this->array = array();
2790 9
    } else {
2791 9
      $this->array = (array)$this->array;
2792 9
    }
2793 8
2794 8
    return $this;
2795 8
  }
2796
2797 8
  /**
2798 9
   * Return a duplicate free copy of the current array. (with the old keys)
2799 9
   *
2800 9
   * @return static <p>(Mutable)</p>
2801
   */
2802 9
  public function uniqueKeepIndex()
2803
  {
2804
    // init
2805 9
    $array = $this->array;
2806
2807
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce(\array_key...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...
2808 9
        \array_keys($array),
2809
        function ($resultArray, $key) use ($array) {
2810
          if (!in_array($array[$key], $resultArray, true)) {
2811
            $resultArray[$key] = $array[$key];
2812
          }
2813
2814
          return $resultArray;
2815
        },
2816 4
        array()
2817
    );
2818 4
2819 4 View Code Duplication
    if ($this->array === null) {
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...
2820 4
      $this->array = array();
2821 4
    } else {
2822
      $this->array = (array)$this->array;
2823 4
    }
2824
2825
    return $this;
2826
  }
2827
2828
  /**
2829
   * Prepends one or more values to the beginning of array at once.
2830
   *
2831 2
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
2832
   */
2833 2 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...
2834
  {
2835
    if (func_num_args()) {
2836
      $args = \array_merge(array(&$this->array), func_get_args());
2837
      call_user_func_array('array_unshift', $args);
2838
    }
2839
2840
    return $this;
2841
  }
2842
2843
  /**
2844 9
   * Get all values from a array.
2845
   *
2846 9
   * @return static <p>(Immutable)</p>
2847 4
   */
2848 4
  public function values()
2849 5
  {
2850
    return static::create(\array_values((array)$this->array));
2851
  }
2852 9
2853
  /**
2854
   * Apply the given function to every element in the array, discarding the results.
2855
   *
2856
   * @param callable $callable
2857
   * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
2858
   *
2859
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
2860
   */
2861
  public function walk($callable, $recursive = false)
2862
  {
2863
    if (true === $recursive) {
2864
      \array_walk_recursive($this->array, $callable);
2865
    } else {
2866
      \array_walk($this->array, $callable);
2867
    }
2868
2869
    return $this;
2870
  }
2871
2872
}
2873