Completed
Push — master ( 4d8967...4acb82 )
by Lars
02:00
created

Arrayy::unique()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 22
Code Lines 13

Duplication

Lines 5
Ratio 22.73 %

Code Coverage

Tests 6
CRAP Score 3

Importance

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

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
2760
        $this->array,
2761
        function ($resultArray, $value) {
2762
          if (!in_array($value, $resultArray, true)) {
2763
            $resultArray[] = $value;
2764 4
          }
2765
2766 4
          return $resultArray;
2767 4
        },
2768 4
        array()
2769 4
    );
2770
2771 4 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2772
      $this->array = array();
2773
    } else {
2774
      $this->array = (array)$this->array;
2775
    }
2776
2777
    return $this;
2778
  }
2779 2
2780
  /**
2781 2
   * Return a duplicate free copy of the current array. (with the old keys)
2782
   *
2783
   * @return static <p>(Mutable)</p>
2784
   */
2785
  public function uniqueKeepIndex()
2786
  {
2787
    // init
2788
    $array = $this->array;
2789
2790
    $this->array = array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce(array_keys(...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...
2791
        array_keys($array),
2792 9
        function ($resultArray, $key) use ($array) {
2793
          if (!in_array($array[$key], $resultArray, true)) {
2794 9
            $resultArray[$key] = $array[$key];
2795 4
          }
2796 4
2797 5
          return $resultArray;
2798
        },
2799
        array()
2800 9
    );
2801
2802 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...
2803
      $this->array = array();
2804
    } else {
2805
      $this->array = (array)$this->array;
2806
    }
2807
2808
    return $this;
2809
  }
2810
2811
  /**
2812
   * Prepends one or more values to the beginning of array at once.
2813
   *
2814
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
2815
   */
2816 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...
2817
  {
2818
    if (func_num_args()) {
2819
      $args = array_merge(array(&$this->array), func_get_args());
2820
      call_user_func_array('array_unshift', $args);
2821
    }
2822
2823
    return $this;
2824
  }
2825
2826
  /**
2827
   * Get all values from a array.
2828
   *
2829
   * @return static <p>(Immutable)</p>
2830
   */
2831
  public function values()
2832
  {
2833
    return static::create(array_values((array)$this->array));
2834
  }
2835
2836
  /**
2837
   * Apply the given function to every element in the array, discarding the results.
2838
   *
2839
   * @param callable $callable
2840
   * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
2841
   *
2842
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
2843
   */
2844
  public function walk($callable, $recursive = false)
2845
  {
2846
    if (true === $recursive) {
2847
      array_walk_recursive($this->array, $callable);
2848
    } else {
2849
      array_walk($this->array, $callable);
2850
    }
2851
2852
    return $this;
2853
  }
2854
2855
}
2856