Completed
Push — master ( 5d5508...88c4b3 )
by Lars
02:35
created

src/Arrayy.php (14 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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