Completed
Push — master ( a09856...04b4ed )
by Lars
15:01
created

Arrayy::changeKeyCase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
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
   * Changes all keys in an array.
284
   *
285
   * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
286
   *                  or <strong>CASE_LOWER</strong> (default)</p>
287 2
   *
288
   * @return static <p>(Immutable)</p>
289 2
   */
290
  public function changeKeyCase($case = CASE_LOWER)
291
  {
292
    return static::create(UTF8::array_change_key_case($this->array, $case));
0 ignored issues
show
Bug introduced by
The method array_change_key_case() does not seem to exist on object<voku\helper\UTF8>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
293
  }
294
295
  /**
296
   * Serialize the current array.
297
   *
298
   * @return string
299 2
   */
300
  public function serialize()
301 2
  {
302
    return serialize($this->array);
303 2
  }
304
305
  /**
306
   * Unserialize an string and return this object.
307
   *
308
   * @param string $string
309
   *
310
   * @return static <p>(Mutable)</p>
311
   */
312
  public function unserialize($string)
313 2
  {
314
    $this->array = unserialize($string);
315 2
316
    return $this;
317 2
  }
318 2
319 2
  /**
320
   * Iterate over the current array and execute a callback for each loop.
321 2
   *
322
   * @param \Closure $closure
323
   *
324
   * @return static <p>(Immutable)</p>
325
   */
326 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...
327
  {
328
    $array = $this->array;
329
330
    foreach ($array as $key => $value) {
331 10
      $closure($value, $key);
332
    }
333 10
334
    return static::create($array);
335 10
  }
336 2
337
  /**
338
   * Returns the average value of the current array.
339 8
   *
340 3
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
341 3
   *
342
   * @return int|double <p>The average value.</p>
343 8
   */
344
  public function average($decimals = 0)
345
  {
346
    $count = $this->count();
347
348
    if (!$count) {
349
      return 0;
350
    }
351 2
352
    if (!is_int($decimals)) {
353 2
      $decimals = 0;
354 2
    }
355 2
356
    return round(\array_sum($this->array) / $count, $decimals);
357 2
  }
358 2
359
  /**
360 2
   * @param mixed      $path
361
   * @param callable   $callable
362
   * @param null|array $currentOffset
363
   */
364 2
  protected function callAtPath($path, $callable, &$currentOffset = null)
365
  {
366
    if ($currentOffset === null) {
367
      $currentOffset = &$this->array;
368
    }
369
370
    $explodedPath = explode($this->pathSeparator, $path);
371 2
    $nextPath = \array_shift($explodedPath);
372
373 2
    if (!isset($currentOffset[$nextPath])) {
374
      return;
375
    }
376
377
    if (!empty($explodedPath)) {
378
      $this->callAtPath(
379
          implode($this->pathSeparator, $explodedPath),
380
          $callable,
381
          $currentOffset[$nextPath]
382
      );
383
    } else {
384
      $callable($currentOffset[$nextPath]);
385
    }
386
  }
387
388
  /**
389
   * Change the path separator of the array wrapper.
390
   *
391
   * By default, the separator is: "."
392
   *
393
   * @param string $separator <p>Separator to set.</p>
394
   *
395
   * @return static <p>Mutable</p>
396
   */
397
  public function changeSeparator($separator)
398
  {
399 4
    $this->pathSeparator = $separator;
400
401 4
    return $this;
402
  }
403 4
404
  /**
405
   * Create a chunked version of the current array.
406
   *
407
   * @param int  $size         <p>Size of each chunk.</p>
408
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
409
   *
410
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
411 8
   */
412
  public function chunk($size, $preserveKeys = false)
413 8
  {
414
    $result = \array_chunk($this->array, $size, $preserveKeys);
415 7
416
    return static::create($result);
417 8
  }
418
419
  /**
420
   * Clean all falsy values from the current array.
421
   *
422
   * @return static <p>(Immutable)</p>
423
   */
424
  public function clean()
425 4
  {
426
    return $this->filter(
427 4
        function ($value) {
428
          return (bool)$value;
429 4
        }
430
    );
431
  }
432
433
  /**
434
   * WARNING!!! -> Clear the current array.
435
   *
436
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
437
   */
438
  public function clear()
439 13
  {
440
    $this->array = array();
441 13
442
    return $this;
443
  }
444
445
  /**
446
   * Check if an item is in the current array.
447
   *
448
   * @param string|int|float $value
449
   *
450
   * @return bool
451 13
   */
452
  public function contains($value)
453 13
  {
454 13
    return in_array($value, $this->array, true);
455 13
  }
456
457 13
  /**
458 13
   * Check if an (case-insensitive) string is in the current array.
459 13
   *
460 13
   * @param string $value
461 13
   *
462
   * @return bool
463 13
   */
464
  public function containsCaseInsensitive($value)
465
  {
466
    return in_array(
467
        UTF8::strtolower($value),
468
        \array_map(
469
            array(
470
                new UTF8(),
471
                'strtolower',
472
            ),
473 4
            $this->array
474
        ),
475 4
        true
476
    );
477
  }
478
479
  /**
480
   * Check if the given key/index exists in the array.
481
   *
482
   * @param string|int|float $key <p>key/index to search for</p>
483
   *
484
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
485 1
   */
486
  public function containsKey($key)
487 1
  {
488
    return $this->offsetExists($key);
489
  }
490
491
  /**
492
   * Check if all given needles are present in the array as key/index.
493
   *
494
   * @param array $needles
495
   *
496
   * @return bool <p>Returns true if the given keys/indexes exists in the array, false otherwise.</p>
497
   */
498
  public function containsKeys(array $needles)
499
  {
500
    return count(\array_intersect($needles, $this->keys()->getArray())) === count($needles);
501
  }
502
503
  /**
504
   * alias: for "Arrayy->contains()"
505
   *
506
   * @see Arrayy::contains()
507
   *
508
   * @param string|int|float $value
509
   *
510
   * @return bool
511 1
   */
512
  public function containsValue($value)
513 1
  {
514
    return $this->contains($value);
515
  }
516
517
  /**
518
   * Check if all given needles are present in the array.
519
   *
520
   * @param array $needles
521
   *
522
   * @return bool <p>Returns true if the given values exists in the array, false otherwise.</p>
523 479
   */
524
  public function containsValues(array $needles)
525 479
  {
526
    return count(\array_intersect($needles, $this->array)) === count($needles);
527
  }
528
529
  /**
530
   * Creates an Arrayy object.
531
   *
532
   * @param array $array
533
   *
534
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
535 1
   */
536
  public static function create($array = array())
537 1
  {
538 1
    return new static($array);
539
  }
540
541 1
  /**
542
   * Generate array of repeated arrays.
543
   *
544
   * @param int $times <p>How many times has to be repeated.</p>
545
   *
546
   * @return Arrayy
547
   */
548
  public function repeat($times)
549
  {
550
    if ($times === 0) {
551
      return new static();
552
    }
553
554
    return static::create(\array_fill(0, (int)$times, $this->array));
555
  }
556
557
558
  /**
559
   * WARNING: Creates an Arrayy object by reference.
560
   *
561
   * @param array $array
562
   *
563
   * @return static <p>(Mutable) Return this Arrayy object.</p>
564
   */
565
  public function createByReference(&$array = array())
566
  {
567
    $array = $this->fallbackForArray($array);
568 5
569
    $this->array = &$array;
570 5
571
    return $this;
572 5
  }
573
574
  /**
575
   * Create an new Arrayy object via JSON.
576
   *
577
   * @param string $json
578
   *
579
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
580
   */
581
  public static function createFromJson($json)
582 4
  {
583
    $array = UTF8::json_decode($json, true);
584 4
585 4
    return static::create($array);
586
  }
587 3
588 4
  /**
589
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
590 4
   *
591
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
592
   *
593
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
594
   */
595
  public static function createFromObject(\ArrayAccess $object)
596
  {
597
    $array = new static();
598
    foreach ($object as $key => $value) {
599
      /** @noinspection OffsetOperationsInspection */
600
      $array[$key] = $value;
601
    }
602
603 8
    return $array;
604
  }
605 8
606 1
  /**
607
   * Create an new Arrayy object via string.
608 1
   *
609 1
   * @param string      $str       <p>The input string.</p>
610 1
   * @param string|null $delimiter <p>The boundary string.</p>
611
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
612 1
   *                               used.</p>
613 7
   *
614
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
615
   */
616
  public static function createFromString($str, $delimiter, $regEx = null)
617 8
  {
618
    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...
619
      preg_match_all($regEx, $str, $array);
620
621 8
      if (!empty($array)) {
622 8
        $array = $array[0];
623 8
      }
624 8
625 8
    } else {
626
      $array = explode($delimiter, $str);
627 8
    }
628
629
    // trim all string in the array
630
    \array_walk(
631
        $array,
632
        function (&$val) {
633
          /** @noinspection ReferenceMismatchInspection */
634
          if (is_string($val)) {
635
            $val = trim($val);
636
          }
637
        }
638
    );
639 1
640
    return static::create($array);
641 1
  }
642
643
  /**
644
   * Create an new instance containing a range of elements.
645
   *
646
   * @param mixed $low  <p>First value of the sequence.</p>
647
   * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
648
   * @param int   $step <p>Used as the increment between elements in the sequence.</p>
649
   *
650
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
651
   */
652
  public static function createWithRange($low, $high, $step = 1)
653 5
  {
654
    return static::create(range($low, $high, $step));
655 5
  }
656
657 5
  /**
658
   * Custom sort by index via "uksort".
659
   *
660
   * @link http://php.net/manual/en/function.uksort.php
661
   *
662
   * @param callable $function
663
   *
664
   * @return static <p>(Mutable) Return this Arrayy object.</p>
665
   */
666
  public function customSortKeys($function)
667
  {
668
    uksort($this->array, $function);
669 4
670
    return $this;
671 4
  }
672
673 4
  /**
674
   * Custom sort by value via "usort".
675
   *
676
   * @link http://php.net/manual/en/function.usort.php
677
   *
678
   * @param callable $function
679
   *
680
   * @return static <p>(Mutable) Return this Arrayy object.</p>
681
   */
682
  public function customSortValues($function)
683 12
  {
684
    usort($this->array, $function);
685 12
686
    return $this;
687 12
  }
688
689
  /**
690
   * Return values that are only in the current array.
691
   *
692
   * @param array $array
693
   *
694
   * @return static <p>(Immutable)</p>
695
   */
696
  public function diff(array $array = array())
697
  {
698 1
    $result = \array_diff($this->array, $array);
699
700 1
    return static::create($result);
701
  }
702
703
  /**
704 1
   * Return values that are only in the current multi-dimensional array.
705 1
   *
706 1
   * @param array      $array
707 1
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
708 1
   *
709 1
   * @return static <p>(Immutable)</p>
710
   */
711
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
712 1
  {
713 1
    $result = array();
714 1
715 1
    if (
716 1
        $helperVariableForRecursion !== null
717 1
        &&
718 1
        is_array($helperVariableForRecursion)
719 1
    ) {
720 1
      $arrayForTheLoop = $helperVariableForRecursion;
721 1
    } else {
722 1
      $arrayForTheLoop = $this->array;
723
    }
724 1
725 1
    foreach ($arrayForTheLoop as $key => $value) {
726
      if (\array_key_exists($key, $array)) {
727 1
        if (is_array($value)) {
728
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
729 1
          if (!empty($recursiveDiff)) {
730
            $result[$key] = $recursiveDiff;
731
          }
732
        } else {
733
          if ($value != $array[$key]) {
734
            $result[$key] = $value;
735
          }
736
        }
737
      } else {
738
        $result[$key] = $value;
739 8
      }
740
    }
741 8
742
    return static::create($result);
743 8
  }
744
745
  /**
746
   * Return values that are only in the new $array.
747
   *
748
   * @param array $array
749
   *
750
   * @return static <p>(Immutable)</p>
751 1
   */
752
  public function diffReverse(array $array = array())
753 1
  {
754
    $result = \array_diff($array, $this->array);
755 1
756 1
    return static::create($result);
757
  }
758 1
759
  /**
760
   * Divide an array into two arrays. One with keys and the other with values.
761
   *
762
   * @return static <p>(Immutable)</p>
763
   */
764
  public function divide()
765
  {
766
    return static::create(
767
        array(
768 4
            $this->keys(),
769
            $this->values(),
770 4
        )
771
    );
772 4
  }
773 4
774 4
  /**
775
   * Iterate over the current array and modify the array's value.
776 4
   *
777
   * @param \Closure $closure
778
   *
779
   * @return static <p>(Immutable)</p>
780
   */
781 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...
782
  {
783
    $array = $this->array;
784
785
    foreach ($array as $key => $value) {
786 4
      $array[$key] = $closure($value, $key);
787
    }
788 4
789 4
    return static::create($array);
790 3
  }
791 1
792 1
  /**
793
   * Check if a value is in the current array using a closure.
794 4
   *
795
   * @param \Closure $closure
796 4
   *
797
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
798
   */
799
  public function exists(\Closure $closure)
800
  {
801
    $isExists = false;
802
    foreach ($this->array as $key => $value) {
803
      if ($closure($value, $key)) {
804
        $isExists = true;
805
        break;
806
      }
807
    }
808
809
    return $isExists;
810
  }
811
812
  /**
813
   * create a fallback for array
814
   *
815
   * 1. use the current array, if it's a array
816 759
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
817
   * 3. fallback to empty array, if there is nothing
818 759
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
819 756
   * 5. call "__toArray()" on object, if the method exists
820
   * 6. cast a string or object with "__toString()" into an array
821
   * 7. throw a "InvalidArgumentException"-Exception
822 10
   *
823 1
   * @param $array
824
   *
825
   * @return array
826 9
   *
827 6
   * @throws \InvalidArgumentException
828
   */
829
  protected function fallbackForArray(&$array)
830 8
  {
831
    if (is_array($array)) {
832
      return $array;
833
    }
834
835 8
    if ($array instanceof self) {
836
      return $array->getArray();
837
    }
838
839
    if (!$array) {
840
      return array();
841 8
    }
842
843 2
    if ($array instanceof \ArrayAccess) {
844 8
      /** @noinspection ReferenceMismatchInspection */
845 6
      return static::createFromObject($array)->getArray();
846
    }
847
848 2
    if (is_object($array) && method_exists($array, '__toArray')) {
849
      return (array)$array->__toArray();
850 2
    }
851
852
    /** @noinspection ReferenceMismatchInspection */
853
    if (
854
        is_string($array)
855
        ||
856
        (is_object($array) && method_exists($array, '__toString'))
857
    ) {
858
      return array((string)$array);
859
    }
860 9
861
    throw new \InvalidArgumentException(
862 9
        'Passed value should be a array'
863 1
    );
864
  }
865
866 9
  /**
867
   * Find all items in an array that pass the truth test.
868 9
   *
869
   * @param \Closure|null $closure
870
   *
871
   * @return static <p>(Immutable)</p>
872
   */
873
  public function filter($closure = null)
874
  {
875
    if (!$closure) {
876
      return $this->clean();
877
    }
878
879
    $array = \array_filter($this->array, $closure);
880
881
    return static::create($array);
882
  }
883
884
  /**
885
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
886
   * within that.
887
   *
888
   * @param string $property
889
   * @param string $value
890
   * @param string $comparisonOp
891
   *                            <p>
892
   *                            'eq' (equals),<br />
893 1
   *                            'gt' (greater),<br />
894
   *                            'gte' || 'ge' (greater or equals),<br />
895 1
   *                            'lt' (less),<br />
896 1
   *                            'lte' || 'le' (less or equals),<br />
897 1
   *                            'ne' (not equals),<br />
898
   *                            'contains',<br />
899
   *                            'notContains',<br />
900
   *                            'newer' (via strtotime),<br />
901 1
   *                            'older' (via strtotime),<br />
902 1
   *                            </p>
903
   *
904
   * @return static <p>(Immutable)</p>
905 1
   */
906
  public function filterBy($property, $value, $comparisonOp = null)
907
  {
908 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...
909
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
910
    }
911 1
912
    $ops = array(
913 1
        'eq'          => function ($item, $prop, $value) {
914 1
          return $item[$prop] === $value;
915
        },
916
        'gt'          => function ($item, $prop, $value) {
917 1
          return $item[$prop] > $value;
918
        },
919
        'ge'          => function ($item, $prop, $value) {
920 1
          return $item[$prop] >= $value;
921
        },
922
        'gte'         => function ($item, $prop, $value) {
923 1
          return $item[$prop] >= $value;
924
        },
925 1
        'lt'          => function ($item, $prop, $value) {
926 1
          return $item[$prop] < $value;
927
        },
928
        'le'          => function ($item, $prop, $value) {
929 1
          return $item[$prop] <= $value;
930
        },
931
        'lte'         => function ($item, $prop, $value) {
932 1
          return $item[$prop] <= $value;
933
        },
934
        'ne'          => function ($item, $prop, $value) {
935 1
          return $item[$prop] !== $value;
936 1
        },
937
        'contains'    => function ($item, $prop, $value) {
938 1
          return in_array($item[$prop], (array)$value, true);
939 1
        },
940 1
        'notContains' => function ($item, $prop, $value) {
941
          return !in_array($item[$prop], (array)$value, true);
942 1
        },
943 1
        'newer'       => function ($item, $prop, $value) {
944 1
          return strtotime($item[$prop]) > strtotime($value);
945 1
        },
946
        'older'       => function ($item, $prop, $value) {
947 1
          return strtotime($item[$prop]) < strtotime($value);
948 1
        },
949 1
    );
950
951 1
    $result = \array_values(
952
        \array_filter(
953 1
            (array)$this->array,
954 1
            function ($item) use (
955
                $property,
956 1
                $value,
957
                $ops,
958
                $comparisonOp
959
            ) {
960
              $item = (array)$item;
961
              $itemArrayy = new Arrayy($item);
962
              $item[$property] = $itemArrayy->get($property, array());
963
964
              return $ops[$comparisonOp]($item, $property, $value);
965
            }
966
        )
967 8
    );
968
969 8
    return static::create($result);
970 6
  }
971 5
972
  /**
973 5
   * Find the first item in an array that passes the truth test,
974
   *  otherwise return false
975 3
   *
976
   * @param \Closure $closure
977
   *
978
   * @return mixed|false <p>Return false if we did not find the value.</p>
979
   */
980
  public function find(\Closure $closure)
981
  {
982
    foreach ($this->array as $key => $value) {
983
      if ($closure($value, $key)) {
984
        return $value;
985
      }
986
    }
987
988
    return false;
989
  }
990
991
  /**
992
   * find by ...
993
   *
994
   * @param string $property
995
   * @param string $value
996
   * @param string $comparisonOp
997 13
   *
998
   * @return static <p>(Immutable)</p>
999 13
   */
1000 13
  public function findBy($property, $value, $comparisonOp = 'eq')
1001
  {
1002 13
    return $this->filterBy($property, $value, $comparisonOp);
1003 3
  }
1004
1005
  /**
1006 10
   * Get the first value from the current array.
1007
   *
1008
   * @return mixed <p>Return null if there wasn't a element.</p>
1009
   */
1010
  public function first()
1011
  {
1012
    $tmpArray = $this->array;
1013
    $result = \array_shift($tmpArray);
1014
1015
    if ($result === null) {
1016 28
      return null;
1017
    }
1018 28
1019 7
    return $result;
1020 7
  }
1021 7
1022 21
  /**
1023 21
   * Get the first value(s) from the current array.
1024 21
   *
1025
   * @param int|null $number <p>How many values you will take?</p>
1026
   *
1027 28
   * @return static <p>(Immutable)</p>
1028
   */
1029
  public function firstsImmutable($number = null)
1030
  {
1031
    if ($number === null) {
1032
      $arrayTmp = $this->array;
1033
      $array = (array)\array_shift($arrayTmp);
1034
    } else {
1035
      $number = (int)$number;
1036
      $arrayTmp = $this->array;
1037 26
      $array = \array_splice($arrayTmp, 0, $number, true);
1038
    }
1039 26
1040 11
    return static::create($array);
1041 11
  }
1042 15
1043 15
  /**
1044
   * Get the first value(s) from the current array.
1045
   *
1046 26
   * @param int|null $number <p>How many values you will take?</p>
1047
   *
1048
   * @return static <p>(Mutable)</p>
1049
   */
1050
  public function firstsMutable($number = null)
1051
  {
1052
    if ($number === null) {
1053
      $this->array = (array)\array_shift($this->array);
1054 1
    } else {
1055
      $number = (int)$number;
1056 1
      $this->array = \array_splice($this->array, 0, $number, true);
1057
    }
1058 1
1059
    return $this;
1060
  }
1061
1062
  /**
1063
   * Exchanges all keys with their associated values in an array.
1064
   *
1065
   * @return static <p>(Immutable)</p>
1066
   */
1067
  public function flip()
1068
  {
1069
    $result = \array_flip($this->array);
1070
1071 58
    return static::create($result);
1072
  }
1073
1074
  /**
1075 58
   * Get a value from an array (optional using dot-notation).
1076 3
   *
1077 58
   * @param string $key      <p>The key to look for.</p>
1078 3
   * @param mixed  $fallback <p>Value to fallback to.</p>
1079 3
   * @param array  $array    <p>The array to get from, if it's set to "null" we use the current array from the
1080 56
   *                         class.</p>
1081
   *
1082
   * @return mixed
1083 58
   */
1084 1
  public function get($key, $fallback = null, $array = null)
1085
  {
1086
    if (
1087
        $array !== null
1088 58
        &&
1089 2
        is_array($array)
1090 2
    ) {
1091
      $usedArray = $array;
1092 58
    } else {
1093 48
      $usedArray = $this->array;
1094 5
    }
1095
1096
    if ($key === null) {
1097 45
      return static::create($usedArray);
1098
    }
1099
1100
    // php cast "bool"-index into "int"-index
1101 19
    if ((bool)$key === $key) {
1102 19
      $key = (int)$key;
1103 19
    }
1104
1105
    if (\array_key_exists($key, $usedArray) === true) {
1106 4
      if (is_array($usedArray[$key])) {
1107 4
        return static::create($usedArray[$key]);
1108
      }
1109 4
1110
      return $usedArray[$key];
1111
    }
1112
1113 4
    // Crawl through array, get key according to object or not
1114
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1115
      if (!isset($usedArray[$segment])) {
1116
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1117
      }
1118
1119
      $usedArray = $usedArray[$segment];
1120
    }
1121 484
1122
    if (is_array($usedArray)) {
1123 484
      return static::create($usedArray);
1124
    }
1125 484
1126
    return $usedArray;
1127
  }
1128
1129
  /**
1130
   * Get the current array from the "Arrayy"-object.
1131 399
   *
1132
   * @return array
1133 399
   */
1134
  public function getArray()
1135
  {
1136 399
    \array_map(array('self', 'internalGetArray'), $this->array);
1137
1138
    return $this->array;
1139
  }
1140
1141
  /**
1142
   * @param mixed $value
1143
   */
1144
  protected function internalGetArray(&$value)
1145
  {
1146
    if ($value instanceof self) {
1147
      $value &= $value->getArray();
1148
    }
1149
  }
1150 1
1151
  /**
1152 1
   * Returns the values from a single column of the input array, identified by
1153
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1154 1
   *
1155
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1156
   * array by the values from the $indexKey column in the input array.
1157
   *
1158
   * @param mixed $columnKey
1159
   * @param mixed $indexKey
1160
   *
1161
   * @return static <p>(Immutable)</p>
1162
   */
1163
  public function getColumn($columnKey = null, $indexKey = null)
1164 38
  {
1165
    $result = \array_column($this->array, $columnKey, $indexKey);
1166 38
1167 10
    return static::create($result);
1168
  }
1169 10
1170 2
  /**
1171 2
   * Get correct PHP constant for direction.
1172 8
   *
1173
   * @param int|string $direction
1174 10
   *
1175
   * @return int
1176
   */
1177
  protected function getDirection($direction)
1178 38
  {
1179
    if (is_string($direction)) {
1180 38
      $direction = strtolower($direction);
1181
1182
      if ($direction === 'desc') {
1183
        $direction = SORT_DESC;
1184 38
      } else {
1185
        $direction = SORT_ASC;
1186
      }
1187
    }
1188
1189
    if (
1190
        $direction !== SORT_DESC
1191
        &&
1192
        $direction !== SORT_ASC
1193
    ) {
1194 1
      $direction = SORT_ASC;
1195
    }
1196 1
1197
    return $direction;
1198
  }
1199
1200
  /**
1201
   * alias: for "Arrayy->keys()"
1202
   *
1203
   * @see Arrayy::keys()
1204
   *
1205
   * @return static <p>(Immutable)</p>
1206 3
   */
1207
  public function getKeys()
1208 3
  {
1209
    return $this->keys();
1210
  }
1211
1212
  /**
1213
   * alias: for "Arrayy->randomImmutable()"
1214
   *
1215
   * @see Arrayy::randomImmutable()
1216
   *
1217
   * @return static <p>(Immutable)</p>
1218 3
   */
1219
  public function getRandom()
1220 3
  {
1221
    return $this->randomImmutable();
1222
  }
1223
1224
  /**
1225
   * alias: for "Arrayy->randomKey()"
1226
   *
1227
   * @see Arrayy::randomKey()
1228
   *
1229
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1230
   */
1231
  public function getRandomKey()
1232 9
  {
1233
    return $this->randomKey();
1234 9
  }
1235
1236
  /**
1237
   * alias: for "Arrayy->randomKeys()"
1238
   *
1239
   * @see Arrayy::randomKeys()
1240
   *
1241
   * @param int $number
1242
   *
1243
   * @return static <p>(Immutable)</p>
1244 3
   */
1245
  public function getRandomKeys($number)
1246 3
  {
1247
    return $this->randomKeys($number);
1248
  }
1249
1250
  /**
1251
   * alias: for "Arrayy->randomValue()"
1252
   *
1253
   * @see Arrayy::randomValue()
1254
   *
1255
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1256
   */
1257
  public function getRandomValue()
1258 6
  {
1259
    return $this->randomValue();
1260 6
  }
1261
1262
  /**
1263
   * alias: for "Arrayy->randomValues()"
1264
   *
1265
   * @see Arrayy::randomValues()
1266
   *
1267
   * @param int $number
1268
   *
1269
   * @return static <p>(Immutable)</p>
1270
   */
1271 3
  public function getRandomValues($number)
1272
  {
1273 3
    return $this->randomValues($number);
1274 3
  }
1275
1276
  /**
1277 3
   * Group values from a array according to the results of a closure.
1278
   *
1279 3
   * @param string $grouper <p>A callable function name.</p>
1280 3
   * @param bool   $saveKeys
1281
   *
1282 3
   * @return static <p>(Immutable)</p>
1283
   */
1284
  public function group($grouper, $saveKeys = false)
1285
  {
1286 3
    $array = (array)$this->array;
1287 3
    $result = array();
1288 3
1289
    // Iterate over values, group by property/results from closure
1290
    foreach ($array as $key => $value) {
1291 3
1292 2
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1293 1
      $newValue = $this->get($groupKey, null, $result);
1294 1
1295 1
      if ($groupKey instanceof self) {
1296 1
        $groupKey = $groupKey->getArray();
1297 1
      }
1298
1299 2
      if ($newValue instanceof self) {
1300
        $newValue = $newValue->getArray();
1301 3
      }
1302
1303 3
      // Add to results
1304
      if ($groupKey !== null) {
1305
        if ($saveKeys) {
1306
          $result[$groupKey] = $newValue;
1307
          $result[$groupKey][$key] = $value;
1308
        } else {
1309
          $result[$groupKey] = $newValue;
1310
          $result[$groupKey][] = $value;
1311
        }
1312
      }
1313 22
1314
    }
1315
1316 22
    return static::create($result);
1317
  }
1318 22
1319
  /**
1320
   * Check if an array has a given key.
1321
   *
1322
   * @param mixed $key
1323
   *
1324
   * @return bool
1325
   */
1326
  public function has($key)
1327
  {
1328 27
    // Generate unique string to use as marker.
1329
    $unFound = (string)uniqid('arrayy', true);
1330 27
1331
    return $this->get($key, $unFound) !== $unFound;
1332
  }
1333
1334
  /**
1335
   * Implodes an array.
1336
   *
1337
   * @param string $glue
1338
   *
1339
   * @return string
1340
   */
1341
  public function implode($glue = '')
1342
  {
1343
    return implode($glue, $this->array);
1344 3
  }
1345
1346 3
  /**
1347
   * Given a list and an iterate-function that returns
1348 3
   * a key for each element in the list (or a property name),
1349 3
   * returns an object with an index of each item.
1350 2
   *
1351 2
   * Just like groupBy, but for when you know your keys are unique.
1352 3
   *
1353
   * @param mixed $key
1354 3
   *
1355
   * @return static <p>(Immutable)</p>
1356
   */
1357
  public function indexBy($key)
1358
  {
1359
    $results = array();
1360
1361
    foreach ($this->array as $a) {
1362
      if (\array_key_exists($key, $a) === true) {
1363
        $results[$a[$key]] = $a;
1364
      }
1365
    }
1366 4
1367
    return static::create($results);
1368 4
  }
1369
1370
  /**
1371
   * alias: for "Arrayy->searchIndex()"
1372
   *
1373
   * @see Arrayy::searchIndex()
1374
   *
1375
   * @param mixed $value <p>The value to search for.</p>
1376
   *
1377
   * @return mixed
1378 12
   */
1379
  public function indexOf($value)
1380 12
  {
1381
    return $this->searchIndex($value);
1382 12
  }
1383
1384
  /**
1385
   * Get everything but the last..$to items.
1386
   *
1387
   * @param int $to
1388
   *
1389
   * @return static <p>(Immutable)</p>
1390
   */
1391
  public function initial($to = 1)
1392 18
  {
1393
    $slice = count($this->array) - $to;
1394 18
1395
    return $this->firstsImmutable($slice);
1396
  }
1397 18
1398
  /**
1399
   * Internal mechanics of remove method.
1400
   *
1401
   * @param string $key
1402
   *
1403
   * @return boolean
1404
   */
1405
  protected function internalRemove($key)
1406
  {
1407 18
    $path = explode($this->pathSeparator, (string)$key);
1408
1409 18
    // Crawl though the keys
1410
    while (count($path) > 1) {
1411 18
      $key = \array_shift($path);
1412
1413
      if (!$this->has($key)) {
1414
        return false;
1415
      }
1416
1417
      $this->array = &$this->array[$key];
1418
    }
1419
1420
    $key = \array_shift($path);
1421
1422 28
    unset($this->array[$key]);
1423
1424 28
    return true;
1425
  }
1426
1427
  /**
1428
   * Internal mechanic of set method.
1429 28
   *
1430 28
   * @param string $key
1431
   * @param mixed  $value
1432
   *
1433 28
   * @return bool
1434 2
   */
1435
  protected function internalSet($key, $value)
1436
  {
1437
    if ($key === null) {
1438
      return false;
1439 2
    }
1440
1441
    // init
1442
    $array =& $this->array;
1443 2
    $path = explode($this->pathSeparator, (string)$key);
1444 2
1445
    // Crawl through the keys
1446 28
    while (count($path) > 1) {
1447
      $key = \array_shift($path);
1448 28
1449
      // If the key doesn't exist at this depth, we will just create an empty array
1450
      // to hold the next value, allowing us to create the arrays to hold final
1451
      // values at the correct depth. Then we'll keep digging into the array.
1452
      if (!isset($array[$key]) || !is_array($array[$key])) {
1453
        $array[$key] = static::create(array());
1454
      }
1455
1456
      $array =& $array[$key];
1457
    }
1458 2
1459
    $array[\array_shift($path)] = $value;
1460 2
1461
    return true;
1462
  }
1463
1464
  /**
1465
   * Return an array with all elements found in input array.
1466
   *
1467
   * @param array $search
1468
   *
1469
   * @return static <p>(Immutable)</p>
1470 1
   */
1471
  public function intersection(array $search)
1472 1
  {
1473
    return static::create(\array_values(\array_intersect($this->array, $search)));
1474
  }
1475
1476
  /**
1477
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1478
   *
1479
   * @param array $search
1480
   *
1481
   * @return bool
1482
   */
1483 1
  public function intersects(array $search)
1484
  {
1485
    return count($this->intersection($search)->array) > 0;
1486 1
  }
1487 1
1488 1
  /**
1489
   * Invoke a function on all of an array's values.
1490
   *
1491 1
   * @param mixed $callable
1492 1
   * @param mixed $arguments
1493 1
   *
1494 1
   * @return static <p>(Immutable)</p>
1495
   */
1496
  public function invoke($callable, $arguments = array())
1497 1
  {
1498
    // If one argument given for each iteration, create an array for it.
1499
    if (!is_array($arguments)) {
1500
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1501
    }
1502
1503
    // If the callable has arguments, pass them.
1504
    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...
1505 15
      $array = \array_map($callable, $this->array, $arguments);
1506
    } else {
1507 15
      $array = \array_map($callable, $this->array);
1508 3
    }
1509
1510
    return static::create($array);
1511 13
  }
1512 13
1513 11
  /**
1514
   * Check whether array is associative or not.
1515 3
   *
1516
   * @return bool <p>Returns true if associative, false otherwise.</p>
1517 3
   */
1518
  public function isAssoc()
1519
  {
1520
    if ($this->isEmpty()) {
1521
      return false;
1522
    }
1523
1524
    foreach ($this->keys()->getArray() as $key) {
1525 85
      if (!is_string($key)) {
1526
        return false;
1527 85
      }
1528
    }
1529
1530
    return true;
1531
  }
1532
1533
  /**
1534
   * Check whether the array is empty or not.
1535
   *
1536
   * @return bool <p>Returns true if empty, false otherwise.</p>
1537
   */
1538
  public function isEmpty()
1539
  {
1540
    return !$this->array;
1541
  }
1542
1543
  /**
1544
   * Check if the current array is equal to the given "$array" or not.
1545
   *
1546
   * @param array $array
1547 14
   *
1548
   * @return bool
1549 14
   */
1550
  public function isEqual(array $array)
1551
  {
1552
    return ($this->array === $array);
1553
  }
1554
1555
  /**
1556
   * Check if the current array is a multi-array.
1557 5
   *
1558
   * @return bool
1559 5
   */
1560 2
  public function isMultiArray()
1561
  {
1562
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1563 4
  }
1564 4
1565 2
  /**
1566
   * Check whether array is numeric or not.
1567 3
   *
1568
   * @return bool <p>Returns true if numeric, false otherwise.</p>
1569 2
   */
1570
  public function isNumeric()
1571
  {
1572
    if ($this->isEmpty()) {
1573
      return false;
1574
    }
1575
1576
    foreach ($this->keys() as $key) {
1577 1
      if (!is_int($key)) {
1578
        return false;
1579 1
      }
1580
    }
1581
1582
    return true;
1583
  }
1584
1585
  /**
1586
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1587 25
   *
1588
   * @return bool
1589 25
   */
1590
  public function isSequential()
1591
  {
1592
    return \array_keys($this->array) === range(0, count($this->array) - 1);
1593
  }
1594
1595
  /**
1596
   * Get all keys from the current array.
1597 4
   *
1598
   * @return static <p>(Immutable)</p>
1599 4
   */
1600
  public function keys()
1601
  {
1602
    return static::create(\array_keys($this->array));
1603
  }
1604
1605
  /**
1606
   * Get the last value from the current array.
1607
   *
1608
   * @return mixed <p>Return null if there wasn't a element.</p>
1609 13
   */
1610
  public function last()
1611 13
  {
1612 1
    return $this->pop();
1613
  }
1614
1615 12
  /**
1616 8
   * Get the last value(s) from the current array.
1617
   *
1618 8
   * @param int|null $number
1619 1
   *
1620 1
   * @return static <p>(Immutable)</p>
1621 7
   */
1622
  public function lastsImmutable($number = null)
1623
  {
1624 8
    if ($this->isEmpty()) {
1625 8
      return static::create();
1626 4
    }
1627 4
1628
    if ($number === null) {
1629
      $poppedValue = $this->pop();
1630 12
1631
      if ($poppedValue === null) {
1632
        $poppedValue = array($poppedValue);
1633
      } else {
1634
        $poppedValue = (array)$poppedValue;
1635
      }
1636
1637
      $arrayy = static::create($poppedValue);
1638
    } else {
1639
      $number = (int)$number;
1640 13
      $arrayy = $this->rest(-$number);
1641
    }
1642 13
1643 1
    return $arrayy;
1644
  }
1645
1646 12
  /**
1647 8
   * Get the last value(s) from the current array.
1648
   *
1649 8
   * @param int|null $number
1650 1
   *
1651 1
   * @return static <p>(Mutable)</p>
1652 7
   */
1653
  public function lastsMutable($number = null)
1654
  {
1655 8
    if ($this->isEmpty()) {
1656 8
      return $this;
1657 4
    }
1658 4
1659
    if ($number === null) {
1660
      $poppedValue = $this->pop();
1661 12
1662
      if ($poppedValue === null) {
1663
        $poppedValue = array($poppedValue);
1664
      } else {
1665
        $poppedValue = (array)$poppedValue;
1666
      }
1667
1668
      $this->array = static::create($poppedValue)->array;
1669
    } else {
1670
      $number = (int)$number;
1671
      $this->array = $this->rest(-$number)->array;
1672
    }
1673 10
1674
    return $this;
1675 10
  }
1676
1677
  /**
1678
   * Count the values from the current array.
1679
   *
1680
   * alias: for "Arrayy->size()"
1681
   *
1682
   * @see Arrayy::size()
1683
   *
1684
   * @return int
1685
   */
1686 4
  public function length()
1687
  {
1688 4
    return $this->size();
1689
  }
1690 4
1691
  /**
1692
   * Apply the given function to the every element of the array,
1693
   * collecting the results.
1694
   *
1695
   * @param callable $callable
1696
   *
1697
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
1698
   */
1699
  public function map($callable)
1700 15
  {
1701
    $result = \array_map($callable, $this->array);
1702 15
1703 2
    return static::create($result);
1704
  }
1705
1706
  /**
1707 13
   * Check if all items in current array match a truth test.
1708
   *
1709 13
   * @param \Closure $closure
1710 13
   *
1711
   * @return bool
1712 13
   */
1713 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...
1714
  {
1715 9
    if (count($this->array) === 0) {
1716
      return false;
1717 7
    }
1718
1719
    // init
1720
    $array = $this->array;
1721
1722
    foreach ($array as $key => $value) {
1723
      $value = $closure($value, $key);
1724
1725
      if ($value === false) {
1726
        return false;
1727 14
      }
1728
    }
1729 14
1730 2
    return true;
1731
  }
1732
1733
  /**
1734 12
   * Check if any item in the current array matches a truth test.
1735
   *
1736 12
   * @param \Closure $closure
1737 12
   *
1738
   * @return bool
1739 12
   */
1740 9 View Code Duplication
  public function matchesAny(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1741
  {
1742 5
    if (count($this->array) === 0) {
1743
      return false;
1744 4
    }
1745
1746
    // init
1747
    $array = $this->array;
1748
1749
    foreach ($array as $key => $value) {
1750
      $value = $closure($value, $key);
1751
1752 10
      if ($value === true) {
1753
        return true;
1754 10
      }
1755 1
    }
1756
1757
    return false;
1758 9
  }
1759
1760
  /**
1761
   * Get the max value from an array.
1762
   *
1763
   * @return mixed
1764
   */
1765
  public function max()
1766
  {
1767
    if ($this->count() === 0) {
1768
      return false;
1769
    }
1770
1771 25
    return max($this->array);
1772
  }
1773 25
1774 4
  /**
1775 4
   * Merge the new $array into the current array.
1776 21
   *
1777
   * - keep key,value from the current array, also if the index is in the new $array
1778
   *
1779 25
   * @param array $array
1780
   * @param bool  $recursive
1781
   *
1782
   * @return static <p>(Immutable)</p>
1783
   */
1784 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...
1785
  {
1786
    if (true === $recursive) {
1787
      $result = \array_replace_recursive($this->array, $array);
1788
    } else {
1789
      $result = \array_replace($this->array, $array);
1790
    }
1791
1792
    return static::create($result);
1793 16
  }
1794
1795 16
  /**
1796 4
   * Merge the new $array into the current array.
1797 4
   *
1798 12
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1799
   * - create new indexes
1800
   *
1801 16
   * @param array $array
1802
   * @param bool  $recursive
1803
   *
1804
   * @return static <p>(Immutable)</p>
1805
   */
1806 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...
1807
  {
1808
    if (true === $recursive) {
1809
      $result = \array_merge_recursive($this->array, $array);
1810
    } else {
1811
      $result = \array_merge($this->array, $array);
1812
    }
1813
1814 16
    return static::create($result);
1815
  }
1816 16
1817 4
  /**
1818 4
   * Merge the the current array into the $array.
1819 12
   *
1820
   * - use key,value from the new $array, also if the index is in the current array
1821
   *
1822 16
   * @param array $array
1823
   * @param bool  $recursive
1824
   *
1825
   * @return static <p>(Immutable)</p>
1826
   */
1827 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...
1828
  {
1829
    if (true === $recursive) {
1830
      $result = \array_replace_recursive($array, $this->array);
1831
    } else {
1832
      $result = \array_replace($array, $this->array);
1833
    }
1834
1835
    return static::create($result);
1836 16
  }
1837
1838 16
  /**
1839 4
   * Merge the current array into the new $array.
1840 4
   *
1841 12
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1842
   * - create new indexes
1843
   *
1844 16
   * @param array $array
1845
   * @param bool  $recursive
1846
   *
1847
   * @return static <p>(Immutable)</p>
1848
   */
1849 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...
1850
  {
1851
    if (true === $recursive) {
1852 10
      $result = \array_merge_recursive($array, $this->array);
1853
    } else {
1854 10
      $result = \array_merge($array, $this->array);
1855 1
    }
1856
1857
    return static::create($result);
1858 9
  }
1859
1860
  /**
1861
   * Get the min value from an array.
1862
   *
1863
   * @return mixed
1864
   */
1865
  public function min()
1866
  {
1867
    if ($this->count() === 0) {
1868
      return false;
1869
    }
1870
1871
    return min($this->array);
1872
  }
1873
1874
  /**
1875
   * Get a subset of the items from the given array.
1876
   *
1877
   * @param mixed[] $keys
1878
   *
1879
   * @return static <p>(Immutable)</p>
1880
   */
1881
  public function only(array $keys)
1882
  {
1883 4
    $array = $this->array;
1884
1885 4
    return static::create(\array_intersect_key($array, \array_flip($keys)));
1886
  }
1887 4
1888
  /**
1889
   * Pad array to the specified size with a given value.
1890
   *
1891
   * @param int   $size  <p>Size of the result array.</p>
1892
   * @param mixed $value <p>Empty value by default.</p>
1893
   *
1894
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
1895 16
   */
1896
  public function pad($size, $value)
1897 16
  {
1898
    $result = \array_pad($this->array, $size, $value);
1899
1900
    return static::create($result);
1901
  }
1902
1903
  /**
1904
   * Pop a specified value off the end of the current array.
1905
   *
1906
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
1907
   */
1908 8
  public function pop()
1909
  {
1910 8
    return \array_pop($this->array);
1911 8
  }
1912 8
1913
  /**
1914 1
   * Prepend a value to the current array.
1915
   *
1916
   * @param mixed $value
1917 8
   * @param mixed $key
1918
   *
1919
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
1920
   */
1921
  public function prepend($value, $key = null)
1922
  {
1923
    if ($key === null) {
1924
      \array_unshift($this->array, $value);
1925 4
    } else {
1926
      /** @noinspection AdditionOperationOnArraysInspection */
1927 4
      $this->array = array($key => $value) + $this->array;
1928 4
    }
1929 4
1930 4
    return $this;
1931
  }
1932 4
1933
  /**
1934
   * Push one or more values onto the end of array at once.
1935
   *
1936
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
1937
   */
1938 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...
1939
  {
1940
    if (func_num_args()) {
1941
      $args = \array_merge(array(&$this->array), func_get_args());
1942 17
      call_user_func_array('array_push', $args);
1943
    }
1944 17
1945
    return $this;
1946
  }
1947
1948 17
  /**
1949 14
   * Get a random value from the current array.
1950
   *
1951 14
   * @param null|int $number <p>How many values you will take?</p>
1952
   *
1953
   * @return static <p>(Immutable)</p>
1954 5
   */
1955 5
  public function randomImmutable($number = null)
1956
  {
1957 5
    if ($this->count() === 0) {
1958
      return static::create();
1959
    }
1960
1961 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...
1962
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
1963
1964
      return static::create($arrayRandValue);
1965
    }
1966
1967 4
    $arrayTmp = $this->array;
1968
    shuffle($arrayTmp);
1969 4
1970
    return static::create($arrayTmp)->firstsImmutable($number);
1971 4
  }
1972
1973
  /**
1974
   * Pick a random key/index from the keys of this array.
1975 4
   *
1976
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1977
   *
1978
   * @throws \RangeException If array is empty
1979
   */
1980
  public function randomKey()
1981
  {
1982
    $result = $this->randomKeys(1);
1983
1984
    if (!isset($result[0])) {
1985
      $result[0] = null;
1986
    }
1987 14
1988
    return $result[0];
1989 14
  }
1990 14
1991
  /**
1992 14
   * Pick a given number of random keys/indexes out of this array.
1993 3
   *
1994 3
   * @param int $number <p>The number of keys/indexes (should be <= $this->count())</p>
1995 3
   *
1996 3
   * @return static <p>(Immutable)</p>
1997
   *
1998 3
   * @throws \RangeException If array is empty
1999 3
   */
2000
  public function randomKeys($number)
2001
  {
2002 11
    $number = (int)$number;
2003
    $count = $this->count();
2004 11
2005
    if ($number === 0 || $number > $count) {
2006
      throw new \RangeException(
2007
          sprintf(
2008
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2009
              $number,
2010
              $count
2011
          )
2012
      );
2013
    }
2014 17
2015
    $result = (array)\array_rand($this->array, $number);
2016 17
2017
    return static::create($result);
2018
  }
2019
2020 17
  /**
2021 7
   * Get a random value from the current array.
2022 7
   *
2023
   * @param null|int $number <p>How many values you will take?</p>
2024 7
   *
2025
   * @return static <p>(Mutable)</p>
2026
   */
2027 11
  public function randomMutable($number = null)
2028
  {
2029 11
    if ($this->count() === 0) {
2030
      return static::create();
2031
    }
2032
2033 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...
2034
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2035
      $this->array = $arrayRandValue;
2036
2037 4
      return $this;
2038
    }
2039 4
2040
    shuffle($this->array);
2041 4
2042
    return $this->firstsMutable($number);
2043
  }
2044
2045 4
  /**
2046
   * Pick a random value from the values of this array.
2047
   *
2048
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2049
   */
2050
  public function randomValue()
2051
  {
2052
    $result = $this->randomImmutable();
2053
2054
    if (!isset($result[0])) {
2055 7
      $result[0] = null;
2056
    }
2057 7
2058
    return $result[0];
2059 7
  }
2060
2061
  /**
2062
   * Pick a given number of random values out of this array.
2063
   *
2064
   * @param int $number
2065
   *
2066
   * @return static <p>(Mutable)</p>
2067
   */
2068
  public function randomValues($number)
2069
  {
2070
    $number = (int)$number;
2071
2072 9
    return $this->randomMutable($number);
2073
  }
2074 9
2075 9
  /**
2076 9
   * Get a random value from an array, with the ability to skew the results.
2077 2
   *
2078 1
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2079 1
   *
2080 2
   * @param array    $array
2081 9
   * @param null|int $number <p>How many values you will take?</p>
2082
   *
2083 9
   * @return static <p>(Immutable)</p>
2084
   */
2085
  public function randomWeighted(array $array, $number = null)
2086
  {
2087
    $options = array();
2088
    foreach ($array as $option => $weight) {
2089
      if ($this->searchIndex($option) !== false) {
2090
        for ($i = 0; $i < $weight; ++$i) {
2091
          $options[] = $option;
2092
        }
2093
      }
2094 3
    }
2095
2096 3
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2097
  }
2098 3
2099
  /**
2100
   * Reduce the current array via callable e.g. anonymous-function.
2101 3
   *
2102
   * @param mixed $callable
2103
   * @param array $init
2104 3
   *
2105
   * @return static <p>(Immutable)</p>
2106
   */
2107
  public function reduce($callable, array $init = array())
2108
  {
2109
    $result = \array_reduce($this->array, $callable, $init);
2110
2111
    if ($result === null) {
2112 9
      $this->array = array();
2113
    } else {
2114 9
      $this->array = (array)$result;
2115
    }
2116 9
2117
    return static::create($this->array);
2118
  }
2119
2120
  /**
2121
   * Create a numerically re-indexed Arrayy object.
2122
   *
2123
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2124
   */
2125
  public function reindex()
2126 1
  {
2127
    $this->array = \array_values($this->array);
2128 1
2129
    return $this;
2130 1
  }
2131 1
2132 1
  /**
2133 1
   * Return all items that fail the truth test.
2134 1
   *
2135
   * @param \Closure $closure
2136 1
   *
2137
   * @return static <p>(Immutable)</p>
2138
   */
2139 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...
2140
  {
2141
    $filtered = array();
2142
2143
    foreach ($this->array as $key => $value) {
2144
      if (!$closure($value, $key)) {
2145
        $filtered[$key] = $value;
2146 18
      }
2147
    }
2148
2149 18
    return static::create($filtered);
2150
  }
2151
2152
  /**
2153
   * Remove a value from the current array (optional using dot-notation).
2154
   *
2155
   * @param mixed $key
2156
   *
2157 18
   * @return static <p>(Immutable)</p>
2158
   */
2159 18
  public function remove($key)
2160
  {
2161
    // Recursive call
2162
    if (is_array($key)) {
2163
      foreach ($key as $k) {
2164
        $this->internalRemove($k);
2165
      }
2166
2167 7
      return static::create($this->array);
2168
    }
2169 7
2170 7
    $this->internalRemove($key);
2171
2172 7
    return static::create($this->array);
2173
  }
2174
2175
  /**
2176
   * Remove the first value from the current array.
2177
   *
2178
   * @return static <p>(Immutable)</p>
2179
   */
2180 7
  public function removeFirst()
2181
  {
2182 7
    $tmpArray = $this->array;
2183 7
    \array_shift($tmpArray);
2184
2185 7
    return static::create($tmpArray);
2186
  }
2187
2188
  /**
2189
   * Remove the last value from the current array.
2190
   *
2191
   * @return static <p>(Immutable)</p>
2192
   */
2193
  public function removeLast()
2194
  {
2195 7
    $tmpArray = $this->array;
2196
    \array_pop($tmpArray);
2197 7
2198 7
    return static::create($tmpArray);
2199 6
  }
2200 6
2201
  /**
2202
   * Removes a particular value from an array (numeric or associative).
2203 6
   *
2204 6
   * @param mixed $value
2205 7
   *
2206
   * @return static <p>(Immutable)</p>
2207 7
   */
2208 7
  public function removeValue($value)
2209 7
  {
2210
    $isNumericArray = true;
2211 7
    foreach ($this->array as $key => $item) {
2212
      if ($item === $value) {
2213
        if (!is_int($key)) {
2214
          $isNumericArray = false;
2215
        }
2216
        unset($this->array[$key]);
2217
      }
2218
    }
2219
2220
    if ($isNumericArray) {
2221
      $this->array = \array_values($this->array);
2222
    }
2223 2
2224
    return static::create($this->array);
2225 2
  }
2226
2227 2
  /**
2228
   * Replace a key with a new key/value pair.
2229
   *
2230
   * @param $replace
2231
   * @param $key
2232
   * @param $value
2233
   *
2234
   * @return static <p>(Immutable)</p>
2235
   */
2236
  public function replace($replace, $key, $value)
2237 2
  {
2238
    $this->remove($replace);
2239 2
2240
    return $this->set($key, $value);
2241 2
  }
2242
2243
  /**
2244
   * Create an array using the current array as values and the other array as keys.
2245
   *
2246
   * @param array $keys <p>An array of keys.</p>
2247
   *
2248
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
2249
   */
2250
  public function replaceAllKeys(array $keys)
2251 2
  {
2252
    $result = \array_combine($keys, $this->array);
2253 2
2254
    return static::create($result);
2255 2
  }
2256
2257
  /**
2258
   * Create an array using the current array as keys and the other array as values.
2259
   *
2260
   * @param array $array <p>An array o values.</p>
2261
   *
2262
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
2263
   */
2264
  public function replaceAllValues(array $array)
2265 1
  {
2266
    $result = \array_combine($this->array, $array);
2267 1
2268 1
    return static::create($result);
2269
  }
2270 1
2271
  /**
2272
   * Replace the keys in an array with another set.
2273
   *
2274
   * @param array $keys <p>An array of keys matching the array's size</p>
2275
   *
2276
   * @return static <p>(Immutable)</p>
2277
   */
2278
  public function replaceKeys(array $keys)
2279
  {
2280
    $values = \array_values($this->array);
2281 3
    $result = \array_combine($keys, $values);
2282
2283 3
    return static::create($result);
2284 3
  }
2285
2286 3
  /**
2287 3
   * Replace the first matched value in an array.
2288 3
   *
2289
   * @param mixed $search
2290 3
   * @param mixed $replacement
2291
   *
2292
   * @return static <p>(Immutable)</p>
2293
   */
2294
  public function replaceOneValue($search, $replacement = '')
2295
  {
2296
    $array = $this->array;
2297
    $key = \array_search($search, $array, true);
2298
2299
    if ($key !== false) {
2300
      $array[$key] = $replacement;
2301 1
    }
2302
2303 1
    return static::create($array);
2304
  }
2305 1
2306
  /**
2307 1
   * Replace values in the current array.
2308
   *
2309 1
   * @param string $search      <p>The string to replace.</p>
2310
   * @param string $replacement <p>What to replace it with.</p>
2311
   *
2312
   * @return static <p>(Immutable)</p>
2313
   */
2314
  public function replaceValues($search, $replacement = '')
2315
  {
2316
    $array = $this->each(
2317
        function ($value) use ($search, $replacement) {
2318
          return UTF8::str_replace($search, $replacement, $value);
2319 15
        }
2320
    );
2321 15
2322
    return $array;
2323 15
  }
2324
2325
  /**
2326
   * Get the last elements from index $from until the end of this array.
2327
   *
2328
   * @param int $from
2329
   *
2330
   * @return static <p>(Immutable)</p>
2331
   */
2332
  public function rest($from = 1)
2333
  {
2334
    $tmpArray = $this->array;
2335
2336 1
    return static::create(\array_splice($tmpArray, $from));
2337
  }
2338 1
2339
  /**
2340 1
   * Move an array element to a new index.
2341 1
   *
2342 1
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2343 1
   *
2344 1
   * @param int|string $from
2345 1
   * @param int|string $to
2346 1
   *
2347 1
   * @return static <p>(Immutable)</p>
2348 1
   */
2349 1
  public function moveElement($from, $to)
2350 1
  {
2351 1
    $array = $this->array;
2352 1
2353 1
    if (is_int($from)) {
2354 1
      $tmp = \array_splice($array, $from, 1);
2355 1
      \array_splice($array, $to, 0, $tmp);
2356 1
      $output = $array;
2357 1
    } elseif (is_string($from)) {
2358
      $indexToMove = \array_search($from, \array_keys($array), true);
2359
      $itemToMove = $array[$from];
2360
      \array_splice($array, $indexToMove, 1);
2361 1
      $i = 0;
2362
      $output = array();
2363
      foreach ($array as $key => $item) {
2364
        if ($i == $to) {
2365
          $output[$from] = $itemToMove;
2366
        }
2367
        $output[$key] = $item;
2368
        $i++;
2369 7
      }
2370
    } else {
2371 7
      $output = array();
2372
    }
2373 7
2374
    return static::create($output);
2375
  }
2376
2377
  /**
2378
   * Return the array in the reverse order.
2379
   *
2380
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2381
   */
2382
  public function reverse()
2383 20
  {
2384
    $this->array = \array_reverse($this->array);
2385 20
2386
    return $this;
2387
  }
2388
2389
  /**
2390
   * Search for the first index of the current array via $value.
2391
   *
2392
   * @param mixed $value
2393
   *
2394
   * @return int|float|string
2395 9
   */
2396
  public function searchIndex($value)
2397
  {
2398 9
    return \array_search($value, $this->array, true);
2399
  }
2400 9
2401
  /**
2402
   * Search for the value of the current array via $index.
2403
   *
2404
   * @param mixed $index
2405 9
   *
2406 1
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
2407 1
   */
2408
  public function searchValue($index)
2409 9
  {
2410 7
    // init
2411 7
    $return = array();
2412
2413
    if ($this->isEmpty()) {
2414 9
      return static::create();
2415
    }
2416
2417
    // php cast "bool"-index into "int"-index
2418
    if ((bool)$index === $index) {
2419
      $index = (int)$index;
2420
    }
2421
2422
    if (\array_key_exists($index, $this->array) === true) {
2423
      $return = array($this->array[$index]);
2424
    }
2425 17
2426
2427 17
    return static::create($return);
2428
  }
2429 17
2430
  /**
2431
   * Set a value for the current array (optional using dot-notation).
2432
   *
2433
   * @param string $key   <p>The key to set.</p>
2434
   * @param mixed  $value <p>Its value.</p>
2435
   *
2436
   * @return static <p>(Immutable)</p>
2437
   */
2438
  public function set($key, $value)
2439
  {
2440
    $this->internalSet($key, $value);
2441
2442 11
    return static::create($this->array);
2443
  }
2444
2445 11
  /**
2446 4
   * Get a value from a array and set it if it was not.
2447 4
   *
2448
   * WARNING: this method only set the value, if the $key is not already set
2449 11
   *
2450
   * @param string $key      <p>The key</p>
2451
   * @param mixed  $fallback <p>The default value to set if it isn't.</p>
2452
   *
2453
   * @return mixed <p>(Mutable)</p>
2454
   */
2455
  public function setAndGet($key, $fallback = null)
2456
  {
2457 4
    // If the key doesn't exist, set it.
2458
    if (!$this->has($key)) {
2459 4
      $this->array = $this->set($key, $fallback)->getArray();
2460
    }
2461
2462
    return $this->get($key);
2463
  }
2464
2465
  /**
2466
   * Shifts a specified value off the beginning of array.
2467 1
   *
2468
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
2469 1
   */
2470
  public function shift()
2471 1
  {
2472
    return \array_shift($this->array);
2473 1
  }
2474
2475
  /**
2476
   * Shuffle the current array.
2477
   *
2478
   * @return static <p>(Immutable)</p>
2479
   */
2480
  public function shuffle()
2481 93
  {
2482
    $array = $this->array;
2483 93
2484
    shuffle($array);
2485
2486
    return static::create($array);
2487
  }
2488
2489
  /**
2490
   * Get the size of an array.
2491
   *
2492
   * @return int
2493
   */
2494
  public function size()
2495 4
  {
2496
    return count($this->array);
2497 4
  }
2498
2499 4
  /**
2500
   * Extract a slice of the array.
2501
   *
2502
   * @param int      $offset       <p>Slice begin index.</p>
2503
   * @param int|null $length       <p>Length of the slice.</p>
2504
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
2505
   *
2506
   * @return static <p>A slice of the original array with length $length.</p>
2507
   */
2508
  public function slice($offset, $length = null, $preserveKeys = false)
2509
  {
2510
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
2511 19
2512
    return static::create($result);
2513 19
  }
2514
2515 19
  /**
2516
   * Sort the current array and optional you can keep the keys.
2517
   *
2518
   * @param integer $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2519
   * @param integer $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2520
   * @param bool    $keepKeys
2521
   *
2522
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2523
   */
2524
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2525
  {
2526
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2527
2528
    return $this;
2529
  }
2530 18
2531
  /**
2532 18
   * Sort the current array by key.
2533
   *
2534 18
   * @link http://php.net/manual/en/function.ksort.php
2535
   * @link http://php.net/manual/en/function.krsort.php
2536
   *
2537
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2538
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2539
   *                              <strong>SORT_NATURAL</strong></p>
2540
   *
2541
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2542
   */
2543
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2544
  {
2545 1
    $this->sorterKeys($this->array, $direction, $strategy);
2546
2547 1
    return $this;
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 sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2559
  {
2560 1
    return $this->sort($direction, $strategy, true);
2561
  }
2562
2563
  /**
2564
   * Sort the current array by value.
2565
   *
2566
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2567
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2568
   *
2569
   * @return static <p>(Immutable)</p>
2570
   */
2571
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2572
  {
2573
    return $this->sort($direction, $strategy, false);
2574
  }
2575
2576 1
  /**
2577
   * Sort a array by value, by a closure or by a property.
2578 1
   *
2579 1
   * - If the sorter is null, the array is sorted naturally.
2580
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2581
   *
2582 1
   * @param null       $sorter
2583 1
   * @param string|int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2584
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2585 1
   *                              <strong>SORT_NATURAL</strong></p>
2586 1
   *
2587
   * @return static <p>(Immutable)</p>
2588 1
   */
2589
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2590 1
  {
2591
    $array = (array)$this->array;
2592 1
    $direction = $this->getDirection($direction);
2593 1
2594 1
    // Transform all values into their results.
2595
    if ($sorter) {
2596
      $arrayy = static::create($array);
2597
2598 1
      $that = $this;
2599
      $results = $arrayy->each(
2600 1
          function ($value) use ($sorter, $that) {
2601
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2602
          }
2603
      );
2604
2605
      $results = $results->getArray();
2606
    } else {
2607
      $results = $array;
2608
    }
2609
2610
    // Sort by the results and replace by original values
2611
    \array_multisort($results, $direction, $strategy, $array);
2612 18
2613
    return static::create($array);
2614 18
  }
2615
2616
  /**
2617 18
   * sorting keys
2618 18
   *
2619 6
   * @param array $elements
2620 6
   * @param int   $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2621 13
   * @param int   $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2622 13
   *
2623 13
   * @return void <p>Mutable</p>
2624 13
   */
2625 13
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2626 18
  {
2627
    $direction = $this->getDirection($direction);
2628
2629
    switch ($direction) {
2630
      case 'desc':
2631
      case SORT_DESC:
2632
        krsort($elements, $strategy);
2633
        break;
2634
      case 'asc':
2635
      case SORT_ASC:
2636
      default:
2637 19
        ksort($elements, $strategy);
2638
    }
2639 19
  }
2640
2641 19
  /**
2642 19
   * @param array      &$elements
2643 19
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2644
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2645
   *                              <strong>SORT_NATURAL</strong></p>
2646 19
   * @param bool       $keepKeys
2647 19
   *
2648 9
   * @return void <p>Mutable</p>
2649 5
   */
2650 5
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2651 4
  {
2652
    $direction = $this->getDirection($direction);
2653 9
2654 10
    if (!$strategy) {
2655 10
      $strategy = SORT_REGULAR;
2656 10
    }
2657 10
2658 4
    switch ($direction) {
2659 4
      case 'desc':
2660 6
      case SORT_DESC:
2661
        if ($keepKeys) {
2662 10
          arsort($elements, $strategy);
2663 19
        } else {
2664
          rsort($elements, $strategy);
2665
        }
2666
        break;
2667
      case 'asc':
2668
      case SORT_ASC:
2669
      default:
2670
        if ($keepKeys) {
2671
          asort($elements, $strategy);
2672
        } else {
2673 1
          sort($elements, $strategy);
2674
        }
2675 1
    }
2676
  }
2677 1
2678 1
  /**
2679 1
   * Split an array in the given amount of pieces.
2680 1
   *
2681 1
   * @param int  $numberOfPieces
2682 1
   * @param bool $keepKeys
2683
   *
2684
   * @return static <p>(Immutable)</p>
2685 1
   */
2686
  public function split($numberOfPieces = 2, $keepKeys = false)
2687
  {
2688
    $arrayCount = $this->count();
2689
2690
    if ($arrayCount === 0) {
2691
      $result = array();
2692
    } else {
2693 1
      $numberOfPieces = (int)$numberOfPieces;
2694
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
2695 1
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
2696
    }
2697 1
2698 1
    return static::create($result);
2699
  }
2700
2701 1
  /**
2702
   * Stripe all empty items.
2703 1
   *
2704
   * @return static <p>(Immutable)</p>
2705
   */
2706
  public function stripEmpty()
2707
  {
2708
    return $this->filter(
2709
        function ($item) {
2710
          if ($item === null) {
2711
            return false;
2712
          }
2713
2714 1
          return (bool)trim((string)$item);
2715
        }
2716 1
    );
2717
  }
2718 1
2719
  /**
2720 1
   * Swap two values between positions by key.
2721
   *
2722
   * @param string|int $swapA <p>a key in the array</p>
2723
   * @param string|int $swapB <p>a key in the array</p>
2724
   *
2725
   * @return static <p>(Immutable)</p>
2726
   */
2727
  public function swap($swapA, $swapB)
2728 141
  {
2729
    $array = $this->array;
2730 141
2731
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
2732
2733
    return static::create($array);
2734
  }
2735
2736
  /**
2737
   * alias: for "Arrayy->getArray()"
2738
   *
2739
   * @see Arrayy::getArray()
2740 5
   */
2741
  public function toArray()
2742 5
  {
2743
    return $this->getArray();
2744
  }
2745
2746
  /**
2747
   * Convert the current array to JSON.
2748
   *
2749
   * @param null|int $options <p>e.g. JSON_PRETTY_PRINT</p>
2750
   *
2751
   * @return string
2752 19
   */
2753
  public function toJson($options = null)
2754 19
  {
2755
    return UTF8::json_encode($this->array, $options);
2756
  }
2757
2758
  /**
2759
   * Implodes array to a string with specified separator.
2760
   *
2761
   * @param string $separator <p>The element's separator.</p>
2762
   *
2763
   * @return string <p>The string representation of array, separated by ",".</p>
2764 9
   */
2765
  public function toString($separator = ',')
2766 9
  {
2767
    return $this->implode($separator);
2768
  }
2769
2770
  /**
2771
   * alias: for "Arrayy->unique()"
2772
   *
2773
   * @see Arrayy::unique()
2774 9
   *
2775
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
2776 9
   */
2777 9
  public function uniqueNewIndex()
2778
  {
2779 8
    return $this->unique();
2780 8
  }
2781 8
2782
  /**
2783 8
   * Return a duplicate free copy of the current array.
2784 9
   *
2785 9
   * @return static <p>(Mutable)</p>
2786 9
   */
2787
  public function unique()
2788 9
  {
2789
    $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...
2790
        $this->array,
2791 9
        function ($resultArray, $value) {
2792
          if (!in_array($value, $resultArray, true)) {
2793
            $resultArray[] = $value;
2794 9
          }
2795
2796
          return $resultArray;
2797
        },
2798
        array()
2799
    );
2800
2801 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...
2802 9
      $this->array = array();
2803
    } else {
2804
      $this->array = (array)$this->array;
2805 9
    }
2806
2807 9
    return $this;
2808 9
  }
2809 9
2810 8
  /**
2811 8
   * Return a duplicate free copy of the current array. (with the old keys)
2812 8
   *
2813
   * @return static <p>(Mutable)</p>
2814 8
   */
2815 9
  public function uniqueKeepIndex()
2816 9
  {
2817 9
    // init
2818
    $array = $this->array;
2819 9
2820
    $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...
2821
        \array_keys($array),
2822 9
        function ($resultArray, $key) use ($array) {
2823
          if (!in_array($array[$key], $resultArray, true)) {
2824
            $resultArray[$key] = $array[$key];
2825 9
          }
2826
2827
          return $resultArray;
2828
        },
2829
        array()
2830
    );
2831
2832 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...
2833 4
      $this->array = array();
2834
    } else {
2835 4
      $this->array = (array)$this->array;
2836 4
    }
2837 4
2838 4
    return $this;
2839
  }
2840 4
2841
  /**
2842
   * Prepends one or more values to the beginning of array at once.
2843
   *
2844
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
2845
   */
2846 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...
2847
  {
2848 2
    if (func_num_args()) {
2849
      $args = \array_merge(array(&$this->array), func_get_args());
2850 2
      call_user_func_array('array_unshift', $args);
2851
    }
2852
2853
    return $this;
2854
  }
2855
2856
  /**
2857
   * Get all values from a array.
2858
   *
2859
   * @return static <p>(Immutable)</p>
2860
   */
2861 9
  public function values()
2862
  {
2863 9
    return static::create(\array_values((array)$this->array));
2864 4
  }
2865 4
2866 5
  /**
2867
   * Apply the given function to every element in the array, discarding the results.
2868
   *
2869 9
   * @param callable $callable
2870
   * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
2871
   *
2872
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
2873
   */
2874
  public function walk($callable, $recursive = false)
2875
  {
2876
    if (true === $recursive) {
2877
      \array_walk_recursive($this->array, $callable);
2878
    } else {
2879
      \array_walk($this->array, $callable);
2880
    }
2881
2882
    return $this;
2883
  }
2884
2885
}
2886