Completed
Push — master ( 3024e1...436d8e )
by Lars
04:12 queued 01:50
created

Arrayy::replaceAllKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 1
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 759
  public function __construct($array = array())
32
  {
33 759
    $array = $this->fallbackForArray($array);
34
35 757
    $this->array = $array;
36 757
  }
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 479
  public static function create($array = array())
524
  {
525 479
    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 1
  public function repeat($times)
536
  {
537 1
    if ($times === 0) {
538 1
      return new static();
539
    }
540
541 1
    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
   */
552
  public function createByReference(&$array = array())
553
  {
554
    $array = $this->fallbackForArray($array);
555
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
   *
566
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
567
   */
568 5
  public static function createFromJson($json)
569
  {
570 5
    $array = UTF8::json_decode($json, true);
571
572 5
    return static::create($array);
573
  }
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 4
  public static function createFromObject(\ArrayAccess $object)
583
  {
584 4
    $array = new static();
585 4
    foreach ($object as $key => $value) {
586
      /** @noinspection OffsetOperationsInspection */
587 3
      $array[$key] = $value;
588 4
    }
589
590 4
    return $array;
591
  }
592
593
  /**
594
   * Create an new Arrayy object via string.
595
   *
596
   * @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
   *
601
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
602
   */
603 8
  public static function createFromString($str, $delimiter, $regEx = null)
604
  {
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 1
      preg_match_all($regEx, $str, $array);
607
608 1
      if (!empty($array)) {
609 1
        $array = $array[0];
610 1
      }
611
612 1
    } else {
613 7
      $array = explode($delimiter, $str);
614
    }
615
616
    // trim all string in the array
617 8
    \array_walk(
618
        $array,
619
        function (&$val) {
620
          /** @noinspection ReferenceMismatchInspection */
621 8
          if (is_string($val)) {
622 8
            $val = trim($val);
623 8
          }
624 8
        }
625 8
    );
626
627 8
    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
   *
637
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
638
   */
639 1
  public static function createWithRange($low, $high, $step = 1)
640
  {
641 1
    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
   */
653 5
  public function customSortKeys($function)
654
  {
655 5
    uksort($this->array, $function);
656
657 5
    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
   *
667
   * @return static <p>(Mutable) Return this Arrayy object.</p>
668
   */
669 4
  public function customSortValues($function)
670
  {
671 4
    usort($this->array, $function);
672
673 4
    return $this;
674
  }
675
676
  /**
677
   * Return values that are only in the current array.
678
   *
679
   * @param array $array
680
   *
681
   * @return static <p>(Immutable)</p>
682
   */
683 12
  public function diff(array $array = array())
684
  {
685 12
    $result = \array_diff($this->array, $array);
686
687 12
    return static::create($result);
688
  }
689
690
  /**
691
   * Return values that are only in the current multi-dimensional array.
692
   *
693
   * @param array      $array
694
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
695
   *
696
   * @return static <p>(Immutable)</p>
697
   */
698 1
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
699
  {
700 1
    $result = array();
701
702
    if (
703
        $helperVariableForRecursion !== null
704 1
        &&
705 1
        is_array($helperVariableForRecursion)
706 1
    ) {
707 1
      $arrayForTheLoop = $helperVariableForRecursion;
708 1
    } else {
709 1
      $arrayForTheLoop = $this->array;
710
    }
711
712 1
    foreach ($arrayForTheLoop as $key => $value) {
713 1
      if (\array_key_exists($key, $array)) {
714 1
        if (is_array($value)) {
715 1
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
716 1
          if (!empty($recursiveDiff)) {
717 1
            $result[$key] = $recursiveDiff;
718 1
          }
719 1
        } else {
720 1
          if ($value != $array[$key]) {
721 1
            $result[$key] = $value;
722 1
          }
723
        }
724 1
      } else {
725 1
        $result[$key] = $value;
726
      }
727 1
    }
728
729 1
    return static::create($result);
730
  }
731
732
  /**
733
   * Return values that are only in the new $array.
734
   *
735
   * @param array $array
736
   *
737
   * @return static <p>(Immutable)</p>
738
   */
739 8
  public function diffReverse(array $array = array())
740
  {
741 8
    $result = \array_diff($array, $this->array);
742
743 8
    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 1
  public function divide()
752
  {
753 1
    return static::create(
754
        array(
755 1
            $this->keys(),
756 1
            $this->values(),
757
        )
758 1
    );
759
  }
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 4 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
  {
770 4
    $array = $this->array;
771
772 4
    foreach ($array as $key => $value) {
773 4
      $array[$key] = $closure($value, $key);
774 4
    }
775
776 4
    return static::create($array);
777
  }
778
779
  /**
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 4
  public function exists(\Closure $closure)
787
  {
788 4
    $isExists = false;
789 4
    foreach ($this->array as $key => $value) {
790 3
      if ($closure($value, $key)) {
791 1
        $isExists = true;
792 1
        break;
793
      }
794 4
    }
795
796 4
    return $isExists;
797
  }
798
799
  /**
800
   * create a fallback for array
801
   *
802
   * 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
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
806
   * 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
   *
810
   * @param $array
811
   *
812
   * @return array
813
   *
814
   * @throws \InvalidArgumentException
815
   */
816 759
  protected function fallbackForArray(&$array)
817
  {
818 759
    if (is_array($array)) {
819 756
      return $array;
820
    }
821
822 10
    if ($array instanceof self) {
823 1
      return $array->getArray();
824
    }
825
826 9
    if (!$array) {
827 6
      return array();
828
    }
829
830 8
    if ($array instanceof \ArrayAccess) {
831
      /** @noinspection ReferenceMismatchInspection */
832
      return static::createFromObject($array)->getArray();
833
    }
834
835 8
    if (is_object($array) && method_exists($array, '__toArray')) {
836
      return (array)$array->__toArray();
837
    }
838
839
    /** @noinspection ReferenceMismatchInspection */
840
    if (
841 8
        is_string($array)
842
        ||
843 2
        (is_object($array) && method_exists($array, '__toString'))
844 8
    ) {
845 6
      return array((string)$array);
846
    }
847
848 2
    throw new \InvalidArgumentException(
849
        'Passed value should be a array'
850 2
    );
851
  }
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 9
  public function filter($closure = null)
861
  {
862 9
    if (!$closure) {
863 1
      return $this->clean();
864
    }
865
866 9
    $array = \array_filter($this->array, $closure);
867
868 9
    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
   * @param string $value
877
   * @param string $comparisonOp
878
   *                            <p>
879
   *                            'eq' (equals),<br />
880
   *                            'gt' (greater),<br />
881
   *                            'gte' || 'ge' (greater or equals),<br />
882
   *                            'lt' (less),<br />
883
   *                            'lte' || 'le' (less or equals),<br />
884
   *                            'ne' (not equals),<br />
885
   *                            'contains',<br />
886
   *                            'notContains',<br />
887
   *                            'newer' (via strtotime),<br />
888
   *                            'older' (via strtotime),<br />
889
   *                            </p>
890
   *
891
   * @return static <p>(Immutable)</p>
892
   */
893 1
  public function filterBy($property, $value, $comparisonOp = null)
894
  {
895 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...
896 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
897 1
    }
898
899
    $ops = array(
900
        'eq'          => function ($item, $prop, $value) {
901 1
          return $item[$prop] === $value;
902 1
        },
903
        'gt'          => function ($item, $prop, $value) {
904
          return $item[$prop] > $value;
905 1
        },
906
        'ge'          => function ($item, $prop, $value) {
907
          return $item[$prop] >= $value;
908 1
        },
909
        'gte'         => function ($item, $prop, $value) {
910
          return $item[$prop] >= $value;
911 1
        },
912
        'lt'          => function ($item, $prop, $value) {
913 1
          return $item[$prop] < $value;
914 1
        },
915
        'le'          => function ($item, $prop, $value) {
916
          return $item[$prop] <= $value;
917 1
        },
918
        'lte'         => function ($item, $prop, $value) {
919
          return $item[$prop] <= $value;
920 1
        },
921
        'ne'          => function ($item, $prop, $value) {
922
          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
        'notContains' => function ($item, $prop, $value) {
928
          return !in_array($item[$prop], (array)$value, true);
929 1
        },
930
        'newer'       => function ($item, $prop, $value) {
931
          return strtotime($item[$prop]) > strtotime($value);
932 1
        },
933
        'older'       => function ($item, $prop, $value) {
934
          return strtotime($item[$prop]) < strtotime($value);
935 1
        },
936 1
    );
937
938 1
    $result = \array_values(
939 1
        \array_filter(
940 1
            (array)$this->array,
941
            function ($item) use (
942 1
                $property,
943 1
                $value,
944 1
                $ops,
945 1
                $comparisonOp
946
            ) {
947 1
              $item = (array)$item;
948 1
              $itemArrayy = new Arrayy($item);
949 1
              $item[$property] = $itemArrayy->get($property, array());
950
951 1
              return $ops[$comparisonOp]($item, $property, $value);
952
            }
953 1
        )
954 1
    );
955
956 1
    return static::create($result);
957
  }
958
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 8
  public function find(\Closure $closure)
968
  {
969 8
    foreach ($this->array as $key => $value) {
970 6
      if ($closure($value, $key)) {
971 5
        return $value;
972
      }
973 5
    }
974
975 3
    return false;
976
  }
977
978
  /**
979
   * find by ...
980
   *
981
   * @param string $property
982
   * @param string $value
983
   * @param string $comparisonOp
984
   *
985
   * @return static <p>(Immutable)</p>
986
   */
987
  public function findBy($property, $value, $comparisonOp = 'eq')
988
  {
989
    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 13
  public function first()
998
  {
999 13
    $tmpArray = $this->array;
1000 13
    $result = \array_shift($tmpArray);
1001
1002 13
    if ($result === null) {
1003 3
      return null;
1004
    }
1005
1006 10
    return $result;
1007
  }
1008
1009
  /**
1010
   * 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 28
  public function firstsImmutable($number = null)
1017
  {
1018 28
    if ($number === null) {
1019 7
      $arrayTmp = $this->array;
1020 7
      $array = (array)\array_shift($arrayTmp);
1021 7
    } else {
1022 21
      $number = (int)$number;
1023 21
      $arrayTmp = $this->array;
1024 21
      $array = \array_splice($arrayTmp, 0, $number, true);
1025
    }
1026
1027 28
    return static::create($array);
1028
  }
1029
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 26
  public function firstsMutable($number = null)
1038
  {
1039 26
    if ($number === null) {
1040 11
      $this->array = (array)\array_shift($this->array);
1041 11
    } else {
1042 15
      $number = (int)$number;
1043 15
      $this->array = \array_splice($this->array, 0, $number, true);
1044
    }
1045
1046 26
    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 1
  public function flip()
1055
  {
1056 1
    $result = \array_flip($this->array);
1057
1058 1
    return static::create($result);
1059
  }
1060
1061
  /**
1062
   * Get a value from an array (optional using dot-notation).
1063
   *
1064
   * @param string $key      <p>The key to look for.</p>
1065
   * @param mixed  $fallback <p>Value to fallback to.</p>
1066
   * @param array  $array    <p>The array to get from, if it's set to "null" we use the current array from the
1067
   *                         class.</p>
1068
   *
1069
   * @return mixed
1070
   */
1071 58
  public function get($key, $fallback = null, $array = null)
1072
  {
1073
    if (
1074
        $array !== null
1075 58
        &&
1076 3
        is_array($array)
1077 58
    ) {
1078 3
      $usedArray = $array;
1079 3
    } else {
1080 56
      $usedArray = $this->array;
1081
    }
1082
1083 58
    if ($key === null) {
1084 1
      return static::create($usedArray);
1085
    }
1086
1087
    // php cast "bool"-index into "int"-index
1088 58
    if ((bool)$key === $key) {
1089 2
      $key = (int)$key;
1090 2
    }
1091
1092 58
    if (\array_key_exists($key, $usedArray) === true) {
1093 48
      if (is_array($usedArray[$key])) {
1094 5
        return static::create($usedArray[$key]);
1095
      }
1096
1097 45
      return $usedArray[$key];
1098
    }
1099
1100
    // Crawl through array, get key according to object or not
1101 19
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1102 19
      if (!isset($usedArray[$segment])) {
1103 19
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1104
      }
1105
1106 4
      $usedArray = $usedArray[$segment];
1107 4
    }
1108
1109 4
    if (is_array($usedArray)) {
1110
      return static::create($usedArray);
1111
    }
1112
1113 4
    return $usedArray;
1114
  }
1115
1116
  /**
1117
   * Get the current array from the "Arrayy"-object.
1118
   *
1119
   * @return array
1120
   */
1121 484
  public function getArray()
1122
  {
1123 484
    \array_map(array('self', 'internalGetArray'), $this->array);
1124
1125 484
    return $this->array;
1126
  }
1127
1128
  /**
1129
   * @param mixed $value
1130
   */
1131 399
  protected function internalGetArray(&$value)
1132
  {
1133 399
    if ($value instanceof self) {
1134
      $value &= $value->getArray();
1135
    }
1136 399
  }
1137
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
   *
1148
   * @return static <p>(Immutable)</p>
1149
   */
1150 1
  public function getColumn($columnKey = null, $indexKey = null)
1151
  {
1152 1
    $result = \array_column($this->array, $columnKey, $indexKey);
1153
1154 1
    return static::create($result);
1155
  }
1156
1157
  /**
1158
   * Get correct PHP constant for direction.
1159
   *
1160
   * @param int|string $direction
1161
   *
1162
   * @return int
1163
   */
1164 38
  protected function getDirection($direction)
1165
  {
1166 38
    if (is_string($direction)) {
1167 10
      $direction = strtolower($direction);
1168
1169 10
      if ($direction === 'desc') {
1170 2
        $direction = SORT_DESC;
1171 2
      } else {
1172 8
        $direction = SORT_ASC;
1173
      }
1174 10
    }
1175
1176
    if (
1177
        $direction !== SORT_DESC
1178 38
        &&
1179
        $direction !== SORT_ASC
1180 38
    ) {
1181
      $direction = SORT_ASC;
1182
    }
1183
1184 38
    return $direction;
1185
  }
1186
1187
  /**
1188
   * alias: for "Arrayy->keys()"
1189
   *
1190
   * @see Arrayy::keys()
1191
   *
1192
   * @return static <p>(Immutable)</p>
1193
   */
1194 1
  public function getKeys()
1195
  {
1196 1
    return $this->keys();
1197
  }
1198
1199
  /**
1200
   * alias: for "Arrayy->randomImmutable()"
1201
   *
1202
   * @see Arrayy::randomImmutable()
1203
   *
1204
   * @return static <p>(Immutable)</p>
1205
   */
1206 3
  public function getRandom()
1207
  {
1208 3
    return $this->randomImmutable();
1209
  }
1210
1211
  /**
1212
   * alias: for "Arrayy->randomKey()"
1213
   *
1214
   * @see Arrayy::randomKey()
1215
   *
1216
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1217
   */
1218 3
  public function getRandomKey()
1219
  {
1220 3
    return $this->randomKey();
1221
  }
1222
1223
  /**
1224
   * alias: for "Arrayy->randomKeys()"
1225
   *
1226
   * @see Arrayy::randomKeys()
1227
   *
1228
   * @param int $number
1229
   *
1230
   * @return static <p>(Immutable)</p>
1231
   */
1232 9
  public function getRandomKeys($number)
1233
  {
1234 9
    return $this->randomKeys($number);
1235
  }
1236
1237
  /**
1238
   * alias: for "Arrayy->randomValue()"
1239
   *
1240
   * @see Arrayy::randomValue()
1241
   *
1242
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1243
   */
1244 3
  public function getRandomValue()
1245
  {
1246 3
    return $this->randomValue();
1247
  }
1248
1249
  /**
1250
   * alias: for "Arrayy->randomValues()"
1251
   *
1252
   * @see Arrayy::randomValues()
1253
   *
1254
   * @param int $number
1255
   *
1256
   * @return static <p>(Immutable)</p>
1257
   */
1258 6
  public function getRandomValues($number)
1259
  {
1260 6
    return $this->randomValues($number);
1261
  }
1262
1263
  /**
1264
   * Group values from a array according to the results of a closure.
1265
   *
1266
   * @param string $grouper <p>A callable function name.</p>
1267
   * @param bool   $saveKeys
1268
   *
1269
   * @return static <p>(Immutable)</p>
1270
   */
1271 3
  public function group($grouper, $saveKeys = false)
1272
  {
1273 3
    $array = (array)$this->array;
1274 3
    $result = array();
1275
1276
    // Iterate over values, group by property/results from closure
1277 3
    foreach ($array as $key => $value) {
1278
1279 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1280 3
      $newValue = $this->get($groupKey, null, $result);
1281
1282 3
      if ($groupKey instanceof self) {
1283
        $groupKey = $groupKey->getArray();
1284
      }
1285
1286 3
      if ($newValue instanceof self) {
1287 3
        $newValue = $newValue->getArray();
1288 3
      }
1289
1290
      // Add to results
1291 3
      if ($groupKey !== null) {
1292 2
        if ($saveKeys) {
1293 1
          $result[$groupKey] = $newValue;
1294 1
          $result[$groupKey][$key] = $value;
1295 1
        } else {
1296 1
          $result[$groupKey] = $newValue;
1297 1
          $result[$groupKey][] = $value;
1298
        }
1299 2
      }
1300
1301 3
    }
1302
1303 3
    return static::create($result);
1304
  }
1305
1306
  /**
1307
   * Check if an array has a given key.
1308
   *
1309
   * @param mixed $key
1310
   *
1311
   * @return bool
1312
   */
1313 22
  public function has($key)
1314
  {
1315
    // Generate unique string to use as marker.
1316 22
    $unFound = (string)uniqid('arrayy', true);
1317
1318 22
    return $this->get($key, $unFound) !== $unFound;
1319
  }
1320
1321
  /**
1322
   * Implodes an array.
1323
   *
1324
   * @param string $glue
1325
   *
1326
   * @return string
1327
   */
1328 27
  public function implode($glue = '')
1329
  {
1330 27
    return implode($glue, $this->array);
1331
  }
1332
1333
  /**
1334
   * Given a list and an iterate-function that returns
1335
   * a key for each element in the list (or a property name),
1336
   * returns an object with an index of each item.
1337
   *
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 3
  public function indexBy($key)
1345
  {
1346 3
    $results = array();
1347
1348 3
    foreach ($this->array as $a) {
1349 3
      if (\array_key_exists($key, $a) === true) {
1350 2
        $results[$a[$key]] = $a;
1351 2
      }
1352 3
    }
1353
1354 3
    return static::create($results);
1355
  }
1356
1357
  /**
1358
   * alias: for "Arrayy->searchIndex()"
1359
   *
1360
   * @see Arrayy::searchIndex()
1361
   *
1362
   * @param mixed $value <p>The value to search for.</p>
1363
   *
1364
   * @return mixed
1365
   */
1366 4
  public function indexOf($value)
1367
  {
1368 4
    return $this->searchIndex($value);
1369
  }
1370
1371
  /**
1372
   * Get everything but the last..$to items.
1373
   *
1374
   * @param int $to
1375
   *
1376
   * @return static <p>(Immutable)</p>
1377
   */
1378 12
  public function initial($to = 1)
1379
  {
1380 12
    $slice = count($this->array) - $to;
1381
1382 12
    return $this->firstsImmutable($slice);
1383
  }
1384
1385
  /**
1386
   * Internal mechanics of remove method.
1387
   *
1388
   * @param string $key
1389
   *
1390
   * @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 18
    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
    }
1406
1407 18
    $key = \array_shift($path);
1408
1409 18
    unset($this->array[$key]);
1410
1411 18
    return true;
1412
  }
1413
1414
  /**
1415
   * Internal mechanic of set method.
1416
   *
1417
   * @param string $key
1418
   * @param mixed  $value
1419
   *
1420
   * @return bool
1421
   */
1422 28
  protected function internalSet($key, $value)
1423
  {
1424 28
    if ($key === null) {
1425
      return false;
1426
    }
1427
1428
    // init
1429 28
    $array =& $this->array;
1430 28
    $path = explode($this->pathSeparator, (string)$key);
1431
1432
    // Crawl through the keys
1433 28
    while (count($path) > 1) {
1434 2
      $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 2
      if (!isset($array[$key]) || !is_array($array[$key])) {
1440
        $array[$key] = static::create(array());
1441
      }
1442
1443 2
      $array =& $array[$key];
1444 2
    }
1445
1446 28
    $array[\array_shift($path)] = $value;
1447
1448 28
    return true;
1449
  }
1450
1451
  /**
1452
   * Return an array with all elements found in input array.
1453
   *
1454
   * @param array $search
1455
   *
1456
   * @return static <p>(Immutable)</p>
1457
   */
1458 2
  public function intersection(array $search)
1459
  {
1460 2
    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
   * @param array $search
1467
   *
1468
   * @return bool
1469
   */
1470 1
  public function intersects(array $search)
1471
  {
1472 1
    return count($this->intersection($search)->array) > 0;
1473
  }
1474
1475
  /**
1476
   * Invoke a function on all of an array's values.
1477
   *
1478
   * @param mixed $callable
1479
   * @param mixed $arguments
1480
   *
1481
   * @return static <p>(Immutable)</p>
1482
   */
1483 1
  public function invoke($callable, $arguments = array())
1484
  {
1485
    // If one argument given for each iteration, create an array for it.
1486 1
    if (!is_array($arguments)) {
1487 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1488 1
    }
1489
1490
    // If the callable has arguments, pass them.
1491 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...
1492 1
      $array = \array_map($callable, $this->array, $arguments);
1493 1
    } else {
1494 1
      $array = \array_map($callable, $this->array);
1495
    }
1496
1497 1
    return static::create($array);
1498
  }
1499
1500
  /**
1501
   * Check whether array is associative or not.
1502
   *
1503
   * @return bool <p>Returns true if associative, false otherwise.</p>
1504
   */
1505 15
  public function isAssoc()
1506
  {
1507 15
    if ($this->isEmpty()) {
1508 3
      return false;
1509
    }
1510
1511 13
    foreach ($this->keys()->getArray() as $key) {
1512 13
      if (!is_string($key)) {
1513 11
        return false;
1514
      }
1515 3
    }
1516
1517 3
    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 85
  public function isEmpty()
1526
  {
1527 85
    return !$this->array;
1528
  }
1529
1530
  /**
1531
   * Check if the current array is equal to the given "$array" or not.
1532
   *
1533
   * @param array $array
1534
   *
1535
   * @return bool
1536
   */
1537
  public function isEqual(array $array)
1538
  {
1539
    return ($this->array === $array);
1540
  }
1541
1542
  /**
1543
   * Check if the current array is a multi-array.
1544
   *
1545
   * @return bool
1546
   */
1547 14
  public function isMultiArray()
1548
  {
1549 14
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1550
  }
1551
1552
  /**
1553
   * Check whether array is numeric or not.
1554
   *
1555
   * @return bool <p>Returns true if numeric, false otherwise.</p>
1556
   */
1557 5
  public function isNumeric()
1558
  {
1559 5
    if ($this->isEmpty()) {
1560 2
      return false;
1561
    }
1562
1563 4
    foreach ($this->keys() as $key) {
1564 4
      if (!is_int($key)) {
1565 2
        return false;
1566
      }
1567 3
    }
1568
1569 2
    return true;
1570
  }
1571
1572
  /**
1573
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1574
   *
1575
   * @return bool
1576
   */
1577 1
  public function isSequential()
1578
  {
1579 1
    return \array_keys($this->array) === range(0, count($this->array) - 1);
1580
  }
1581
1582
  /**
1583
   * Get all keys from the current array.
1584
   *
1585
   * @return static <p>(Immutable)</p>
1586
   */
1587 25
  public function keys()
1588
  {
1589 25
    return static::create(\array_keys($this->array));
1590
  }
1591
1592
  /**
1593
   * Get the last value from the current array.
1594
   *
1595
   * @return mixed <p>Return null if there wasn't a element.</p>
1596
   */
1597 4
  public function last()
1598
  {
1599 4
    return $this->pop();
1600
  }
1601
1602
  /**
1603
   * Get the last value(s) from the current array.
1604
   *
1605
   * @param int|null $number
1606
   *
1607
   * @return static <p>(Immutable)</p>
1608
   */
1609 13
  public function lastsImmutable($number = null)
1610
  {
1611 13
    if ($this->isEmpty()) {
1612 1
      return static::create();
1613
    }
1614
1615 12
    if ($number === null) {
1616 8
      $poppedValue = $this->pop();
1617
1618 8
      if ($poppedValue === null) {
1619 1
        $poppedValue = array($poppedValue);
1620 1
      } else {
1621 7
        $poppedValue = (array)$poppedValue;
1622
      }
1623
1624 8
      $arrayy = static::create($poppedValue);
1625 8
    } else {
1626 4
      $number = (int)$number;
1627 4
      $arrayy = $this->rest(-$number);
1628
    }
1629
1630 12
    return $arrayy;
1631
  }
1632
1633
  /**
1634
   * Get the last value(s) from the current array.
1635
   *
1636
   * @param int|null $number
1637
   *
1638
   * @return static <p>(Mutable)</p>
1639
   */
1640 13
  public function lastsMutable($number = null)
1641
  {
1642 13
    if ($this->isEmpty()) {
1643 1
      return $this;
1644
    }
1645
1646 12
    if ($number === null) {
1647 8
      $poppedValue = $this->pop();
1648
1649 8
      if ($poppedValue === null) {
1650 1
        $poppedValue = array($poppedValue);
1651 1
      } else {
1652 7
        $poppedValue = (array)$poppedValue;
1653
      }
1654
1655 8
      $this->array = static::create($poppedValue)->array;
1656 8
    } else {
1657 4
      $number = (int)$number;
1658 4
      $this->array = $this->rest(-$number)->array;
1659
    }
1660
1661 12
    return $this;
1662
  }
1663
1664
  /**
1665
   * Count the values from the current array.
1666
   *
1667
   * alias: for "Arrayy->size()"
1668
   *
1669
   * @see Arrayy::size()
1670
   *
1671
   * @return int
1672
   */
1673 10
  public function length()
1674
  {
1675 10
    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
   *
1684
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
1685
   */
1686 4
  public function map($callable)
1687
  {
1688 4
    $result = \array_map($callable, $this->array);
1689
1690 4
    return static::create($result);
1691
  }
1692
1693
  /**
1694
   * Check if all items in current array match a truth test.
1695
   *
1696
   * @param \Closure $closure
1697
   *
1698
   * @return bool
1699
   */
1700 15 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 15
    if (count($this->array) === 0) {
1703 2
      return false;
1704
    }
1705
1706
    // init
1707 13
    $array = $this->array;
1708
1709 13
    foreach ($array as $key => $value) {
1710 13
      $value = $closure($value, $key);
1711
1712 13
      if ($value === false) {
1713 7
        return false;
1714
      }
1715 9
    }
1716
1717 7
    return true;
1718
  }
1719
1720
  /**
1721
   * Check if any item in the current array matches a truth test.
1722
   *
1723
   * @param \Closure $closure
1724
   *
1725
   * @return bool
1726
   */
1727 14 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 14
    if (count($this->array) === 0) {
1730 2
      return false;
1731
    }
1732
1733
    // init
1734 12
    $array = $this->array;
1735
1736 12
    foreach ($array as $key => $value) {
1737 12
      $value = $closure($value, $key);
1738
1739 12
      if ($value === true) {
1740 9
        return true;
1741
      }
1742 5
    }
1743
1744 4
    return false;
1745
  }
1746
1747
  /**
1748
   * Get the max value from an array.
1749
   *
1750
   * @return mixed
1751
   */
1752 10
  public function max()
1753
  {
1754 10
    if ($this->count() === 0) {
1755 1
      return false;
1756
    }
1757
1758 9
    return max($this->array);
1759
  }
1760
1761
  /**
1762
   * 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 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...
1772
  {
1773 25
    if (true === $recursive) {
1774 4
      $result = \array_replace_recursive($this->array, $array);
1775 4
    } else {
1776 21
      $result = \array_replace($this->array, $array);
1777
    }
1778
1779 25
    return static::create($result);
1780
  }
1781
1782
  /**
1783
   * Merge the new $array into the current array.
1784
   *
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 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...
1794
  {
1795 16
    if (true === $recursive) {
1796 4
      $result = \array_merge_recursive($this->array, $array);
1797 4
    } else {
1798 12
      $result = \array_merge($this->array, $array);
1799
    }
1800
1801 16
    return static::create($result);
1802
  }
1803
1804
  /**
1805
   * 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 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...
1815
  {
1816 16
    if (true === $recursive) {
1817 4
      $result = \array_replace_recursive($array, $this->array);
1818 4
    } else {
1819 12
      $result = \array_replace($array, $this->array);
1820
    }
1821
1822 16
    return static::create($result);
1823
  }
1824
1825
  /**
1826
   * Merge the current array into the new $array.
1827
   *
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
   */
1836 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...
1837
  {
1838 16
    if (true === $recursive) {
1839 4
      $result = \array_merge_recursive($array, $this->array);
1840 4
    } else {
1841 12
      $result = \array_merge($array, $this->array);
1842
    }
1843
1844 16
    return static::create($result);
1845
  }
1846
1847
  /**
1848
   * Get the min value from an array.
1849
   *
1850
   * @return mixed
1851
   */
1852 10
  public function min()
1853
  {
1854 10
    if ($this->count() === 0) {
1855 1
      return false;
1856
    }
1857
1858 9
    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
   * @return static <p>(Immutable)</p>
1867
   */
1868
  public function only(array $keys)
1869
  {
1870
    $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
   * @param int   $size  <p>Size of the result array.</p>
1879
   * @param mixed $value <p>Empty value by default.</p>
1880
   *
1881
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
1882
   */
1883 4
  public function pad($size, $value)
1884
  {
1885 4
    $result = \array_pad($this->array, $size, $value);
1886
1887 4
    return static::create($result);
1888
  }
1889
1890
  /**
1891
   * Pop a specified value off the end of the current array.
1892
   *
1893
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
1894
   */
1895 16
  public function pop()
1896
  {
1897 16
    return \array_pop($this->array);
1898
  }
1899
1900
  /**
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 8
  public function prepend($value, $key = null)
1909
  {
1910 8
    if ($key === null) {
1911 8
      \array_unshift($this->array, $value);
1912 8
    } else {
1913
      /** @noinspection AdditionOperationOnArraysInspection */
1914 1
      $this->array = array($key => $value) + $this->array;
1915
    }
1916
1917 8
    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 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...
1926
  {
1927 4
    if (func_num_args()) {
1928 4
      $args = \array_merge(array(&$this->array), func_get_args());
1929 4
      call_user_func_array('array_push', $args);
1930 4
    }
1931
1932 4
    return $this;
1933
  }
1934
1935
  /**
1936
   * Get a random value from the current array.
1937
   *
1938
   * @param null|int $number <p>How many values you will take?</p>
1939
   *
1940
   * @return static <p>(Immutable)</p>
1941
   */
1942 17
  public function randomImmutable($number = null)
1943
  {
1944 17
    if ($this->count() === 0) {
1945
      return static::create();
1946
    }
1947
1948 17 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 14
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
1950
1951 14
      return static::create($arrayRandValue);
1952
    }
1953
1954 5
    $arrayTmp = $this->array;
1955 5
    shuffle($arrayTmp);
1956
1957 5
    return static::create($arrayTmp)->firstsImmutable($number);
1958
  }
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 4
  public function randomKey()
1968
  {
1969 4
    $result = $this->randomKeys(1);
1970
1971 4
    if (!isset($result[0])) {
1972
      $result[0] = null;
1973
    }
1974
1975 4
    return $result[0];
1976
  }
1977
1978
  /**
1979
   * Pick a given number of random keys/indexes out of this array.
1980
   *
1981
   * @param int $number <p>The number of keys/indexes (should be <= $this->count())</p>
1982
   *
1983
   * @return static <p>(Immutable)</p>
1984
   *
1985
   * @throws \RangeException If array is empty
1986
   */
1987 14
  public function randomKeys($number)
1988
  {
1989 14
    $number = (int)$number;
1990 14
    $count = $this->count();
1991
1992 14
    if ($number === 0 || $number > $count) {
1993 3
      throw new \RangeException(
1994 3
          sprintf(
1995 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1996 3
              $number,
1997
              $count
1998 3
          )
1999 3
      );
2000
    }
2001
2002 11
    $result = (array)\array_rand($this->array, $number);
2003
2004 11
    return static::create($result);
2005
  }
2006
2007
  /**
2008
   * Get a random value from the current array.
2009
   *
2010
   * @param null|int $number <p>How many values you will take?</p>
2011
   *
2012
   * @return static <p>(Mutable)</p>
2013
   */
2014 17
  public function randomMutable($number = null)
2015
  {
2016 17
    if ($this->count() === 0) {
2017
      return static::create();
2018
    }
2019
2020 17 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 7
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2022 7
      $this->array = $arrayRandValue;
2023
2024 7
      return $this;
2025
    }
2026
2027 11
    shuffle($this->array);
2028
2029 11
    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 4
  public function randomValue()
2038
  {
2039 4
    $result = $this->randomImmutable();
2040
2041 4
    if (!isset($result[0])) {
2042
      $result[0] = null;
2043
    }
2044
2045 4
    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 7
  public function randomValues($number)
2056
  {
2057 7
    $number = (int)$number;
2058
2059 7
    return $this->randomMutable($number);
2060
  }
2061
2062
  /**
2063
   * Get a random value from an array, with the ability to skew the results.
2064
   *
2065
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2066
   *
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 9
  public function randomWeighted(array $array, $number = null)
2073
  {
2074 9
    $options = array();
2075 9
    foreach ($array as $option => $weight) {
2076 9
      if ($this->searchIndex($option) !== false) {
2077 2
        for ($i = 0; $i < $weight; ++$i) {
2078 1
          $options[] = $option;
2079 1
        }
2080 2
      }
2081 9
    }
2082
2083 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2084
  }
2085
2086
  /**
2087
   * 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 3
  public function reduce($callable, array $init = array())
2095
  {
2096 3
    $result = \array_reduce($this->array, $callable, $init);
2097
2098 3
    if ($result === null) {
2099
      $this->array = array();
2100
    } else {
2101 3
      $this->array = (array)$result;
2102
    }
2103
2104 3
    return static::create($this->array);
2105
  }
2106
2107
  /**
2108
   * Create a numerically re-indexed Arrayy object.
2109
   *
2110
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2111
   */
2112 9
  public function reindex()
2113
  {
2114 9
    $this->array = \array_values($this->array);
2115
2116 9
    return $this;
2117
  }
2118
2119
  /**
2120
   * Return all items that fail the truth test.
2121
   *
2122
   * @param \Closure $closure
2123
   *
2124
   * @return static <p>(Immutable)</p>
2125
   */
2126 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...
2127
  {
2128 1
    $filtered = array();
2129
2130 1
    foreach ($this->array as $key => $value) {
2131 1
      if (!$closure($value, $key)) {
2132 1
        $filtered[$key] = $value;
2133 1
      }
2134 1
    }
2135
2136 1
    return static::create($filtered);
2137
  }
2138
2139
  /**
2140
   * Remove a value from the current array (optional using dot-notation).
2141
   *
2142
   * @param mixed $key
2143
   *
2144
   * @return static <p>(Immutable)</p>
2145
   */
2146 18
  public function remove($key)
2147
  {
2148
    // Recursive call
2149 18
    if (is_array($key)) {
2150
      foreach ($key as $k) {
2151
        $this->internalRemove($k);
2152
      }
2153
2154
      return static::create($this->array);
2155
    }
2156
2157 18
    $this->internalRemove($key);
2158
2159 18
    return static::create($this->array);
2160
  }
2161
2162
  /**
2163
   * Remove the first value from the current array.
2164
   *
2165
   * @return static <p>(Immutable)</p>
2166
   */
2167 7
  public function removeFirst()
2168
  {
2169 7
    $tmpArray = $this->array;
2170 7
    \array_shift($tmpArray);
2171
2172 7
    return static::create($tmpArray);
2173
  }
2174
2175
  /**
2176
   * Remove the last value from the current array.
2177
   *
2178
   * @return static <p>(Immutable)</p>
2179
   */
2180 7
  public function removeLast()
2181
  {
2182 7
    $tmpArray = $this->array;
2183 7
    \array_pop($tmpArray);
2184
2185 7
    return static::create($tmpArray);
2186
  }
2187
2188
  /**
2189
   * Removes a particular value from an array (numeric or associative).
2190
   *
2191
   * @param mixed $value
2192
   *
2193
   * @return static <p>(Immutable)</p>
2194
   */
2195 7
  public function removeValue($value)
2196
  {
2197 7
    $isNumericArray = true;
2198 7
    foreach ($this->array as $key => $item) {
2199 6
      if ($item === $value) {
2200 6
        if (!is_int($key)) {
2201
          $isNumericArray = false;
2202
        }
2203 6
        unset($this->array[$key]);
2204 6
      }
2205 7
    }
2206
2207 7
    if ($isNumericArray) {
2208 7
      $this->array = \array_values($this->array);
2209 7
    }
2210
2211 7
    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
   *
2221
   * @return static <p>(Immutable)</p>
2222
   */
2223 2
  public function replace($replace, $key, $value)
2224
  {
2225 2
    $this->remove($replace);
2226
2227 2
    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
   *
2235
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
2236
   */
2237 2
  public function replaceAllKeys(array $keys)
2238
  {
2239 2
    $result = \array_combine($keys, $this->array);
2240
2241 2
    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
   *
2249
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
2250
   */
2251 2
  public function replaceAllValues(array $array)
2252
  {
2253 2
    $result = \array_combine($this->array, $array);
2254
2255 2
    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
   */
2265 1
  public function replaceKeys(array $keys)
2266
  {
2267 1
    $values = \array_values($this->array);
2268 1
    $result = \array_combine($keys, $values);
2269
2270 1
    return static::create($result);
2271
  }
2272
2273
  /**
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 3
  public function replaceOneValue($search, $replacement = '')
2282
  {
2283 3
    $array = $this->array;
2284 3
    $key = \array_search($search, $array, true);
2285
2286 3
    if ($key !== false) {
2287 3
      $array[$key] = $replacement;
2288 3
    }
2289
2290 3
    return static::create($array);
2291
  }
2292
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 1
  public function replaceValues($search, $replacement = '')
2302
  {
2303 1
    $array = $this->each(
2304
        function ($value) use ($search, $replacement) {
2305 1
          return UTF8::str_replace($search, $replacement, $value);
2306
        }
2307 1
    );
2308
2309 1
    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 15
  public function rest($from = 1)
2320
  {
2321 15
    $tmpArray = $this->array;
2322
2323 15
    return static::create(\array_splice($tmpArray, $from));
2324
  }
2325
2326
  /**
2327
   * Move an array element to a new index.
2328
   *
2329
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2330
   *
2331
   * @param int|string $from
2332
   * @param int|string $to
2333
   *
2334
   * @return static <p>(Immutable)</p>
2335
   */
2336 1
  public function moveElement($from, $to)
2337
  {
2338 1
    $array = $this->array;
2339
2340 1
    if (is_int($from)) {
2341 1
      $tmp = \array_splice($array, $from, 1);
2342 1
      \array_splice($array, $to, 0, $tmp);
2343 1
      $output = $array;
2344 1
    } elseif (is_string($from)) {
2345 1
      $indexToMove = \array_search($from, \array_keys($array), true);
2346 1
      $itemToMove = $array[$from];
2347 1
      \array_splice($array, $indexToMove, 1);
2348 1
      $i = 0;
2349 1
      $output = array();
2350 1
      foreach ($array as $key => $item) {
2351 1
        if ($i == $to) {
2352 1
          $output[$from] = $itemToMove;
2353 1
        }
2354 1
        $output[$key] = $item;
2355 1
        $i++;
2356 1
      }
2357 1
    } else {
2358
      $output = array();
2359
    }
2360
2361 1
    return static::create($output);
2362
  }
2363
2364
  /**
2365
   * Return the array in the reverse order.
2366
   *
2367
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2368
   */
2369 7
  public function reverse()
2370
  {
2371 7
    $this->array = \array_reverse($this->array);
2372
2373 7
    return $this;
2374
  }
2375
2376
  /**
2377
   * Search for the first index of the current array via $value.
2378
   *
2379
   * @param mixed $value
2380
   *
2381
   * @return int|float|string
2382
   */
2383 20
  public function searchIndex($value)
2384
  {
2385 20
    return \array_search($value, $this->array, true);
2386
  }
2387
2388
  /**
2389
   * Search for the value of the current array via $index.
2390
   *
2391
   * @param mixed $index
2392
   *
2393
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
2394
   */
2395 9
  public function searchValue($index)
2396
  {
2397
    // init
2398 9
    $return = array();
2399
2400 9
    if ($this->isEmpty()) {
2401
      return static::create();
2402
    }
2403
2404
    // php cast "bool"-index into "int"-index
2405 9
    if ((bool)$index === $index) {
2406 1
      $index = (int)$index;
2407 1
    }
2408
2409 9
    if (\array_key_exists($index, $this->array) === true) {
2410 7
      $return = array($this->array[$index]);
2411 7
    }
2412
2413
2414 9
    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 17
  public function set($key, $value)
2426
  {
2427 17
    $this->internalSet($key, $value);
2428
2429 17
    return static::create($this->array);
2430
  }
2431
2432
  /**
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
   * @return mixed <p>(Mutable)</p>
2441
   */
2442 11
  public function setAndGet($key, $fallback = null)
2443
  {
2444
    // If the key doesn't exist, set it.
2445 11
    if (!$this->has($key)) {
2446 4
      $this->array = $this->set($key, $fallback)->getArray();
2447 4
    }
2448
2449 11
    return $this->get($key);
2450
  }
2451
2452
  /**
2453
   * Shifts a specified value off the beginning of array.
2454
   *
2455
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
2456
   */
2457 4
  public function shift()
2458
  {
2459 4
    return \array_shift($this->array);
2460
  }
2461
2462
  /**
2463
   * Shuffle the current array.
2464
   *
2465
   * @return static <p>(Immutable)</p>
2466
   */
2467 1
  public function shuffle()
2468
  {
2469 1
    $array = $this->array;
2470
2471 1
    shuffle($array);
2472
2473 1
    return static::create($array);
2474
  }
2475
2476
  /**
2477
   * Get the size of an array.
2478
   *
2479
   * @return int
2480
   */
2481 93
  public function size()
2482
  {
2483 93
    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
   */
2495 4
  public function slice($offset, $length = null, $preserveKeys = false)
2496
  {
2497 4
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
2498
2499 4
    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 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2512
  {
2513 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2514
2515 19
    return $this;
2516
  }
2517
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
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2529
   */
2530 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2531
  {
2532 18
    $this->sorterKeys($this->array, $direction, $strategy);
2533
2534 18
    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
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2542
   *
2543
   * @return static <p>(Immutable)</p>
2544
   */
2545 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2546
  {
2547 1
    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 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2559
  {
2560 1
    return $this->sort($direction, $strategy, false);
2561
  }
2562
2563
  /**
2564
   * Sort a array by value, by a closure or by a property.
2565
   *
2566
   * - 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
   *
2569
   * @param null       $sorter
2570
   * @param string|int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2571
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2572
   *                              <strong>SORT_NATURAL</strong></p>
2573
   *
2574
   * @return static <p>(Immutable)</p>
2575
   */
2576 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2577
  {
2578 1
    $array = (array)$this->array;
2579 1
    $direction = $this->getDirection($direction);
2580
2581
    // Transform all values into their results.
2582 1
    if ($sorter) {
2583 1
      $arrayy = static::create($array);
2584
2585 1
      $that = $this;
2586 1
      $results = $arrayy->each(
2587
          function ($value) use ($sorter, $that) {
2588 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2589
          }
2590 1
      );
2591
2592 1
      $results = $results->getArray();
2593 1
    } else {
2594 1
      $results = $array;
2595
    }
2596
2597
    // Sort by the results and replace by original values
2598 1
    \array_multisort($results, $direction, $strategy, $array);
2599
2600 1
    return static::create($array);
2601
  }
2602
2603
  /**
2604
   * sorting keys
2605
   *
2606
   * @param array $elements
2607
   * @param int   $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2608
   * @param int   $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2609
   *
2610
   * @return void <p>Mutable</p>
2611
   */
2612 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2613
  {
2614 18
    $direction = $this->getDirection($direction);
2615
2616
    switch ($direction) {
2617 18
      case 'desc':
2618 18
      case SORT_DESC:
2619 6
        krsort($elements, $strategy);
2620 6
        break;
2621 13
      case 'asc':
2622 13
      case SORT_ASC:
2623 13
      default:
2624 13
        ksort($elements, $strategy);
2625 13
    }
2626 18
  }
2627
2628
  /**
2629
   * @param array      &$elements
2630
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2631
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2632
   *                              <strong>SORT_NATURAL</strong></p>
2633
   * @param bool       $keepKeys
2634
   *
2635
   * @return void <p>Mutable</p>
2636
   */
2637 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2638
  {
2639 19
    $direction = $this->getDirection($direction);
2640
2641 19
    if (!$strategy) {
2642 19
      $strategy = SORT_REGULAR;
2643 19
    }
2644
2645
    switch ($direction) {
2646 19
      case 'desc':
2647 19
      case SORT_DESC:
2648 9
        if ($keepKeys) {
2649 5
          arsort($elements, $strategy);
2650 5
        } else {
2651 4
          rsort($elements, $strategy);
2652
        }
2653 9
        break;
2654 10
      case 'asc':
2655 10
      case SORT_ASC:
2656 10
      default:
2657 10
        if ($keepKeys) {
2658 4
          asort($elements, $strategy);
2659 4
        } else {
2660 6
          sort($elements, $strategy);
2661
        }
2662 10
    }
2663 19
  }
2664
2665
  /**
2666
   * Split an array in the given amount of pieces.
2667
   *
2668
   * @param int  $numberOfPieces
2669
   * @param bool $keepKeys
2670
   *
2671
   * @return static <p>(Immutable)</p>
2672
   */
2673 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2674
  {
2675 1
    $arrayCount = $this->count();
2676
2677 1
    if ($arrayCount === 0) {
2678 1
      $result = array();
2679 1
    } else {
2680 1
      $numberOfPieces = (int)$numberOfPieces;
2681 1
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
2682 1
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
2683
    }
2684
2685 1
    return static::create($result);
2686
  }
2687
2688
  /**
2689
   * Stripe all empty items.
2690
   *
2691
   * @return static <p>(Immutable)</p>
2692
   */
2693 1
  public function stripEmpty()
2694
  {
2695 1
    return $this->filter(
2696
        function ($item) {
2697 1
          if ($item === null) {
2698 1
            return false;
2699
          }
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
   *
2712
   * @return static <p>(Immutable)</p>
2713
   */
2714 1
  public function swap($swapA, $swapB)
2715
  {
2716 1
    $array = $this->array;
2717
2718 1
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
2719
2720 1
    return static::create($array);
2721
  }
2722
2723
  /**
2724
   * alias: for "Arrayy->getArray()"
2725
   *
2726
   * @see Arrayy::getArray()
2727
   */
2728 141
  public function toArray()
2729
  {
2730 141
    return $this->getArray();
2731
  }
2732
2733
  /**
2734
   * Convert the current array to JSON.
2735
   *
2736
   * @param null|int $options <p>e.g. JSON_PRETTY_PRINT</p>
2737
   *
2738
   * @return string
2739
   */
2740 5
  public function toJson($options = null)
2741
  {
2742 5
    return UTF8::json_encode($this->array, $options);
2743
  }
2744
2745
  /**
2746
   * Implodes array to a string with specified separator.
2747
   *
2748
   * @param string $separator <p>The element's separator.</p>
2749
   *
2750
   * @return string <p>The string representation of array, separated by ",".</p>
2751
   */
2752 19
  public function toString($separator = ',')
2753
  {
2754 19
    return $this->implode($separator);
2755
  }
2756
2757
  /**
2758
   * alias: for "Arrayy->unique()"
2759
   *
2760
   * @see Arrayy::unique()
2761
   *
2762
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
2763
   */
2764 9
  public function uniqueNewIndex()
2765
  {
2766 9
    return $this->unique();
2767
  }
2768
2769
  /**
2770
   * Return a duplicate free copy of the current array.
2771
   *
2772
   * @return static <p>(Mutable)</p>
2773
   */
2774 9
  public function unique()
2775
  {
2776 9
    $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 8
          if (!in_array($value, $resultArray, true)) {
2780 8
            $resultArray[] = $value;
2781 8
          }
2782
2783 8
          return $resultArray;
2784 9
        },
2785 9
        array()
2786 9
    );
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
    } else {
2791 9
      $this->array = (array)$this->array;
2792
    }
2793
2794 9
    return $this;
2795
  }
2796
2797
  /**
2798
   * Return a duplicate free copy of the current array. (with the old keys)
2799
   *
2800
   * @return static <p>(Mutable)</p>
2801
   */
2802 9
  public function uniqueKeepIndex()
2803
  {
2804
    // init
2805 9
    $array = $this->array;
2806
2807 9
    $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 9
        function ($resultArray, $key) use ($array) {
2810 8
          if (!in_array($array[$key], $resultArray, true)) {
2811 8
            $resultArray[$key] = $array[$key];
2812 8
          }
2813
2814 8
          return $resultArray;
2815 9
        },
2816 9
        array()
2817 9
    );
2818
2819 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...
2820
      $this->array = array();
2821
    } else {
2822 9
      $this->array = (array)$this->array;
2823
    }
2824
2825 9
    return $this;
2826
  }
2827
2828
  /**
2829
   * Prepends one or more values to the beginning of array at once.
2830
   *
2831
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
2832
   */
2833 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...
2834
  {
2835 4
    if (func_num_args()) {
2836 4
      $args = \array_merge(array(&$this->array), func_get_args());
2837 4
      call_user_func_array('array_unshift', $args);
2838 4
    }
2839
2840 4
    return $this;
2841
  }
2842
2843
  /**
2844
   * Get all values from a array.
2845
   *
2846
   * @return static <p>(Immutable)</p>
2847
   */
2848 2
  public function values()
2849
  {
2850 2
    return static::create(\array_values((array)$this->array));
2851
  }
2852
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 9
  public function walk($callable, $recursive = false)
2862
  {
2863 9
    if (true === $recursive) {
2864 4
      \array_walk_recursive($this->array, $callable);
2865 4
    } else {
2866 5
      \array_walk($this->array, $callable);
2867
    }
2868
2869 9
    return $this;
2870
  }
2871
2872
}
2873