Completed
Push — master ( 02a9d7...7b587d )
by Lars
06:42
created

Arrayy::randomValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 10
ccs 4
cts 6
cp 0.6667
crap 2.1481
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Arrayy;
4
5
use voku\helper\UTF8;
6
7
/**
8
 * Methods to manage arrays.
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
class Arrayy extends \ArrayObject implements \ArrayAccess, \Serializable, \Countable
14
{
15
  /**
16
   * @var array
17
   */
18
  protected $array = array();
19
20
  /**
21
   * @var string
22
   */
23
  protected $pathSeparator = '.';
24
25
  /** @noinspection MagicMethodsValidityInspection */
26
  /**
27
   * Initializes
28
   *
29
   * @param array $array
30
   */
31 756
  public function __construct($array = array())
32
  {
33 756
    $array = $this->fallbackForArray($array);
34
35 754
    $this->array = $array;
36 754
  }
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 self::create($return);
51
    }
52
53 1
    return $return;
54
  }
55
56
  /**
57
   * Call object as function.
58
   *
59
   * @param mixed $key
60
   *
61
   * @return mixed
62
   */
63
  public function __invoke($key = null)
64
  {
65
    if ($key !== null) {
66
      if (isset($this->array[$key])) {
67
        return $this->array[$key];
68
      }
69
70
      return false;
71
    }
72
73
    return (array)$this->array;
74
  }
75
76
  /**
77
   * Whether or not an element exists by key.
78
   *
79
   * @param mixed $key
80
   *
81
   * @return bool <p>True is the key/index exists, otherwise false.</p>
82
   */
83
  public function __isset($key)
84
  {
85
    return $this->offsetExists($key);
86
  }
87
88
  /**
89
   * Assigns a value to the specified element.
90
   *
91
   * @param mixed $key
92
   * @param mixed $value
93
   */
94 2
  public function __set($key, $value)
95
  {
96 2
    $this->internalSet($key, $value);
97 2
  }
98
99
  /**
100
   * magic to string
101
   *
102
   * @return string
103
   */
104 16
  public function __toString()
105
  {
106 16
    return $this->toString();
107
  }
108
109
  /**
110
   * Unset element by key.
111
   *
112
   * @param mixed $key
113
   */
114
  public function __unset($key)
115
  {
116
    unset($this->array[$key]);
117
  }
118
119
  /**
120
   * alias: for "Arrayy->append()"
121
   *
122
   * @see Arrayy::append()
123
   *
124
   * @param mixed $value
125
   *
126
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
127
   */
128 1
  public function add($value)
129
  {
130 1
    return $this->append($value);
131
  }
132
133
  /**
134
   * Append a value to the current array.
135
   *
136
   * @param mixed $value
137
   *
138
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
139
   */
140 9
  public function append($value)
141
  {
142 9
    $this->array[] = $value;
143
144 9
    return $this;
145
  }
146
147
  /**
148
   * Count the values from the current array.
149
   *
150
   * alias: for "Arrayy->size()"
151
   *
152
   * @see Arrayy::size()
153
   *
154
   * @return int
155
   */
156 93
  public function count()
157
  {
158 93
    return $this->size();
159
  }
160
161
  /**
162
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
163
   *
164
   * @return ArrayyIterator <p>An iterator for the values in the array.</p>
165
   */
166 19
  public function getIterator()
167
  {
168 19
    return new ArrayyIterator($this->array);
169
  }
170
171
  /**
172
   * Whether or not an offset exists.
173
   *
174
   * @param int|float|string $offset
175
   *
176
   * @return bool
177
   */
178 38
  public function offsetExists($offset)
179
  {
180 38
    if ($this->isEmpty()) {
181 4
      return false;
182
    }
183
184
    // php cast "bool"-index into "int"-index
185 34
    if ((bool)$offset === $offset) {
186 1
      $offset = (int)$offset;
187 1
    }
188
189 34
    $tmpReturn = array_key_exists($offset, $this->array);
190
191
    if (
192
        $tmpReturn === true
193 34
        ||
194
        (
195
            $tmpReturn === false
196 11
            &&
197 11
            strpos((string)$offset, $this->pathSeparator) === false
198 11
        )
199 34
    ) {
200 32
      return $tmpReturn;
201
    }
202
203 2
    $offsetExists = false;
204
205 2
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
206
207 2
      $offsetExists = false;
208 2
      $explodedPath = explode($this->pathSeparator, (string)$offset);
209 2
      $lastOffset = array_pop($explodedPath);
210 2
      $containerPath = implode($this->pathSeparator, $explodedPath);
211
212 2
      $this->callAtPath(
213 2
          $containerPath,
214
          function ($container) use ($lastOffset, &$offsetExists) {
215 2
            $offsetExists = array_key_exists($lastOffset, $container);
216 2
          }
217 2
      );
218 2
    }
219
220 2
    return $offsetExists;
221
  }
222
223
  /**
224
   * Returns the value at specified offset.
225
   *
226
   * @param mixed $offset
227
   *
228
   * @return mixed <p>Will return null if the offset did not exists.</p>
229
   */
230 24
  public function offsetGet($offset)
231
  {
232 24
    return $this->offsetExists($offset) ? $this->get($offset) : null;
233
  }
234
235
  /**
236
   * Assigns a value to the specified offset.
237
   *
238
   * @param mixed $offset
239
   * @param mixed $value
240
   */
241 15
  public function offsetSet($offset, $value)
242
  {
243 15
    if ($offset === null) {
244 4
      $this->array[] = $value;
245 4
    } else {
246 11
      $this->internalSet($offset, $value);
247
    }
248 15
  }
249
250
  /**
251
   * Unset an offset.
252
   *
253
   * @param mixed $offset
254
   */
255 6
  public function offsetUnset($offset)
256
  {
257 6
    if ($this->isEmpty()) {
258 1
      return;
259
    }
260
261 5
    if (array_key_exists($offset, $this->array)) {
262 3
      unset($this->array[$offset]);
263
264 3
      return;
265
    }
266
267 2
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
268
269 1
      $path = explode($this->pathSeparator, (string)$offset);
270 1
      $pathToUnset = array_pop($path);
271
272 1
      $this->callAtPath(
273 1
          implode($this->pathSeparator, $path),
274
          function (&$offset) use ($pathToUnset) {
275 1
            unset($offset[$pathToUnset]);
276 1
          }
277 1
      );
278
279 1
    }
280 2
  }
281
282
  /**
283
   * Serialize the current array.
284
   *
285
   * @return string
286
   */
287 2
  public function serialize()
288
  {
289 2
    return serialize($this->array);
290
  }
291
292
  /**
293
   * Unserialize an string and return this object.
294
   *
295
   * @param string $string
296
   *
297
   * @return static <p>(Mutable)</p>
298
   */
299 2
  public function unserialize($string)
300
  {
301 2
    $this->array = unserialize($string);
302
303 2
    return $this;
304
  }
305
306
  /**
307
   * Iterate over the current array and execute a callback for each loop.
308
   *
309
   * @param \Closure $closure
310
   *
311
   * @return static <p>(Immutable)</p>
312
   */
313 2 View Code Duplication
  public function at(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
314
  {
315 2
    $array = $this->array;
316
317 2
    foreach ($array as $key => $value) {
318 2
      $closure($value, $key);
319 2
    }
320
321 2
    return static::create($array);
322
  }
323
324
  /**
325
   * Returns the average value of the current array.
326
   *
327
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
328
   *
329
   * @return int|double <p>The average value.</p>
330
   */
331 10
  public function average($decimals = 0)
332
  {
333 10
    $count = $this->count();
334
335 10
    if (!$count) {
336 2
      return 0;
337
    }
338
339 8
    if (!is_int($decimals)) {
340 3
      $decimals = 0;
341 3
    }
342
343 8
    return round(array_sum($this->array) / $count, $decimals);
344
  }
345
346
  /**
347
   * @param mixed      $path
348
   * @param callable   $callable
349
   * @param null|array $currentOffset
350
   */
351 2
  protected function callAtPath($path, $callable, &$currentOffset = null)
352
  {
353 2
    if ($currentOffset === null) {
354 2
      $currentOffset = &$this->array;
355 2
    }
356
357 2
    $explodedPath = explode($this->pathSeparator, $path);
358 2
    $nextPath = array_shift($explodedPath);
359
360 2
    if (!isset($currentOffset[$nextPath])) {
361
      return;
362
    }
363
364 2
    if (!empty($explodedPath)) {
365
      $this->callAtPath(
366
          implode($this->pathSeparator, $explodedPath),
367
          $callable,
368
          $currentOffset[$nextPath]
369
      );
370
    } else {
371 2
      $callable($currentOffset[$nextPath]);
372
    }
373 2
  }
374
375
  /**
376
   * Change the path separator of the array wrapper.
377
   *
378
   * By default, the separator is: "."
379
   *
380
   * @param string $separator <p>Separator to set.</p>
381
   *
382
   * @return static <p>Mutable</p>
383
   */
384
  public function changeSeparator($separator)
385
  {
386
    $this->pathSeparator = $separator;
387
388
    return $this;
389
  }
390
391
  /**
392
   * Create a chunked version of the current array.
393
   *
394
   * @param int  $size         <p>Size of each chunk.</p>
395
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
396
   *
397
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
398
   */
399 4
  public function chunk($size, $preserveKeys = false)
400
  {
401 4
    $result = array_chunk($this->array, $size, $preserveKeys);
402
403 4
    return static::create($result);
404
  }
405
406
  /**
407
   * Clean all falsy values from the current array.
408
   *
409
   * @return static <p>(Immutable)</p>
410
   */
411 8
  public function clean()
412
  {
413 8
    return $this->filter(
414
        function ($value) {
415 7
          return (bool)$value;
416
        }
417 8
    );
418
  }
419
420
  /**
421
   * WARNING!!! -> Clear the current array.
422
   *
423
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
424
   */
425 4
  public function clear()
426
  {
427 4
    $this->array = array();
428
429 4
    return $this;
430
  }
431
432
  /**
433
   * Check if an item is in the current array.
434
   *
435
   * @param string|int|float $value
436
   *
437
   * @return bool
438
   */
439 13
  public function contains($value)
440
  {
441 13
    return in_array($value, $this->array, true);
442
  }
443
444
  /**
445
   * Check if an (case-insensitive) string is in the current array.
446
   *
447
   * @param string $value
448
   *
449
   * @return bool
450
   */
451 13
  public function containsCaseInsensitive($value)
452
  {
453 13
    return in_array(
454 13
        UTF8::strtolower($value),
455 13
        array_map(
456
            array(
457 13
                new UTF8(),
458 13
                'strtolower',
459 13
            ),
460 13
            $this->array
461 13
        ),
462
        true
463 13
    );
464
  }
465
466
  /**
467
   * Check if the given key/index exists in the array.
468
   *
469
   * @param string|int|float $key <p>key/index to search for</p>
470
   *
471
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
472
   */
473 4
  public function containsKey($key)
474
  {
475 4
    return $this->offsetExists($key);
476
  }
477
478
  /**
479
   * Check if all given needles are present in the array as key/index.
480
   *
481
   * @param array $needles
482
   *
483
   * @return bool <p>Returns true if the given keys/indexes exists in the array, false otherwise.</p>
484
   */
485 1
  public function containsKeys(array $needles)
486
  {
487 1
    return count(array_intersect($needles, $this->keys()->getArray())) === count($needles);
488
  }
489
490
  /**
491
   * alias: for "Arrayy->contains()"
492
   *
493
   * @see Arrayy::contains()
494
   *
495
   * @param string|int|float $value
496
   *
497
   * @return bool
498
   */
499
  public function containsValue($value)
500
  {
501
    return $this->contains($value);
502
  }
503
504
  /**
505
   * Check if all given needles are present in the array.
506
   *
507
   * @param array $needles
508
   *
509
   * @return bool <p>Returns true if the given values exists in the array, false otherwise.</p>
510
   */
511 1
  public function containsValues(array $needles)
512
  {
513 1
    return count(array_intersect($needles, $this->array)) === count($needles);
514
  }
515
516
  /**
517
   * Creates an Arrayy object.
518
   *
519
   * @param array $array
520
   *
521
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
522
   */
523 476
  public static function create($array = array())
524
  {
525 476
    return new static($array);
526
  }
527
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 5
  public static function createFromJson($json)
552
  {
553 5
    $array = UTF8::json_decode($json, true);
554
555 5
    return static::create($array);
556
  }
557
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 4
  public static function createFromObject(\ArrayAccess $object)
566
  {
567 4
    $array = new static();
568 4
    foreach ($object as $key => $value) {
569
      /** @noinspection OffsetOperationsInspection */
570 3
      $array[$key] = $value;
571 4
    }
572
573 4
    return $array;
574
  }
575
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 8
  public static function createFromString($str, $delimiter, $regEx = null)
587
  {
588 8
    if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
589 1
      preg_match_all($regEx, $str, $array);
590
591 1
      if (!empty($array)) {
592 1
        $array = $array[0];
593 1
      }
594
595 1
    } else {
596 7
      $array = explode($delimiter, $str);
597
    }
598
599
    // trim all string in the array
600 8
    array_walk(
601 8
        $array,
602
        function (&$val) {
603
          /** @noinspection ReferenceMismatchInspection */
604 8
          if (is_string($val)) {
605 8
            $val = trim($val);
606 8
          }
607 8
        }
608 8
    );
609
610 8
    return static::create($array);
611
  }
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 1
  public static function createWithRange($low, $high, $step = 1)
623
  {
624 1
    return static::create(range($low, $high, $step));
625
  }
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 5
  public function customSortKeys($function)
637
  {
638 5
    uksort($this->array, $function);
639
640 5
    return $this;
641
  }
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 4
  public function customSortValues($function)
653
  {
654 4
    usort($this->array, $function);
655
656 4
    return $this;
657
  }
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 12
  public function diff(array $array = array())
667
  {
668 12
    $result = array_diff($this->array, $array);
669
670 12
    return static::create($result);
671
  }
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 1
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
682
  {
683 1
    $result = array();
684
685
    if (
686
        $helperVariableForRecursion !== null
687 1
        &&
688 1
        is_array($helperVariableForRecursion)
689 1
    ) {
690 1
      $arrayForTheLoop = $helperVariableForRecursion;
691 1
    } else {
692 1
      $arrayForTheLoop = $this->array;
693
    }
694
695 1
    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
        }
707 1
      } else {
708 1
        $result[$key] = $value;
709
      }
710 1
    }
711
712 1
    return static::create($result);
713
  }
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 8
  public function diffReverse(array $array = array())
723
  {
724 8
    $result = array_diff($array, $this->array);
725
726 8
    return static::create($result);
727
  }
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 1
  public function divide()
735
  {
736 1
    return static::create(
737
        array(
738 1
            $this->keys(),
739 1
            $this->values(),
740
        )
741 1
    );
742
  }
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 4 View Code Duplication
  public function each(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
752
  {
753 4
    $array = $this->array;
754
755 4
    foreach ($array as $key => $value) {
756 4
      $array[$key] = $closure($value, $key);
757 4
    }
758
759 4
    return static::create($array);
760
  }
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 4
  public function exists(\Closure $closure)
770
  {
771 4
    $isExists = false;
772 4
    foreach ($this->array as $key => $value) {
773 3
      if ($closure($value, $key)) {
774 1
        $isExists = true;
775 1
        break;
776
      }
777 4
    }
778
779 4
    return $isExists;
780
  }
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 756
  protected function fallbackForArray(&$array)
800
  {
801 756
    if (is_array($array)) {
802 753
      return $array;
803
    }
804
805 10
    if ($array instanceof self) {
806 1
      return $array->getArray();
807
    }
808
809 9
    if (!$array) {
810 6
      return array();
811
    }
812
813 8
    if ($array instanceof \ArrayAccess) {
814
      /** @noinspection ReferenceMismatchInspection */
815
      return self::createFromObject($array)->getArray();
816
    }
817
818 8
    if (is_object($array) && method_exists($array, '__toArray')) {
819
      return (array)$array->__toArray();
820
    }
821
822
    /** @noinspection ReferenceMismatchInspection */
823
    if (
824 8
        is_string($array)
825
        ||
826 2
        (is_object($array) && method_exists($array, '__toString'))
827 8
    ) {
828 6
      return array((string)$array);
829
    }
830
831 2
    throw new \InvalidArgumentException(
832
        'Passed value should be a array'
833 2
    );
834
  }
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 9
  public function filter($closure = null)
844
  {
845 9
    if (!$closure) {
846 1
      return $this->clean();
847
    }
848
849 9
    $array = array_filter($this->array, $closure);
850
851 9
    return static::create($array);
852
  }
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
   */
876 1
  public function filterBy($property, $value, $comparisonOp = null)
877
  {
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 1
    }
881
882
    $ops = array(
883
        'eq'          => function ($item, $prop, $value) {
884 1
          return $item[$prop] === $value;
885 1
        },
886
        'gt'          => function ($item, $prop, $value) {
887
          return $item[$prop] > $value;
888 1
        },
889
        'ge'          => function ($item, $prop, $value) {
890
          return $item[$prop] >= $value;
891 1
        },
892
        'gte'         => function ($item, $prop, $value) {
893
          return $item[$prop] >= $value;
894 1
        },
895
        'lt'          => function ($item, $prop, $value) {
896 1
          return $item[$prop] < $value;
897 1
        },
898
        'le'          => function ($item, $prop, $value) {
899
          return $item[$prop] <= $value;
900 1
        },
901
        'lte'         => function ($item, $prop, $value) {
902
          return $item[$prop] <= $value;
903 1
        },
904
        'ne'          => function ($item, $prop, $value) {
905
          return $item[$prop] !== $value;
906 1
        },
907
        'contains'    => function ($item, $prop, $value) {
908 1
          return in_array($item[$prop], (array)$value, true);
909 1
        },
910
        'notContains' => function ($item, $prop, $value) {
911
          return !in_array($item[$prop], (array)$value, true);
912 1
        },
913
        'newer'       => function ($item, $prop, $value) {
914
          return strtotime($item[$prop]) > strtotime($value);
915 1
        },
916
        'older'       => function ($item, $prop, $value) {
917
          return strtotime($item[$prop]) < strtotime($value);
918 1
        },
919 1
    );
920
921 1
    $result = array_values(
922 1
        array_filter(
923 1
            (array)$this->array,
924
            function ($item) use (
925 1
                $property,
926 1
                $value,
927 1
                $ops,
928 1
                $comparisonOp
929
            ) {
930 1
              $item = (array)$item;
931 1
              $itemArrayy = new Arrayy($item);
932 1
              $item[$property] = $itemArrayy->get($property, array());
933
934 1
              return $ops[$comparisonOp]($item, $property, $value);
935
            }
936 1
        )
937 1
    );
938
939 1
    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
   */
950 8
  public function find(\Closure $closure)
951
  {
952 8
    foreach ($this->array as $key => $value) {
953 6
      if ($closure($value, $key)) {
954 5
        return $value;
955
      }
956 5
    }
957
958 3
    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
   */
980 13
  public function first()
981
  {
982 13
    $tmpArray = $this->array;
983 13
    $result = array_shift($tmpArray);
984
985 13
    if ($result === null) {
986 3
      return null;
987
    }
988
989 10
    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
   */
999 28
  public function firstsImmutable($number = null)
1000
  {
1001 28
    if ($number === null) {
1002 7
      $arrayTmp = $this->array;
1003 7
      $array = (array)array_shift($arrayTmp);
1004 7
    } else {
1005 21
      $number = (int)$number;
1006 21
      $arrayTmp = $this->array;
1007 21
      $array = array_splice($arrayTmp, 0, $number, true);
1008
    }
1009
1010 28
    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
   */
1020 26
  public function firstsMutable($number = null)
1021
  {
1022 26
    if ($number === null) {
1023 11
      $this->array = (array)array_shift($this->array);
1024 11
    } else {
1025 15
      $number = (int)$number;
1026 15
      $this->array = array_splice($this->array, 0, $number, true);
1027
    }
1028
1029 26
    return $this;
1030
  }
1031
1032
  /**
1033
   * Exchanges all keys with their associated values in an array.
1034
   *
1035
   * @return static <p>(Immutable)</p>
1036
   */
1037 1
  public function flip()
1038
  {
1039 1
    $result = array_flip($this->array);
1040
1041 1
    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
   * @return mixed
1053
   */
1054 58
  public function get($key, $fallback = null, $array = null)
1055
  {
1056
    if (
1057
        $array !== null
1058 58
        &&
1059 3
        is_array($array)
1060 58
    ) {
1061 3
      $usedArray = $array;
1062 3
    } else {
1063 56
      $usedArray = $this->array;
1064
    }
1065
1066 58
    if ($key === null) {
1067 1
      return self::create($usedArray);
1068
    }
1069
1070
    // php cast "bool"-index into "int"-index
1071 58
    if ((bool)$key === $key) {
1072 2
      $key = (int)$key;
1073 2
    }
1074
1075 58
    if (array_key_exists($key, $usedArray) === true) {
1076 48
      if (is_array($usedArray[$key])) {
1077 5
        return self::create($usedArray[$key]);
1078
      }
1079
1080 45
      return $usedArray[$key];
1081
    }
1082
1083
    // Crawl through array, get key according to object or not
1084 19
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1085 19
      if (!isset($usedArray[$segment])) {
1086 19
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1087
      }
1088
1089 4
      $usedArray = $usedArray[$segment];
1090 4
    }
1091
1092 4
    if (is_array($usedArray)) {
1093
      return self::create($usedArray);
1094
    }
1095
1096 4
    return $usedArray;
1097
  }
1098
1099
  /**
1100
   * Get the current array from the "Arrayy"-object.
1101
   *
1102
   * @return array
1103
   */
1104 481
  public function getArray()
1105
  {
1106 481
    array_map(array('self', 'internalGetArray'), $this->array);
1107
1108 481
    return $this->array;
1109
  }
1110
1111
  /**
1112
   * @param mixed $value
1113
   */
1114 396
  protected function internalGetArray(&$value)
1115
  {
1116 396
    if ($value instanceof self) {
1117
      $value &= $value->getArray();
1118
    }
1119 396
  }
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
   * @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 1
    return static::create($result);
1138
  }
1139
1140
  /**
1141
   * Get correct PHP constant for direction.
1142
   *
1143
   * @param int|string $direction
1144
   *
1145
   * @return int
1146
   */
1147 38
  protected function getDirection($direction)
1148
  {
1149 38
    if (is_string($direction)) {
1150 10
      $direction = strtolower($direction);
1151
1152 10
      if ($direction === 'desc') {
1153 2
        $direction = SORT_DESC;
1154 2
      } else {
1155 8
        $direction = SORT_ASC;
1156
      }
1157 10
    }
1158
1159
    if (
1160
        $direction !== SORT_DESC
1161 38
        &&
1162
        $direction !== SORT_ASC
1163 38
    ) {
1164
      $direction = SORT_ASC;
1165
    }
1166
1167 38
    return $direction;
1168
  }
1169
1170
  /**
1171
   * alias: for "Arrayy->keys()"
1172
   *
1173
   * @see Arrayy::keys()
1174
   *
1175
   * @return static <p>(Immutable)</p>
1176
   */
1177 1
  public function getKeys()
1178
  {
1179 1
    return $this->keys();
1180
  }
1181
1182
  /**
1183
   * alias: for "Arrayy->randomImmutable()"
1184
   *
1185
   * @see Arrayy::randomImmutable()
1186
   *
1187
   * @return static <p>(Immutable)</p>
1188
   */
1189 3
  public function getRandom()
1190
  {
1191 3
    return $this->randomImmutable();
1192
  }
1193
1194
  /**
1195
   * alias: for "Arrayy->randomKey()"
1196
   *
1197
   * @see Arrayy::randomKey()
1198
   *
1199
   * @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 3
    return $this->randomKey();
1204
  }
1205
1206
  /**
1207
   * alias: for "Arrayy->randomKeys()"
1208
   *
1209
   * @see Arrayy::randomKeys()
1210
   *
1211
   * @param int $number
1212
   *
1213
   * @return static <p>(Immutable)</p>
1214
   */
1215 9
  public function getRandomKeys($number)
1216
  {
1217 9
    return $this->randomKeys($number);
1218
  }
1219
1220
  /**
1221
   * alias: for "Arrayy->randomValue()"
1222
   *
1223
   * @see Arrayy::randomValue()
1224
   *
1225
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1226
   */
1227 3
  public function getRandomValue()
1228
  {
1229 3
    return $this->randomValue();
1230
  }
1231
1232
  /**
1233
   * alias: for "Arrayy->randomValues()"
1234
   *
1235
   * @see Arrayy::randomValues()
1236
   *
1237
   * @param int $number
1238
   *
1239
   * @return static <p>(Immutable)</p>
1240
   */
1241 6
  public function getRandomValues($number)
1242
  {
1243 6
    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
   * @return static <p>(Immutable)</p>
1253
   */
1254 3
  public function group($grouper, $saveKeys = false)
1255
  {
1256 3
    $array = (array)$this->array;
1257 3
    $result = array();
1258
1259
    // Iterate over values, group by property/results from closure
1260 3
    foreach ($array as $key => $value) {
1261
1262 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1263 3
      $newValue = $this->get($groupKey, null, $result);
1264
1265 3
      if ($groupKey instanceof self) {
1266
        $groupKey = $groupKey->getArray();
1267
      }
1268
1269 3
      if ($newValue instanceof self) {
1270 3
        $newValue = $newValue->getArray();
1271 3
      }
1272
1273
      // Add to results
1274 3
      if ($groupKey !== null) {
1275 2
        if ($saveKeys) {
1276 1
          $result[$groupKey] = $newValue;
1277 1
          $result[$groupKey][$key] = $value;
1278 1
        } else {
1279 1
          $result[$groupKey] = $newValue;
1280 1
          $result[$groupKey][] = $value;
1281
        }
1282 2
      }
1283
1284 3
    }
1285
1286 3
    return static::create($result);
1287
  }
1288
1289
  /**
1290
   * Check if an array has a given key.
1291
   *
1292
   * @param mixed $key
1293
   *
1294
   * @return bool
1295
   */
1296 22
  public function has($key)
1297
  {
1298
    // Generate unique string to use as marker.
1299 22
    $unFound = (string)uniqid('arrayy', true);
1300
1301 22
    return $this->get($key, $unFound) !== $unFound;
1302
  }
1303
1304
  /**
1305
   * Implodes an array.
1306
   *
1307
   * @param string $glue
1308
   *
1309
   * @return string
1310
   */
1311 27
  public function implode($glue = '')
1312
  {
1313 27
    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
   * @return static <p>(Immutable)</p>
1326
   */
1327 3
  public function indexBy($key)
1328
  {
1329 3
    $results = array();
1330
1331 3
    foreach ($this->array as $a) {
1332 3
      if (array_key_exists($key, $a) === true) {
1333 2
        $results[$a[$key]] = $a;
1334 2
      }
1335 3
    }
1336
1337 3
    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
   * @return mixed
1348
   */
1349 4
  public function indexOf($value)
1350
  {
1351 4
    return $this->searchIndex($value);
1352
  }
1353
1354
  /**
1355
   * Get everything but the last..$to items.
1356
   *
1357
   * @param int $to
1358
   *
1359
   * @return static <p>(Immutable)</p>
1360
   */
1361 12
  public function initial($to = 1)
1362
  {
1363 12
    $slice = count($this->array) - $to;
1364
1365 12
    return $this->firstsImmutable($slice);
1366
  }
1367
1368
  /**
1369
   * Internal mechanics of remove method.
1370
   *
1371
   * @param string $key
1372
   *
1373
   * @return boolean
1374
   */
1375 18
  protected function internalRemove($key)
1376
  {
1377 18
    $path = explode($this->pathSeparator, (string)$key);
1378
1379
    // Crawl though the keys
1380 18
    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
    }
1389
1390 18
    $key = array_shift($path);
1391
1392 18
    unset($this->array[$key]);
1393
1394 18
    return true;
1395
  }
1396
1397
  /**
1398
   * Internal mechanic of set method.
1399
   *
1400
   * @param string $key
1401
   * @param mixed  $value
1402
   *
1403
   * @return bool
1404
   */
1405 28
  protected function internalSet($key, $value)
1406
  {
1407 28
    if ($key === null) {
1408
      return false;
1409
    }
1410
1411
    // init
1412 28
    $array =& $this->array;
1413 28
    $path = explode($this->pathSeparator, (string)$key);
1414
1415
    // Crawl through the keys
1416 28
    while (count($path) > 1) {
1417 2
      $key = array_shift($path);
1418
1419
      // If the key doesn't exist at this depth, we will just create an empty array
1420
      // 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 2
      if (!isset($array[$key]) || !is_array($array[$key])) {
1423
        $array[$key] = self::create(array());
1424
      }
1425
1426 2
      $array =& $array[$key];
1427 2
    }
1428
1429 28
    $array[array_shift($path)] = $value;
1430
1431 28
    return true;
1432
  }
1433
1434
  /**
1435
   * Return an array with all elements found in input array.
1436
   *
1437
   * @param array $search
1438
   *
1439
   * @return static <p>(Immutable)</p>
1440
   */
1441 2
  public function intersection(array $search)
1442
  {
1443 2
    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
   * @return bool
1452
   */
1453 1
  public function intersects(array $search)
1454
  {
1455 1
    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
   * @return static <p>(Immutable)</p>
1465
   */
1466 1
  public function invoke($callable, $arguments = array())
1467
  {
1468
    // If one argument given for each iteration, create an array for it.
1469 1
    if (!is_array($arguments)) {
1470 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1471 1
    }
1472
1473
    // 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 1
    } else {
1477 1
      $array = array_map($callable, $this->array);
1478
    }
1479
1480 1
    return static::create($array);
1481
  }
1482
1483
  /**
1484
   * Check whether array is associative or not.
1485
   *
1486
   * @return bool <p>Returns true if associative, false otherwise.</p>
1487
   */
1488 15
  public function isAssoc()
1489
  {
1490 15
    if ($this->isEmpty()) {
1491 3
      return false;
1492
    }
1493
1494 13
    foreach ($this->keys()->getArray() as $key) {
1495 13
      if (!is_string($key)) {
1496 11
        return false;
1497
      }
1498 3
    }
1499
1500 3
    return true;
1501
  }
1502
1503
  /**
1504
   * Check whether the array is empty or not.
1505
   *
1506
   * @return bool <p>Returns true if empty, false otherwise.</p>
1507
   */
1508 85
  public function isEmpty()
1509
  {
1510 85
    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
   * @return bool
1529
   */
1530 14
  public function isMultiArray()
1531
  {
1532 14
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1533
  }
1534
1535
  /**
1536
   * Check whether array is numeric or not.
1537
   *
1538
   * @return bool <p>Returns true if numeric, false otherwise.</p>
1539
   */
1540 5
  public function isNumeric()
1541
  {
1542 5
    if ($this->isEmpty()) {
1543 2
      return false;
1544
    }
1545
1546 4
    foreach ($this->keys() as $key) {
1547 4
      if (!is_int($key)) {
1548 2
        return false;
1549
      }
1550 3
    }
1551
1552 2
    return true;
1553
  }
1554
1555
  /**
1556
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1557
   *
1558
   * @return bool
1559
   */
1560 1
  public function isSequential()
1561
  {
1562 1
    return array_keys($this->array) === range(0, count($this->array) - 1);
1563
  }
1564
1565
  /**
1566
   * Get all keys from the current array.
1567
   *
1568
   * @return static <p>(Immutable)</p>
1569
   */
1570 25
  public function keys()
1571
  {
1572 25
    return static::create(array_keys($this->array));
1573
  }
1574
1575
  /**
1576
   * Get the last value from the current array.
1577
   *
1578
   * @return mixed <p>Return null if there wasn't a element.</p>
1579
   */
1580 4
  public function last()
1581
  {
1582 4
    return $this->pop();
1583
  }
1584
1585
  /**
1586
   * Get the last value(s) from the current array.
1587
   *
1588
   * @param int|null $number
1589
   *
1590
   * @return static <p>(Immutable)</p>
1591
   */
1592 13
  public function lastsImmutable($number = null)
1593
  {
1594 13
    if ($this->isEmpty()) {
1595 1
      return static::create();
1596
    }
1597
1598 12
    if ($number === null) {
1599 8
      $poppedValue = $this->pop();
1600
1601 8
      if ($poppedValue === null) {
1602 1
        $poppedValue = array($poppedValue);
1603 1
      } else {
1604 7
        $poppedValue = (array)$poppedValue;
1605
      }
1606
1607 8
      $arrayy = static::create($poppedValue);
1608 8
    } else {
1609 4
      $number = (int)$number;
1610 4
      $arrayy = $this->rest(-$number);
1611
    }
1612
1613 12
    return $arrayy;
1614
  }
1615
1616
  /**
1617
   * Get the last value(s) from the current array.
1618
   *
1619
   * @param int|null $number
1620
   *
1621
   * @return static <p>(Mutable)</p>
1622
   */
1623 13
  public function lastsMutable($number = null)
1624
  {
1625 13
    if ($this->isEmpty()) {
1626 1
      return $this;
1627
    }
1628
1629 12
    if ($number === null) {
1630 8
      $poppedValue = $this->pop();
1631
1632 8
      if ($poppedValue === null) {
1633 1
        $poppedValue = array($poppedValue);
1634 1
      } else {
1635 7
        $poppedValue = (array)$poppedValue;
1636
      }
1637
1638 8
      $this->array = static::create($poppedValue)->array;
1639 8
    } else {
1640 4
      $number = (int)$number;
1641 4
      $this->array = $this->rest(-$number)->array;
1642
    }
1643
1644 12
    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
   * @return int
1655
   */
1656 10
  public function length()
1657
  {
1658 10
    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
   * @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 4
    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
   * @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
  {
1685 15
    if (count($this->array) === 0) {
1686 2
      return false;
1687
    }
1688
1689
    // init
1690 13
    $array = $this->array;
1691
1692 13
    foreach ($array as $key => $value) {
1693 13
      $value = $closure($value, $key);
1694
1695 13
      if ($value === false) {
1696 7
        return false;
1697
      }
1698 9
    }
1699
1700 7
    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
   * @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
  {
1712 14
    if (count($this->array) === 0) {
1713 2
      return false;
1714
    }
1715
1716
    // init
1717 12
    $array = $this->array;
1718
1719 12
    foreach ($array as $key => $value) {
1720 12
      $value = $closure($value, $key);
1721
1722 12
      if ($value === true) {
1723 9
        return true;
1724
      }
1725 5
    }
1726
1727 4
    return false;
1728
  }
1729
1730
  /**
1731
   * Get the max value from an array.
1732
   *
1733
   * @return mixed
1734
   */
1735 10
  public function max()
1736
  {
1737 10
    if ($this->count() === 0) {
1738 1
      return false;
1739
    }
1740
1741 9
    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
   * @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
  {
1756 25
    if (true === $recursive) {
1757 4
      $result = array_replace_recursive($this->array, $array);
1758 4
    } else {
1759 21
      $result = array_replace($this->array, $array);
1760
    }
1761
1762 25
    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
   * @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
  {
1778 16
    if (true === $recursive) {
1779 4
      $result = array_merge_recursive($this->array, $array);
1780 4
    } else {
1781 12
      $result = array_merge($this->array, $array);
1782
    }
1783
1784 16
    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
   * @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
  {
1799 16
    if (true === $recursive) {
1800 4
      $result = array_replace_recursive($array, $this->array);
1801 4
    } else {
1802 12
      $result = array_replace($array, $this->array);
1803
    }
1804
1805 16
    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
   * @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
  {
1821 16
    if (true === $recursive) {
1822 4
      $result = array_merge_recursive($array, $this->array);
1823 4
    } else {
1824 12
      $result = array_merge($array, $this->array);
1825
    }
1826
1827 16
    return static::create($result);
1828
  }
1829
1830
  /**
1831
   * Get the min value from an array.
1832
   *
1833
   * @return mixed
1834
   */
1835 10
  public function min()
1836
  {
1837 10
    if ($this->count() === 0) {
1838 1
      return false;
1839
    }
1840
1841 9
    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
   * @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 4
    return static::create($result);
1871
  }
1872
1873
  /**
1874
   * Pop a specified value off the end of the current array.
1875
   *
1876
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
1877
   */
1878 16
  public function pop()
1879
  {
1880 16
    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
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
1890
   */
1891 8
  public function prepend($value, $key = null)
1892
  {
1893 8
    if ($key === null) {
1894 8
      array_unshift($this->array, $value);
1895 8
    } else {
1896
      /** @noinspection AdditionOperationOnArraysInspection */
1897 1
      $this->array = array($key => $value) + $this->array;
1898
    }
1899
1900 8
    return $this;
1901
  }
1902
1903
  /**
1904
   * Push one or more values onto the end of array at once.
1905
   *
1906
   * @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
  {
1910 4
    if (func_num_args()) {
1911 4
      $args = array_merge(array(&$this->array), func_get_args());
1912 4
      call_user_func_array('array_push', $args);
1913 4
    }
1914
1915 4
    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
   * @return static <p>(Immutable)</p>
1924
   */
1925 17
  public function randomImmutable($number = null)
1926
  {
1927 17
    if ($this->count() === 0) {
1928
      return static::create();
1929
    }
1930
1931 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1932 14
      $arrayRandValue = array($this->array[array_rand($this->array)]);
1933
1934 14
      return static::create($arrayRandValue);
1935
    }
1936
1937 5
    $arrayTmp = $this->array;
1938 5
    shuffle($arrayTmp);
1939
1940 5
    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
   * @throws \RangeException If array is empty
1949
   */
1950 4
  public function randomKey()
1951
  {
1952 4
    $result = $this->randomKeys(1);
1953
1954 4
    if (!isset($result[0])) {
1955
      $result[0] = null;
1956
    }
1957
1958 4
    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
   * @throws \RangeException If array is empty
1969
   */
1970 14
  public function randomKeys($number)
1971
  {
1972 14
    $number = (int)$number;
1973 14
    $count = $this->count();
1974
1975 14
    if ($number === 0 || $number > $count) {
1976 3
      throw new \RangeException(
1977 3
          sprintf(
1978 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
1979 3
              $number,
1980
              $count
1981 3
          )
1982 3
      );
1983
    }
1984
1985 11
    $result = (array)array_rand($this->array, $number);
1986
1987 11
    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
   * @return static <p>(Mutable)</p>
1996
   */
1997 17
  public function randomMutable($number = null)
1998
  {
1999 17
    if ($this->count() === 0) {
2000
      return static::create();
2001
    }
2002
2003 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2004 7
      $arrayRandValue = array($this->array[array_rand($this->array)]);
2005 7
      $this->array = $arrayRandValue;
2006
2007 7
      return $this;
2008
    }
2009
2010 11
    shuffle($this->array);
2011
2012 11
    return $this->firstsMutable($number);
2013
  }
2014
2015
  /**
2016
   * Pick a random value from the values of this array.
2017
   *
2018
   * @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 4
    if (!isset($result[0])) {
2025
      $result[0] = null;
2026
    }
2027
2028 4
    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
   * @return static <p>(Mutable)</p>
2037
   */
2038 7
  public function randomValues($number)
2039
  {
2040 7
    $number = (int)$number;
2041
2042 7
    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
   * @return static <p>(Immutable)</p>
2054
   */
2055 9
  public function randomWeighted(array $array, $number = null)
2056
  {
2057 9
    $options = array();
2058 9
    foreach ($array as $option => $weight) {
2059 9
      if ($this->searchIndex($option) !== false) {
2060 2
        for ($i = 0; $i < $weight; ++$i) {
2061 1
          $options[] = $option;
2062 1
        }
2063 2
      }
2064 9
    }
2065
2066 9
    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
   * @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 3
    if ($result === null) {
2082
      $this->array = array();
2083
    } else {
2084 3
      $this->array = (array)$result;
2085
    }
2086
2087 3
    return static::create($this->array);
2088
  }
2089
2090
  /**
2091
   * Create a numerically re-indexed Arrayy object.
2092
   *
2093
   * @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 9
    return $this;
2100
  }
2101
2102
  /**
2103
   * Return all items that fail the truth test.
2104
   *
2105
   * @param \Closure $closure
2106
   *
2107
   * @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
2113 1
    foreach ($this->array as $key => $value) {
2114 1
      if (!$closure($value, $key)) {
2115 1
        $filtered[$key] = $value;
2116 1
      }
2117 1
    }
2118
2119 1
    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
   * @return static <p>(Immutable)</p>
2128
   */
2129 18
  public function remove($key)
2130
  {
2131
    // Recursive call
2132 18
    if (is_array($key)) {
2133
      foreach ($key as $k) {
2134
        $this->internalRemove($k);
2135
      }
2136
2137
      return static::create($this->array);
2138
    }
2139
2140 18
    $this->internalRemove($key);
2141
2142 18
    return static::create($this->array);
2143
  }
2144
2145
  /**
2146
   * Remove the first value from the current array.
2147
   *
2148
   * @return static <p>(Immutable)</p>
2149
   */
2150 7
  public function removeFirst()
2151
  {
2152 7
    $tmpArray = $this->array;
2153 7
    array_shift($tmpArray);
2154
2155 7
    return static::create($tmpArray);
2156
  }
2157
2158
  /**
2159
   * Remove the last value from the current array.
2160
   *
2161
   * @return static <p>(Immutable)</p>
2162
   */
2163 7
  public function removeLast()
2164
  {
2165 7
    $tmpArray = $this->array;
2166 7
    array_pop($tmpArray);
2167
2168 7
    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
   * @return static <p>(Immutable)</p>
2177
   */
2178 7
  public function removeValue($value)
2179
  {
2180 7
    $isNumericArray = true;
2181 7
    foreach ($this->array as $key => $item) {
2182 6
      if ($item === $value) {
2183 6
        if (!is_int($key)) {
2184
          $isNumericArray = false;
2185
        }
2186 6
        unset($this->array[$key]);
2187 6
      }
2188 7
    }
2189
2190 7
    if ($isNumericArray) {
2191 7
      $this->array = array_values($this->array);
2192 7
    }
2193
2194 7
    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
   * @return static <p>(Immutable)</p>
2205
   */
2206 2
  public function replace($replace, $key, $value)
2207
  {
2208 2
    $this->remove($replace);
2209
2210 2
    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
   * @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 2
    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
   * @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 2
    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
   * @return static <p>(Immutable)</p>
2247
   */
2248 1
  public function replaceKeys(array $keys)
2249
  {
2250 1
    $values = array_values($this->array);
2251 1
    $result = array_combine($keys, $values);
2252
2253 1
    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
   * @return static <p>(Immutable)</p>
2263
   */
2264 3
  public function replaceOneValue($search, $replacement = '')
2265
  {
2266 3
    $array = $this->array;
2267 3
    $key = array_search($search, $array, true);
2268
2269 3
    if ($key !== false) {
2270 3
      $array[$key] = $replacement;
2271 3
    }
2272
2273 3
    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
   * @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 1
    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
   * @return static <p>(Immutable)</p>
2301
   */
2302 15
  public function rest($from = 1)
2303
  {
2304 15
    $tmpArray = $this->array;
2305
2306 15
    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
   * @return static <p>(Immutable)</p>
2318
   */
2319 1
  public function moveElement($from, $to)
2320
  {
2321 1
    $array = $this->array;
2322
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 1
      }
2340 1
    } else {
2341
      $output = array();
2342
    }
2343
2344 1
    return static::create($output);
2345
  }
2346
2347
  /**
2348
   * Return the array in the reverse order.
2349
   *
2350
   * @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 7
    return $this;
2357
  }
2358
2359
  /**
2360
   * Search for the first index of the current array via $value.
2361
   *
2362
   * @param mixed $value
2363
   *
2364
   * @return int|float|string
2365
   */
2366 20
  public function searchIndex($value)
2367
  {
2368 20
    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
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
2377
   */
2378 9
  public function searchValue($index)
2379
  {
2380
    // init
2381 9
    $return = array();
2382
2383 9
    if ($this->isEmpty()) {
2384
      return static::create();
2385
    }
2386
2387
    // php cast "bool"-index into "int"-index
2388 9
    if ((bool)$index === $index) {
2389 1
      $index = (int)$index;
2390 1
    }
2391
2392 9
    if (array_key_exists($index, $this->array) === true) {
2393 7
      $return = array($this->array[$index]);
2394 7
    }
2395
2396
2397 9
    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
   * @return static <p>(Immutable)</p>
2407
   */
2408 17
  public function set($key, $value)
2409
  {
2410 17
    $this->internalSet($key, $value);
2411
2412 17
    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
   * @return mixed <p>(Mutable)</p>
2424
   */
2425 11
  public function setAndGet($key, $fallback = null)
2426
  {
2427
    // If the key doesn't exist, set it.
2428 11
    if (!$this->has($key)) {
2429 4
      $this->array = $this->set($key, $fallback)->getArray();
2430 4
    }
2431
2432 11
    return $this->get($key);
2433
  }
2434
2435
  /**
2436
   * Shifts a specified value off the beginning of array.
2437
   *
2438
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
2439
   */
2440 4
  public function shift()
2441
  {
2442 4
    return array_shift($this->array);
2443
  }
2444
2445
  /**
2446
   * Shuffle the current array.
2447
   *
2448
   * @return static <p>(Immutable)</p>
2449
   */
2450 1
  public function shuffle()
2451
  {
2452 1
    $array = $this->array;
2453
2454 1
    shuffle($array);
2455
2456 1
    return static::create($array);
2457
  }
2458
2459
  /**
2460
   * Get the size of an array.
2461
   *
2462
   * @return int
2463
   */
2464 93
  public function size()
2465
  {
2466 93
    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
   * @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 4
    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
   * @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 19
    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
   *
2511
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2512
   */
2513 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2514
  {
2515 18
    $this->sorterKeys($this->array, $direction, $strategy);
2516
2517 18
    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
   *
2526
   * @return static <p>(Immutable)</p>
2527
   */
2528 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2529
  {
2530 1
    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
   *
2539
   * @return static <p>(Immutable)</p>
2540
   */
2541 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2542
  {
2543 1
    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
   *                              <strong>SORT_NATURAL</strong></p>
2556
   *
2557
   * @return static <p>(Immutable)</p>
2558
   */
2559 1
  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
    // Transform all values into their results.
2565 1
    if ($sorter) {
2566 1
      $arrayy = self::create($array);
2567
2568 1
      $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
          }
2573 1
      );
2574
2575 1
      $results = $results->getArray();
2576 1
    } else {
2577 1
      $results = $array;
2578
    }
2579
2580
    // Sort by the results and replace by original values
2581 1
    array_multisort($results, $direction, $strategy, $array);
2582
2583 1
    return static::create($array);
2584
  }
2585
2586
  /**
2587
   * sorting keys
2588
   *
2589
   * @param array $elements
2590
   * @param int   $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2591
   * @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
   */
2595 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2596
  {
2597 18
    $direction = $this->getDirection($direction);
2598
2599
    switch ($direction) {
2600 18
      case 'desc':
2601 18
      case SORT_DESC:
2602 6
        krsort($elements, $strategy);
2603 6
        break;
2604 13
      case 'asc':
2605 13
      case SORT_ASC:
2606 13
      default:
2607 13
        ksort($elements, $strategy);
2608 13
    }
2609 18
  }
2610
2611
  /**
2612
   * @param array      &$elements
2613
   * @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
   *                              <strong>SORT_NATURAL</strong></p>
2616
   * @param bool       $keepKeys
2617
   *
2618
   * @return void <p>Mutable</p>
2619
   */
2620 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2621
  {
2622 19
    $direction = $this->getDirection($direction);
2623
2624 19
    if (!$strategy) {
2625 19
      $strategy = SORT_REGULAR;
2626 19
    }
2627
2628
    switch ($direction) {
2629 19
      case 'desc':
2630 19
      case SORT_DESC:
2631 9
        if ($keepKeys) {
2632 5
          arsort($elements, $strategy);
2633 5
        } else {
2634 4
          rsort($elements, $strategy);
2635
        }
2636 9
        break;
2637 10
      case 'asc':
2638 10
      case SORT_ASC:
2639 10
      default:
2640 10
        if ($keepKeys) {
2641 4
          asort($elements, $strategy);
2642 4
        } else {
2643 6
          sort($elements, $strategy);
2644
        }
2645 10
    }
2646 19
  }
2647
2648
  /**
2649
   * Split an array in the given amount of pieces.
2650
   *
2651
   * @param int  $numberOfPieces
2652
   * @param bool $keepKeys
2653
   *
2654
   * @return static <p>(Immutable)</p>
2655
   */
2656 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2657
  {
2658 1
    $arrayCount = $this->count();
2659
2660 1
    if ($arrayCount === 0) {
2661 1
      $result = array();
2662 1
    } else {
2663 1
      $numberOfPieces = (int)$numberOfPieces;
2664 1
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
2665 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
2666
    }
2667
2668 1
    return static::create($result);
2669
  }
2670
2671
  /**
2672
   * Stripe all empty items.
2673
   *
2674
   * @return static <p>(Immutable)</p>
2675
   */
2676 1
  public function stripEmpty()
2677
  {
2678 1
    return $this->filter(
2679
        function ($item) {
2680 1
          if ($item === null) {
2681 1
            return false;
2682
          }
2683
2684 1
          return (bool)trim((string)$item);
2685
        }
2686 1
    );
2687
  }
2688
2689
  /**
2690
   * Swap two values between positions by key.
2691
   *
2692
   * @param string|int $swapA <p>a key in the array</p>
2693
   * @param string|int $swapB <p>a key in the array</p>
2694
   *
2695
   * @return static <p>(Immutable)</p>
2696
   */
2697 1
  public function swap($swapA, $swapB)
2698
  {
2699 1
    $array = $this->array;
2700
2701 1
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
2702
2703 1
    return static::create($array);
2704
  }
2705
2706
  /**
2707
   * alias: for "Arrayy->getArray()"
2708
   *
2709
   * @see Arrayy::getArray()
2710
   */
2711 141
  public function toArray()
2712
  {
2713 141
    return $this->getArray();
2714
  }
2715
2716
  /**
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 5
  public function toJson($options = null)
2724
  {
2725 5
    return UTF8::json_encode($this->array, $options);
2726
  }
2727
2728
  /**
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 19
  public function toString($separator = ',')
2736
  {
2737 19
    return $this->implode($separator);
2738
  }
2739
2740
  /**
2741
   * alias: for "Arrayy->unique()"
2742
   *
2743
   * @see Arrayy::unique()
2744
   *
2745
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
2746
   */
2747 8
  public function uniqueNewIndex()
2748
  {
2749 8
    return $this->unique();
2750
  }
2751
2752
  /**
2753
   * Return a duplicate free copy of the current array.
2754
   *
2755
   * @return static <p>(Mutable)</p>
2756
   */
2757 8
  public function unique()
2758
  {
2759 8
    $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 8
        $this->array,
2761
        function ($resultArray, $value) {
2762 7
          if (!in_array($value, $resultArray, true)) {
2763 7
            $resultArray[] = $value;
2764 7
          }
2765
2766 7
          return $resultArray;
2767 8
        },
2768 8
        array()
2769 8
    );
2770
2771 8 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 8
      $this->array = (array)$this->array;
2775
    }
2776
2777 8
    return $this;
2778
  }
2779
2780
  /**
2781
   * Return a duplicate free copy of the current array. (with the old keys)
2782
   *
2783
   * @return static <p>(Mutable)</p>
2784
   */
2785 8
  public function uniqueKeepIndex()
2786
  {
2787
    // init
2788 8
    $array = $this->array;
2789
2790 8
    $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 8
        array_keys($array),
2792 8
        function ($resultArray, $key) use ($array) {
2793 7
          if (!in_array($array[$key], $resultArray, true)) {
2794 7
            $resultArray[$key] = $array[$key];
2795 7
          }
2796
2797 7
          return $resultArray;
2798 8
        },
2799 8
        array()
2800 8
    );
2801
2802 8 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 8
      $this->array = (array)$this->array;
2806
    }
2807
2808 8
    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 4 View Code Duplication
  public function unshift(/* variadic arguments allowed */)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2817
  {
2818 4
    if (func_num_args()) {
2819 4
      $args = array_merge(array(&$this->array), func_get_args());
2820 4
      call_user_func_array('array_unshift', $args);
2821 4
    }
2822
2823 4
    return $this;
2824
  }
2825
2826
  /**
2827
   * Get all values from a array.
2828
   *
2829
   * @return static <p>(Immutable)</p>
2830
   */
2831 2
  public function values()
2832
  {
2833 2
    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 9
  public function walk($callable, $recursive = false)
2845
  {
2846 9
    if (true === $recursive) {
2847 4
      array_walk_recursive($this->array, $callable);
2848 4
    } else {
2849 5
      array_walk($this->array, $callable);
2850
    }
2851
2852 9
    return $this;
2853
  }
2854
2855
}
2856