Completed
Push — master ( 004f7a...aac8f4 )
by Lars
03:54 queued 01:47
created

Arrayy::removeValue()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5.0729

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 8
nop 1
dl 0
loc 18
ccs 12
cts 14
cp 0.8571
crap 5.0729
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace Arrayy;
4
5
use voku\helper\UTF8;
6
7
/** @noinspection ClassReImplementsParentInterfaceInspection */
8
9
/**
10
 * Methods to manage arrays.
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 */
15
class Arrayy extends \ArrayObject implements \IteratorAggregate, \ArrayAccess, \Serializable, \Countable
16
{
17
  /**
18
   * @var array
19
   */
20
  protected $array = array();
21
22
  /**
23
   * @var string
24
   */
25
  protected $iteratorClass;
26
27
  /**
28
   * @var string
29
   */
30
  protected $pathSeparator = '.';
31
32
  /** @noinspection MagicMethodsValidityInspection */
33
  /**
34
   * Initializes
35
   *
36
   * @param array  $array
37
   * @param string $iteratorClass
38
   */
39 762
  public function __construct($array = array(), $iteratorClass = '\\Arrayy\\ArrayyIterator')
40
  {
41 762
    $array = $this->fallbackForArray($array);
42 760
    $this->array = $array;
43
44 760
    $this->setIteratorClass($iteratorClass);
45 760
  }
46
47
  /**
48
   * Get a value by key.
49
   *
50
   * @param $key
51
   *
52
   * @return mixed <p>Get a Value from the current array.</p>
53
   */
54 1
  public function &__get($key)
55
  {
56 1
    $return = $this->get($key);
57
58 1
    if (is_array($return)) {
59
      return static::create($return);
60
    }
61
62 1
    return $return;
63
  }
64
65
  /**
66
   * Call object as function.
67
   *
68
   * @param mixed $key
69
   *
70
   * @return mixed
71
   */
72
  public function __invoke($key = null)
73
  {
74
    if ($key !== null) {
75
      if (isset($this->array[$key])) {
76
        return $this->array[$key];
77
      }
78
79
      return false;
80
    }
81
82
    return (array)$this->array;
83
  }
84
85
  /**
86
   * Whether or not an element exists by key.
87
   *
88
   * @param mixed $key
89
   *
90
   * @return bool <p>True is the key/index exists, otherwise false.</p>
91
   */
92
  public function __isset($key)
93
  {
94
    return $this->offsetExists($key);
95
  }
96
97
  /**
98
   * Assigns a value to the specified element.
99
   *
100
   * @param mixed $key
101
   * @param mixed $value
102
   */
103 2
  public function __set($key, $value)
104
  {
105 2
    $this->internalSet($key, $value);
106 2
  }
107
108
  /**
109
   * magic to string
110
   *
111
   * @return string
112
   */
113 16
  public function __toString()
114
  {
115 16
    return $this->toString();
116
  }
117
118
  /**
119
   * Unset element by key.
120
   *
121
   * @param mixed $key
122
   */
123
  public function __unset($key)
124
  {
125
    $this->internalRemove($key);
126
  }
127
128
  /**
129
   * alias: for "Arrayy->append()"
130
   *
131
   * @see Arrayy::append()
132
   *
133
   * @param mixed $value
134
   *
135
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
136
   */
137 1
  public function add($value)
138
  {
139 1
    return $this->append($value);
140
  }
141
142
  /**
143
   * Append a value to the current array.
144
   *
145
   * @param mixed $value
146
   *
147
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
148
   */
149 9
  public function append($value)
150
  {
151 9
    $this->array[] = $value;
152
153 9
    return $this;
154
  }
155
156
  /**
157
   * Sort the entries by value
158
   *
159
   * @return void
160
   */
161
  public function asort()
162
  {
163
    asort($this->array);
164
  }
165
166
  /**
167
   * Count the values from the current array.
168
   *
169
   * alias: for "Arrayy->size()"
170
   *
171
   * @see Arrayy::size()
172
   *
173
   * @return int
174
   */
175 93
  public function count()
176
  {
177 93
    return $this->size();
178
  }
179
180
  /**
181
   * Exchange the array for another one.
182
   *
183
   * @param  array|Arrayy $data
184
   *
185
   * @return array
186
   */
187
  public function exchangeArray($data)
188
  {
189
    $this->array = $this->fallbackForArray($data);
190
191
    return $this->array;
192
  }
193
194
  /**
195
   * Creates a copy of the ArrayyObject.
196
   *
197
   * @return array
198
   */
199
  public function getArrayCopy()
200
  {
201
    return $this->array;
202
  }
203
204
  /**
205
   * Returns a new ArrayyIterator, thus implementing the IteratorAggregate interface.
206
   *
207
   * @return ArrayyIterator <p>An iterator for the values in the array.</p>
208
   */
209 19
  public function getIterator()
210
  {
211 19
    $iterator = $this->getIteratorClass();
212
213 19
    return new $iterator($this->array);
214
  }
215
216
  /**
217
   * Gets the iterator classname for the ArrayObject.
218
   *
219
   * @return string
220
   */
221 19
  public function getIteratorClass()
222
  {
223 19
    return $this->iteratorClass;
224
  }
225
226
  /**
227
   * Sort the entries by key
228
   *
229
   * @return void
230
   */
231
  public function ksort()
232
  {
233
    ksort($this->array);
234
  }
235
236
  /**
237
   * Sort an array using a case insensitive "natural order" algorithm
238
   *
239
   * @return void
240
   */
241
  public function natcasesort()
242
  {
243
    natcasesort($this->array);
244
  }
245
246
  /**
247
   * Sort entries using a "natural order" algorithm
248
   *
249
   * @return void
250
   */
251
  public function natsort()
252
  {
253
    natsort($this->array);
254
  }
255
256
  /**
257
   * Whether or not an offset exists.
258
   *
259
   * @param int|float|string $offset
260
   *
261
   * @return bool
262
   */
263 38
  public function offsetExists($offset)
264
  {
265 38
    if ($this->isEmpty()) {
266 4
      return false;
267
    }
268
269
    // php cast "bool"-index into "int"-index
270 34
    if ((bool)$offset === $offset) {
271 1
      $offset = (int)$offset;
272 1
    }
273
274 34
    $tmpReturn = \array_key_exists($offset, $this->array);
275
276
    if (
277
        $tmpReturn === true
278 34
        ||
279
        (
280
            $tmpReturn === false
281 11
            &&
282 11
            strpos((string)$offset, $this->pathSeparator) === false
283 11
        )
284 34
    ) {
285 32
      return $tmpReturn;
286
    }
287
288 2
    $offsetExists = false;
289
290 2
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
291
292 2
      $offsetExists = false;
293 2
      $explodedPath = explode($this->pathSeparator, (string)$offset);
294 2
      $lastOffset = \array_pop($explodedPath);
295 2
      $containerPath = implode($this->pathSeparator, $explodedPath);
296
297 2
      $this->callAtPath(
298 2
          $containerPath,
299
          function ($container) use ($lastOffset, &$offsetExists) {
300 2
            $offsetExists = \array_key_exists($lastOffset, $container);
301 2
          }
302 2
      );
303 2
    }
304
305 2
    return $offsetExists;
306
  }
307
308
  /**
309
   * Returns the value at specified offset.
310
   *
311
   * @param mixed $offset
312
   *
313
   * @return mixed <p>Will return null if the offset did not exists.</p>
314
   */
315 24
  public function &offsetGet($offset)
316
  {
317 24
    $return = $this->offsetExists($offset) ? $this->get($offset) : null;
318
319 24
    return $return;
320
  }
321
322
  /**
323
   * Assigns a value to the specified offset.
324
   *
325
   * @param mixed $offset
326
   * @param mixed $value
327
   */
328 17
  public function offsetSet($offset, $value)
329
  {
330 17
    if ($offset === null) {
331 4
      $this->array[] = $value;
332 4
    } else {
333 13
      $this->internalSet($offset, $value);
334
    }
335 17
  }
336
337
  /**
338
   * Unset an offset.
339
   *
340
   * @param mixed $offset
341
   */
342 7
  public function offsetUnset($offset)
343
  {
344 7
    if ($this->isEmpty()) {
345 1
      return;
346
    }
347
348 6
    if (\array_key_exists($offset, $this->array)) {
349 4
      unset($this->array[$offset]);
350
351 4
      return;
352
    }
353
354 3
    if (strpos((string)$offset, $this->pathSeparator) !== false) {
355
356 2
      $path = explode($this->pathSeparator, (string)$offset);
357 2
      $pathToUnset = \array_pop($path);
358
359 2
      $this->callAtPath(
360 2
          implode($this->pathSeparator, $path),
361
          function (&$offset) use ($pathToUnset) {
362 2
            unset($offset[$pathToUnset]);
363 2
          }
364 2
      );
365
366 2
    }
367 3
  }
368
369
  /**
370
   * Serialize the current "Arrayy"-object.
371
   *
372
   * @return string
373
   */
374 1
  public function serialize()
375
  {
376 1
    return parent::serialize();
377
  }
378
379
  /**
380
   * Sets the iterator classname for the current "Arrayy"-object.
381
   *
382
   * @param  string $class
383
   *
384
   * @return void
385
   *
386
   * @throws \InvalidArgumentException
387
   */
388 760
  public function setIteratorClass($class)
389
  {
390 760
    if (class_exists($class)) {
391 760
      $this->iteratorClass = $class;
392
393 760
      return;
394
    }
395
396
    if (strpos($class, '\\') === 0) {
397
      $class = '\\' . $class;
398
      if (class_exists($class)) {
399
        $this->iteratorClass = $class;
400
401
        return;
402
      }
403
    }
404
405
    throw new \InvalidArgumentException('The iterator class does not exist');
406
  }
407
408
  /**
409
   * Sort the entries with a user-defined comparison function and maintain key association
410
   *
411
   * @param  callable $function
412
   *
413
   * @return void
414
   */
415
  public function uasort($function)
416
  {
417
    if (is_callable($function)) {
418
      uasort($this->array, $function);
419
    }
420
  }
421
422
  /**
423
   * Sort the entries by keys using a user-defined comparison function
424
   *
425
   * @param  callable $function
426
   *
427
   * @return void
428
   */
429
  public function uksort($function)
430
  {
431
    if (is_callable($function)) {
432
      uksort($this->array, $function);
433
    }
434
  }
435
436
  /**
437
   * Unserialize an string and return this object.
438
   *
439
   * @param string $string
440
   *
441
   * @return static <p>(Mutable)</p>
442
   */
443 1
  public function unserialize($string)
444
  {
445 1
    parent::unserialize($string);
446
447 1
    return $this;
448
  }
449
450
  /**
451
   * Iterate over the current array and execute a callback for each loop.
452
   *
453
   * @param \Closure $closure
454
   *
455
   * @return static <p>(Immutable)</p>
456
   */
457 2 View Code Duplication
  public function at(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
458
  {
459 2
    $array = $this->array;
460
461 2
    foreach ($array as $key => $value) {
462 2
      $closure($value, $key);
463 2
    }
464
465 2
    return static::create($array);
466
  }
467
468
  /**
469
   * Returns the average value of the current array.
470
   *
471
   * @param int $decimals <p>The number of decimal-numbers to return.</p>
472
   *
473
   * @return int|double <p>The average value.</p>
474
   */
475 10
  public function average($decimals = 0)
476
  {
477 10
    $count = $this->count();
478
479 10
    if (!$count) {
480 2
      return 0;
481
    }
482
483 8
    if (!is_int($decimals)) {
484 3
      $decimals = 0;
485 3
    }
486
487 8
    return round(\array_sum($this->array) / $count, $decimals);
488
  }
489
490
  /**
491
   * @param mixed      $path
492
   * @param callable   $callable
493
   * @param null|array $currentOffset
494
   */
495 3
  protected function callAtPath($path, $callable, &$currentOffset = null)
496
  {
497 3
    if ($currentOffset === null) {
498 3
      $currentOffset = &$this->array;
499 3
    }
500
501 3
    $explodedPath = explode($this->pathSeparator, $path);
502 3
    $nextPath = \array_shift($explodedPath);
503
504 3
    if (!isset($currentOffset[$nextPath])) {
505
      return;
506
    }
507
508 3
    if (!empty($explodedPath)) {
509
      $this->callAtPath(
510
          implode($this->pathSeparator, $explodedPath),
511
          $callable,
512
          $currentOffset[$nextPath]
513
      );
514
    } else {
515 3
      $callable($currentOffset[$nextPath]);
516
    }
517 3
  }
518
519
  /**
520
   * Changes all keys in an array.
521
   *
522
   * @param int $case [optional] <p> Either <strong>CASE_UPPER</strong><br />
523
   *                  or <strong>CASE_LOWER</strong> (default)</p>
524
   *
525
   * @return static <p>(Immutable)</p>
526
   */
527 1
  public function changeKeyCase($case = CASE_LOWER)
528
  {
529 1
    return static::create(UTF8::array_change_key_case($this->array, $case));
0 ignored issues
show
Bug introduced by
The method array_change_key_case() does not seem to exist on object<voku\helper\UTF8>.

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

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

Loading history...
530
  }
531
532
  /**
533
   * Change the path separator of the array wrapper.
534
   *
535
   * By default, the separator is: "."
536
   *
537
   * @param string $separator <p>Separator to set.</p>
538
   *
539
   * @return static <p>Mutable</p>
540
   */
541
  public function changeSeparator($separator)
542
  {
543
    $this->pathSeparator = $separator;
544
545
    return $this;
546
  }
547
548
  /**
549
   * Create a chunked version of the current array.
550
   *
551
   * @param int  $size         <p>Size of each chunk.</p>
552
   * @param bool $preserveKeys <p>Whether array keys are preserved or no.</p>
553
   *
554
   * @return static <p>(Immutable) A new array of chunks from the original array.</p>
555
   */
556 4
  public function chunk($size, $preserveKeys = false)
557
  {
558 4
    $result = \array_chunk($this->array, $size, $preserveKeys);
559
560 4
    return static::create($result);
561
  }
562
563
  /**
564
   * Clean all falsy values from the current array.
565
   *
566
   * @return static <p>(Immutable)</p>
567
   */
568 8
  public function clean()
569
  {
570 8
    return $this->filter(
571
        function ($value) {
572 7
          return (bool)$value;
573
        }
574 8
    );
575
  }
576
577
  /**
578
   * WARNING!!! -> Clear the current array.
579
   *
580
   * @return static <p>(Mutable) Return this Arrayy object, with an empty array.</p>
581
   */
582 4
  public function clear()
583
  {
584 4
    $this->array = array();
585
586 4
    return $this;
587
  }
588
589
  /**
590
   * Check if an item is in the current array.
591
   *
592
   * @param string|int|float $value
593
   *
594
   * @return bool
595
   */
596 13
  public function contains($value)
597
  {
598 13
    return in_array($value, $this->array, true);
599
  }
600
601
  /**
602
   * Check if an (case-insensitive) string is in the current array.
603
   *
604
   * @param string $value
605
   *
606
   * @return bool
607
   */
608 13
  public function containsCaseInsensitive($value)
609
  {
610 13
    return in_array(
611 13
        UTF8::strtolower($value),
612 13
        \array_map(
613
            array(
614 13
                new UTF8(),
615 13
                'strtolower',
616 13
            ),
617 13
            $this->array
618 13
        ),
619
        true
620 13
    );
621
  }
622
623
  /**
624
   * Check if the given key/index exists in the array.
625
   *
626
   * @param string|int|float $key <p>key/index to search for</p>
627
   *
628
   * @return bool <p>Returns true if the given key/index exists in the array, false otherwise.</p>
629
   */
630 4
  public function containsKey($key)
631
  {
632 4
    return $this->offsetExists($key);
633
  }
634
635
  /**
636
   * Check if all given needles are present in the array as key/index.
637
   *
638
   * @param array $needles
639
   *
640
   * @return bool <p>Returns true if the given keys/indexes exists in the array, false otherwise.</p>
641
   */
642 1
  public function containsKeys(array $needles)
643
  {
644 1
    return count(\array_intersect($needles, $this->keys()->getArray())) === count($needles);
645
  }
646
647
  /**
648
   * alias: for "Arrayy->contains()"
649
   *
650
   * @see Arrayy::contains()
651
   *
652
   * @param string|int|float $value
653
   *
654
   * @return bool
655
   */
656
  public function containsValue($value)
657
  {
658
    return $this->contains($value);
659
  }
660
661
  /**
662
   * Check if all given needles are present in the array.
663
   *
664
   * @param array $needles
665
   *
666
   * @return bool <p>Returns true if the given values exists in the array, false otherwise.</p>
667
   */
668 1
  public function containsValues(array $needles)
669
  {
670 1
    return count(\array_intersect($needles, $this->array)) === count($needles);
671
  }
672
673
  /**
674
   * Creates an Arrayy object.
675
   *
676
   * @param array $array
677
   *
678
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
679
   */
680 479
  public static function create($array = array())
681
  {
682 479
    return new static($array);
683
  }
684
685
  /**
686
   * WARNING: Creates an Arrayy object by reference.
687
   *
688
   * @param array $array
689
   *
690
   * @return static <p>(Mutable) Return this Arrayy object.</p>
691
   */
692 1
  public function createByReference(&$array = array())
693
  {
694 1
    $array = $this->fallbackForArray($array);
695
696 1
    $this->array = &$array;
697
698 1
    return $this;
699
  }
700
701
  /**
702
   * Create an new Arrayy object via JSON.
703
   *
704
   * @param string $json
705
   *
706
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
707
   */
708 5
  public static function createFromJson($json)
709
  {
710 5
    $array = UTF8::json_decode($json, true);
711
712 5
    return static::create($array);
713
  }
714
715
  /**
716
   * Create an new instance filled with values from an object that have implemented ArrayAccess.
717
   *
718
   * @param \ArrayAccess $object <p>Object that implements ArrayAccess</p>
719
   *
720
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
721
   */
722 4
  public static function createFromObject(\ArrayAccess $object)
723
  {
724 4
    $array = new static();
725 4
    foreach ($object as $key => $value) {
726
      /** @noinspection OffsetOperationsInspection */
727 3
      $array[$key] = $value;
728 4
    }
729
730 4
    return $array;
731
  }
732
733
  /**
734
   * Create an new Arrayy object via string.
735
   *
736
   * @param string      $str       <p>The input string.</p>
737
   * @param string|null $delimiter <p>The boundary string.</p>
738
   * @param string|null $regEx     <p>Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be
739
   *                               used.</p>
740
   *
741
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
742
   */
743 8
  public static function createFromString($str, $delimiter, $regEx = null)
744
  {
745 8
    if ($regEx) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $regEx of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
746 1
      preg_match_all($regEx, $str, $array);
747
748 1
      if (!empty($array)) {
749 1
        $array = $array[0];
750 1
      }
751
752 1
    } else {
753 7
      $array = explode($delimiter, $str);
754
    }
755
756
    // trim all string in the array
757 8
    \array_walk(
758
        $array,
759
        function (&$val) {
760
          /** @noinspection ReferenceMismatchInspection */
761 8
          if (is_string($val)) {
762 8
            $val = trim($val);
763 8
          }
764 8
        }
765 8
    );
766
767 8
    return static::create($array);
768
  }
769
770
  /**
771
   * Create an new instance containing a range of elements.
772
   *
773
   * @param mixed $low  <p>First value of the sequence.</p>
774
   * @param mixed $high <p>The sequence is ended upon reaching the end value.</p>
775
   * @param int   $step <p>Used as the increment between elements in the sequence.</p>
776
   *
777
   * @return static <p>(Immutable) Returns an new instance of the Arrayy object.</p>
778
   */
779 1
  public static function createWithRange($low, $high, $step = 1)
780
  {
781 1
    return static::create(range($low, $high, $step));
782
  }
783
784
  /**
785
   * Custom sort by index via "uksort".
786
   *
787
   * @link http://php.net/manual/en/function.uksort.php
788
   *
789
   * @param callable $function
790
   *
791
   * @return static <p>(Mutable) Return this Arrayy object.</p>
792
   */
793 5
  public function customSortKeys($function)
794
  {
795 5
    uksort($this->array, $function);
796
797 5
    return $this;
798
  }
799
800
  /**
801
   * Custom sort by value via "usort".
802
   *
803
   * @link http://php.net/manual/en/function.usort.php
804
   *
805
   * @param callable $function
806
   *
807
   * @return static <p>(Mutable) Return this Arrayy object.</p>
808
   */
809 4
  public function customSortValues($function)
810
  {
811 4
    usort($this->array, $function);
812
813 4
    return $this;
814
  }
815
816
  /**
817
   * Return values that are only in the current array.
818
   *
819
   * @param array $array
820
   *
821
   * @return static <p>(Immutable)</p>
822
   */
823 12
  public function diff(array $array = array())
824
  {
825 12
    $result = \array_diff($this->array, $array);
826
827 12
    return static::create($result);
828
  }
829
830
  /**
831
   * Return values that are only in the current multi-dimensional array.
832
   *
833
   * @param array      $array
834
   * @param null|array $helperVariableForRecursion <p>(only for internal usage)</p>
835
   *
836
   * @return static <p>(Immutable)</p>
837
   */
838 1
  public function diffRecursive(array $array = array(), $helperVariableForRecursion = null)
839
  {
840 1
    $result = array();
841
842
    if (
843
        $helperVariableForRecursion !== null
844 1
        &&
845 1
        is_array($helperVariableForRecursion)
846 1
    ) {
847 1
      $arrayForTheLoop = $helperVariableForRecursion;
848 1
    } else {
849 1
      $arrayForTheLoop = $this->array;
850
    }
851
852 1
    foreach ($arrayForTheLoop as $key => $value) {
853 1
      if (\array_key_exists($key, $array)) {
854 1
        if (is_array($value)) {
855 1
          $recursiveDiff = $this->diffRecursive($array[$key], $value);
856 1
          if (!empty($recursiveDiff)) {
857 1
            $result[$key] = $recursiveDiff;
858 1
          }
859 1
        } else {
860 1
          if ($value != $array[$key]) {
861 1
            $result[$key] = $value;
862 1
          }
863
        }
864 1
      } else {
865 1
        $result[$key] = $value;
866
      }
867 1
    }
868
869 1
    return static::create($result);
870
  }
871
872
  /**
873
   * Return values that are only in the new $array.
874
   *
875
   * @param array $array
876
   *
877
   * @return static <p>(Immutable)</p>
878
   */
879 8
  public function diffReverse(array $array = array())
880
  {
881 8
    $result = \array_diff($array, $this->array);
882
883 8
    return static::create($result);
884
  }
885
886
  /**
887
   * Divide an array into two arrays. One with keys and the other with values.
888
   *
889
   * @return static <p>(Immutable)</p>
890
   */
891 1
  public function divide()
892
  {
893 1
    return static::create(
894
        array(
895 1
            $this->keys(),
896 1
            $this->values(),
897
        )
898 1
    );
899
  }
900
901
  /**
902
   * Iterate over the current array and modify the array's value.
903
   *
904
   * @param \Closure $closure
905
   *
906
   * @return static <p>(Immutable)</p>
907
   */
908 4 View Code Duplication
  public function each(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
909
  {
910 4
    $array = $this->array;
911
912 4
    foreach ($array as $key => $value) {
913 4
      $array[$key] = $closure($value, $key);
914 4
    }
915
916 4
    return static::create($array);
917
  }
918
919
  /**
920
   * Check if a value is in the current array using a closure.
921
   *
922
   * @param \Closure $closure
923
   *
924
   * @return bool <p>Returns true if the given value is found, false otherwise.</p>
925
   */
926 4
  public function exists(\Closure $closure)
927
  {
928 4
    $isExists = false;
929 4
    foreach ($this->array as $key => $value) {
930 3
      if ($closure($value, $key)) {
931 1
        $isExists = true;
932 1
        break;
933
      }
934 4
    }
935
936 4
    return $isExists;
937
  }
938
939
  /**
940
   * create a fallback for array
941
   *
942
   * 1. use the current array, if it's a array
943
   * 2. call "getArray()" on object, if there is a "Arrayy"-object
944
   * 3. fallback to empty array, if there is nothing
945
   * 4. call "createFromObject()" on object, if there is a "\ArrayAccess"-object
946
   * 5. call "__toArray()" on object, if the method exists
947
   * 6. cast a string or object with "__toString()" into an array
948
   * 7. throw a "InvalidArgumentException"-Exception
949
   *
950
   * @param $array
951
   *
952
   * @return array
953
   *
954
   * @throws \InvalidArgumentException
955
   */
956 762
  protected function fallbackForArray(&$array)
957
  {
958 762
    if (is_array($array)) {
959 759
      return $array;
960
    }
961
962 10
    if ($array instanceof self) {
963 1
      return $array->getArray();
964
    }
965
966 9
    if (!$array) {
967 6
      return array();
968
    }
969
970 8
    $isObject = is_object($array);
971
972 8
    if ($isObject && $array instanceof \ArrayAccess) {
973
      /** @noinspection ReferenceMismatchInspection */
974
      return static::createFromObject($array)->getArray();
975
    }
976
977 8
    if ($isObject && $array instanceof \ArrayObject) {
978
      return $array->getArrayCopy();
979
    }
980
981 8
    if ($isObject && method_exists($array, '__toArray')) {
982
      return (array)$array->__toArray();
983
    }
984
985
    /** @noinspection ReferenceMismatchInspection */
986
    if (
987 8
        is_string($array)
988
        ||
989 2
        ($isObject && method_exists($array, '__toString'))
990 8
    ) {
991 6
      return array((string)$array);
992
    }
993
994 2
    throw new \InvalidArgumentException(
995
        'Passed value should be a array'
996 2
    );
997
  }
998
999
  /**
1000
   * Find all items in an array that pass the truth test.
1001
   *
1002
   * @param \Closure|null $closure
1003
   *
1004
   * @return static <p>(Immutable)</p>
1005
   */
1006 9
  public function filter($closure = null)
1007
  {
1008 9
    if (!$closure) {
1009 1
      return $this->clean();
1010
    }
1011
1012 9
    $array = \array_filter($this->array, $closure);
1013
1014 9
    return static::create($array);
1015
  }
1016
1017
  /**
1018
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
1019
   * within that.
1020
   *
1021
   * @param string $property
1022
   * @param string $value
1023
   * @param string $comparisonOp
1024
   *                            <p>
1025
   *                            'eq' (equals),<br />
1026
   *                            'gt' (greater),<br />
1027
   *                            'gte' || 'ge' (greater or equals),<br />
1028
   *                            'lt' (less),<br />
1029
   *                            'lte' || 'le' (less or equals),<br />
1030
   *                            'ne' (not equals),<br />
1031
   *                            'contains',<br />
1032
   *                            'notContains',<br />
1033
   *                            'newer' (via strtotime),<br />
1034
   *                            'older' (via strtotime),<br />
1035
   *                            </p>
1036
   *
1037
   * @return static <p>(Immutable)</p>
1038
   */
1039 1
  public function filterBy($property, $value, $comparisonOp = null)
1040
  {
1041 1
    if (!$comparisonOp) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $comparisonOp of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1042 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
1043 1
    }
1044
1045
    $ops = array(
1046
        'eq'          => function ($item, $prop, $value) {
1047 1
          return $item[$prop] === $value;
1048 1
        },
1049
        'gt'          => function ($item, $prop, $value) {
1050
          return $item[$prop] > $value;
1051 1
        },
1052
        'ge'          => function ($item, $prop, $value) {
1053
          return $item[$prop] >= $value;
1054 1
        },
1055
        'gte'         => function ($item, $prop, $value) {
1056
          return $item[$prop] >= $value;
1057 1
        },
1058
        'lt'          => function ($item, $prop, $value) {
1059 1
          return $item[$prop] < $value;
1060 1
        },
1061
        'le'          => function ($item, $prop, $value) {
1062
          return $item[$prop] <= $value;
1063 1
        },
1064
        'lte'         => function ($item, $prop, $value) {
1065
          return $item[$prop] <= $value;
1066 1
        },
1067
        'ne'          => function ($item, $prop, $value) {
1068
          return $item[$prop] !== $value;
1069 1
        },
1070
        'contains'    => function ($item, $prop, $value) {
1071 1
          return in_array($item[$prop], (array)$value, true);
1072 1
        },
1073
        'notContains' => function ($item, $prop, $value) {
1074
          return !in_array($item[$prop], (array)$value, true);
1075 1
        },
1076
        'newer'       => function ($item, $prop, $value) {
1077
          return strtotime($item[$prop]) > strtotime($value);
1078 1
        },
1079
        'older'       => function ($item, $prop, $value) {
1080
          return strtotime($item[$prop]) < strtotime($value);
1081 1
        },
1082 1
    );
1083
1084 1
    $result = \array_values(
1085 1
        \array_filter(
1086 1
            (array)$this->array,
1087
            function ($item) use (
1088 1
                $property,
1089 1
                $value,
1090 1
                $ops,
1091 1
                $comparisonOp
1092
            ) {
1093 1
              $item = (array)$item;
1094 1
              $itemArrayy = new Arrayy($item);
1095 1
              $item[$property] = $itemArrayy->get($property, array());
1096
1097 1
              return $ops[$comparisonOp]($item, $property, $value);
1098
            }
1099 1
        )
1100 1
    );
1101
1102 1
    return static::create($result);
1103
  }
1104
1105
  /**
1106
   * Find the first item in an array that passes the truth test,
1107
   *  otherwise return false
1108
   *
1109
   * @param \Closure $closure
1110
   *
1111
   * @return mixed|false <p>Return false if we did not find the value.</p>
1112
   */
1113 8
  public function find(\Closure $closure)
1114
  {
1115 8
    foreach ($this->array as $key => $value) {
1116 6
      if ($closure($value, $key)) {
1117 5
        return $value;
1118
      }
1119 5
    }
1120
1121 3
    return false;
1122
  }
1123
1124
  /**
1125
   * find by ...
1126
   *
1127
   * @param string $property
1128
   * @param string $value
1129
   * @param string $comparisonOp
1130
   *
1131
   * @return static <p>(Immutable)</p>
1132
   */
1133
  public function findBy($property, $value, $comparisonOp = 'eq')
1134
  {
1135
    return $this->filterBy($property, $value, $comparisonOp);
1136
  }
1137
1138
  /**
1139
   * Get the first value from the current array.
1140
   *
1141
   * @return mixed <p>Return null if there wasn't a element.</p>
1142
   */
1143 13
  public function first()
1144
  {
1145 13
    $tmpArray = $this->array;
1146 13
    $result = \array_shift($tmpArray);
1147
1148 13
    if ($result === null) {
1149 3
      return null;
1150
    }
1151
1152 10
    return $result;
1153
  }
1154
1155
  /**
1156
   * Get the first value(s) from the current array.
1157
   *
1158
   * @param int|null $number <p>How many values you will take?</p>
1159
   *
1160
   * @return static <p>(Immutable)</p>
1161
   */
1162 28
  public function firstsImmutable($number = null)
1163
  {
1164 28
    if ($number === null) {
1165 7
      $arrayTmp = $this->array;
1166 7
      $array = (array)\array_shift($arrayTmp);
1167 7
    } else {
1168 21
      $number = (int)$number;
1169 21
      $arrayTmp = $this->array;
1170 21
      $array = \array_splice($arrayTmp, 0, $number, true);
1171
    }
1172
1173 28
    return static::create($array);
1174
  }
1175
1176
  /**
1177
   * Get the first value(s) from the current array.
1178
   *
1179
   * @param int|null $number <p>How many values you will take?</p>
1180
   *
1181
   * @return static <p>(Mutable)</p>
1182
   */
1183 26
  public function firstsMutable($number = null)
1184
  {
1185 26
    if ($number === null) {
1186 11
      $this->array = (array)\array_shift($this->array);
1187 11
    } else {
1188 15
      $number = (int)$number;
1189 15
      $this->array = \array_splice($this->array, 0, $number, true);
1190
    }
1191
1192 26
    return $this;
1193
  }
1194
1195
  /**
1196
   * Exchanges all keys with their associated values in an array.
1197
   *
1198
   * @return static <p>(Immutable)</p>
1199
   */
1200 1
  public function flip()
1201
  {
1202 1
    $result = \array_flip($this->array);
1203
1204 1
    return static::create($result);
1205
  }
1206
1207
  /**
1208
   * Get a value from an array (optional using dot-notation).
1209
   *
1210
   * @param string $key      <p>The key to look for.</p>
1211
   * @param mixed  $fallback <p>Value to fallback to.</p>
1212
   * @param array  $array    <p>The array to get from, if it's set to "null" we use the current array from the
1213
   *                         class.</p>
1214
   *
1215
   * @return mixed
1216
   */
1217 58
  public function get($key, $fallback = null, $array = null)
1218
  {
1219
    if (
1220
        $array !== null
1221 58
        &&
1222 3
        is_array($array)
1223 58
    ) {
1224 3
      $usedArray = $array;
1225 3
    } else {
1226 56
      $usedArray = $this->array;
1227
    }
1228
1229 58
    if ($key === null) {
1230 1
      return static::create($usedArray);
1231
    }
1232
1233
    // php cast "bool"-index into "int"-index
1234 58
    if ((bool)$key === $key) {
1235 2
      $key = (int)$key;
1236 2
    }
1237
1238 58
    if (\array_key_exists($key, $usedArray) === true) {
1239 48
      if (is_array($usedArray[$key])) {
1240 5
        return static::create($usedArray[$key]);
1241
      }
1242
1243 45
      return $usedArray[$key];
1244
    }
1245
1246
    // Crawl through array, get key according to object or not
1247 19
    foreach (explode($this->pathSeparator, (string)$key) as $segment) {
1248 19
      if (!isset($usedArray[$segment])) {
1249 19
        return $fallback instanceof \Closure ? $fallback() : $fallback;
1250
      }
1251
1252 4
      $usedArray = $usedArray[$segment];
1253 4
    }
1254
1255 4
    if (is_array($usedArray)) {
1256
      return static::create($usedArray);
1257
    }
1258
1259 4
    return $usedArray;
1260
  }
1261
1262
  /**
1263
   * Get the current array from the "Arrayy"-object.
1264
   *
1265
   * @return array
1266
   */
1267 488
  public function getArray()
1268
  {
1269 488
    \array_map(array('self', 'internalGetArray'), $this->array);
1270
1271 488
    return $this->array;
1272
  }
1273
1274
  /**
1275
   * Returns the values from a single column of the input array, identified by
1276
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1277
   *
1278
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1279
   * array by the values from the $indexKey column in the input array.
1280
   *
1281
   * @param mixed $columnKey
1282
   * @param mixed $indexKey
1283
   *
1284
   * @return static <p>(Immutable)</p>
1285
   */
1286 1
  public function getColumn($columnKey = null, $indexKey = null)
1287
  {
1288 1
    $result = \array_column($this->array, $columnKey, $indexKey);
1289
1290 1
    return static::create($result);
1291
  }
1292
1293
  /**
1294
   * Get correct PHP constant for direction.
1295
   *
1296
   * @param int|string $direction
1297
   *
1298
   * @return int
1299
   */
1300 38
  protected function getDirection($direction)
1301
  {
1302 38
    if (is_string($direction)) {
1303 10
      $direction = strtolower($direction);
1304
1305 10
      if ($direction === 'desc') {
1306 2
        $direction = SORT_DESC;
1307 2
      } else {
1308 8
        $direction = SORT_ASC;
1309
      }
1310 10
    }
1311
1312
    if (
1313
        $direction !== SORT_DESC
1314 38
        &&
1315
        $direction !== SORT_ASC
1316 38
    ) {
1317
      $direction = SORT_ASC;
1318
    }
1319
1320 38
    return $direction;
1321
  }
1322
1323
  /**
1324
   * alias: for "Arrayy->keys()"
1325
   *
1326
   * @see Arrayy::keys()
1327
   *
1328
   * @return static <p>(Immutable)</p>
1329
   */
1330 1
  public function getKeys()
1331
  {
1332 1
    return $this->keys();
1333
  }
1334
1335
  /**
1336
   * alias: for "Arrayy->randomImmutable()"
1337
   *
1338
   * @see Arrayy::randomImmutable()
1339
   *
1340
   * @return static <p>(Immutable)</p>
1341
   */
1342 3
  public function getRandom()
1343
  {
1344 3
    return $this->randomImmutable();
1345
  }
1346
1347
  /**
1348
   * alias: for "Arrayy->randomKey()"
1349
   *
1350
   * @see Arrayy::randomKey()
1351
   *
1352
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
1353
   */
1354 3
  public function getRandomKey()
1355
  {
1356 3
    return $this->randomKey();
1357
  }
1358
1359
  /**
1360
   * alias: for "Arrayy->randomKeys()"
1361
   *
1362
   * @see Arrayy::randomKeys()
1363
   *
1364
   * @param int $number
1365
   *
1366
   * @return static <p>(Immutable)</p>
1367
   */
1368 9
  public function getRandomKeys($number)
1369
  {
1370 9
    return $this->randomKeys($number);
1371
  }
1372
1373
  /**
1374
   * alias: for "Arrayy->randomValue()"
1375
   *
1376
   * @see Arrayy::randomValue()
1377
   *
1378
   * @return mixed <p>get a random value or null if there wasn't a value.</p>
1379
   */
1380 3
  public function getRandomValue()
1381
  {
1382 3
    return $this->randomValue();
1383
  }
1384
1385
  /**
1386
   * alias: for "Arrayy->randomValues()"
1387
   *
1388
   * @see Arrayy::randomValues()
1389
   *
1390
   * @param int $number
1391
   *
1392
   * @return static <p>(Immutable)</p>
1393
   */
1394 6
  public function getRandomValues($number)
1395
  {
1396 6
    return $this->randomValues($number);
1397
  }
1398
1399
  /**
1400
   * Group values from a array according to the results of a closure.
1401
   *
1402
   * @param string $grouper <p>A callable function name.</p>
1403
   * @param bool   $saveKeys
1404
   *
1405
   * @return static <p>(Immutable)</p>
1406
   */
1407 3
  public function group($grouper, $saveKeys = false)
1408
  {
1409 3
    $array = (array)$this->array;
1410 3
    $result = array();
1411
1412
    // Iterate over values, group by property/results from closure
1413 3
    foreach ($array as $key => $value) {
1414
1415 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
1416 3
      $newValue = $this->get($groupKey, null, $result);
1417
1418 3
      if ($groupKey instanceof self) {
1419
        $groupKey = $groupKey->getArray();
1420
      }
1421
1422 3
      if ($newValue instanceof self) {
1423 3
        $newValue = $newValue->getArray();
1424 3
      }
1425
1426
      // Add to results
1427 3
      if ($groupKey !== null) {
1428 2
        if ($saveKeys) {
1429 1
          $result[$groupKey] = $newValue;
1430 1
          $result[$groupKey][$key] = $value;
1431 1
        } else {
1432 1
          $result[$groupKey] = $newValue;
1433 1
          $result[$groupKey][] = $value;
1434
        }
1435 2
      }
1436
1437 3
    }
1438
1439 3
    return static::create($result);
1440
  }
1441
1442
  /**
1443
   * Check if an array has a given key.
1444
   *
1445
   * @param mixed $key
1446
   *
1447
   * @return bool
1448
   */
1449 22
  public function has($key)
1450
  {
1451
    // Generate unique string to use as marker.
1452 22
    $unFound = (string)uniqid('arrayy', true);
1453
1454 22
    return $this->get($key, $unFound) !== $unFound;
1455
  }
1456
1457
  /**
1458
   * Implodes an array.
1459
   *
1460
   * @param string $glue
1461
   *
1462
   * @return string
1463
   */
1464 27
  public function implode($glue = '')
1465
  {
1466 27
    return implode($glue, $this->array);
1467
  }
1468
1469
  /**
1470
   * Given a list and an iterate-function that returns
1471
   * a key for each element in the list (or a property name),
1472
   * returns an object with an index of each item.
1473
   *
1474
   * Just like groupBy, but for when you know your keys are unique.
1475
   *
1476
   * @param mixed $key
1477
   *
1478
   * @return static <p>(Immutable)</p>
1479
   */
1480 3
  public function indexBy($key)
1481
  {
1482 3
    $results = array();
1483
1484 3
    foreach ($this->array as $a) {
1485 3
      if (\array_key_exists($key, $a) === true) {
1486 2
        $results[$a[$key]] = $a;
1487 2
      }
1488 3
    }
1489
1490 3
    return static::create($results);
1491
  }
1492
1493
  /**
1494
   * alias: for "Arrayy->searchIndex()"
1495
   *
1496
   * @see Arrayy::searchIndex()
1497
   *
1498
   * @param mixed $value <p>The value to search for.</p>
1499
   *
1500
   * @return mixed
1501
   */
1502 4
  public function indexOf($value)
1503
  {
1504 4
    return $this->searchIndex($value);
1505
  }
1506
1507
  /**
1508
   * Get everything but the last..$to items.
1509
   *
1510
   * @param int $to
1511
   *
1512
   * @return static <p>(Immutable)</p>
1513
   */
1514 12
  public function initial($to = 1)
1515
  {
1516 12
    $slice = count($this->array) - $to;
1517
1518 12
    return $this->firstsImmutable($slice);
1519
  }
1520
1521
  /**
1522
   * @param mixed $value
1523
   */
1524 403
  protected function internalGetArray(&$value)
1525
  {
1526 403
    if ($value instanceof self) {
1527
      $value &= $value->getArray();
1528 403
    } elseif ($value instanceof \JsonSerializable) {
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1529
      $value &= $value->jsonSerialize();
1530
    }
1531 403
  }
1532
1533
  /**
1534
   * Internal mechanics of remove method.
1535
   *
1536
   * @param string $key
1537
   *
1538
   * @return boolean
1539
   */
1540 18
  protected function internalRemove($key)
1541
  {
1542 18
    $path = explode($this->pathSeparator, (string)$key);
1543
1544
    // Crawl though the keys
1545 18
    while (count($path) > 1) {
1546
      $key = \array_shift($path);
1547
1548
      if (!$this->has($key)) {
1549
        return false;
1550
      }
1551
1552
      $this->array = &$this->array[$key];
1553
    }
1554
1555 18
    $key = \array_shift($path);
1556
1557 18
    unset($this->array[$key]);
1558
1559 18
    return true;
1560
  }
1561
1562
  /**
1563
   * Internal mechanic of set method.
1564
   *
1565
   * @param string $key
1566
   * @param mixed  $value
1567
   *
1568
   * @return bool
1569
   */
1570 30
  protected function internalSet($key, $value)
1571
  {
1572 30
    if ($key === null) {
1573
      return false;
1574
    }
1575
1576
    // init
1577 30
    $array =& $this->array;
1578 30
    $path = explode($this->pathSeparator, (string)$key);
1579
1580
    // Crawl through the keys
1581 30
    while (count($path) > 1) {
1582 3
      $key = \array_shift($path);
1583
1584
      // If the key doesn't exist at this depth, we will just create an empty array
1585
      // to hold the next value, allowing us to create the arrays to hold final
1586
      // values at the correct depth. Then we'll keep digging into the array.
1587 3
      if (!isset($array[$key]) || !is_array($array[$key])) {
1588
        $array[$key] = static::create(array());
1589
      }
1590
1591 3
      $array =& $array[$key];
1592 3
    }
1593
1594 30
    $array[\array_shift($path)] = $value;
1595
1596 30
    return true;
1597
  }
1598
1599
  /**
1600
   * Return an array with all elements found in input array.
1601
   *
1602
   * @param array $search
1603
   *
1604
   * @return static <p>(Immutable)</p>
1605
   */
1606 2
  public function intersection(array $search)
1607
  {
1608 2
    return static::create(\array_values(\array_intersect($this->array, $search)));
1609
  }
1610
1611
  /**
1612
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1613
   *
1614
   * @param array $search
1615
   *
1616
   * @return bool
1617
   */
1618 1
  public function intersects(array $search)
1619
  {
1620 1
    return count($this->intersection($search)->array) > 0;
1621
  }
1622
1623
  /**
1624
   * Invoke a function on all of an array's values.
1625
   *
1626
   * @param mixed $callable
1627
   * @param mixed $arguments
1628
   *
1629
   * @return static <p>(Immutable)</p>
1630
   */
1631 1
  public function invoke($callable, $arguments = array())
1632
  {
1633
    // If one argument given for each iteration, create an array for it.
1634 1
    if (!is_array($arguments)) {
1635 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1636 1
    }
1637
1638
    // If the callable has arguments, pass them.
1639 1
    if ($arguments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $arguments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1640 1
      $array = \array_map($callable, $this->array, $arguments);
1641 1
    } else {
1642 1
      $array = \array_map($callable, $this->array);
1643
    }
1644
1645 1
    return static::create($array);
1646
  }
1647
1648
  /**
1649
   * Check whether array is associative or not.
1650
   *
1651
   * @return bool <p>Returns true if associative, false otherwise.</p>
1652
   */
1653 15
  public function isAssoc()
1654
  {
1655 15
    if ($this->isEmpty()) {
1656 3
      return false;
1657
    }
1658
1659 13
    foreach ($this->keys()->getArray() as $key) {
1660 13
      if (!is_string($key)) {
1661 11
        return false;
1662
      }
1663 3
    }
1664
1665 3
    return true;
1666
  }
1667
1668
  /**
1669
   * Check whether the array is empty or not.
1670
   *
1671
   * @return bool <p>Returns true if empty, false otherwise.</p>
1672
   */
1673 86
  public function isEmpty()
1674
  {
1675 86
    return !$this->array;
1676
  }
1677
1678
  /**
1679
   * Check if the current array is equal to the given "$array" or not.
1680
   *
1681
   * @param array $array
1682
   *
1683
   * @return bool
1684
   */
1685
  public function isEqual(array $array)
1686
  {
1687
    return ($this->array === $array);
1688
  }
1689
1690
  /**
1691
   * Check if the current array is a multi-array.
1692
   *
1693
   * @return bool
1694
   */
1695 14
  public function isMultiArray()
1696
  {
1697 14
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
1698
  }
1699
1700
  /**
1701
   * Check whether array is numeric or not.
1702
   *
1703
   * @return bool <p>Returns true if numeric, false otherwise.</p>
1704
   */
1705 5
  public function isNumeric()
1706
  {
1707 5
    if ($this->isEmpty()) {
1708 2
      return false;
1709
    }
1710
1711 4
    foreach ($this->keys() as $key) {
1712 4
      if (!is_int($key)) {
1713 2
        return false;
1714
      }
1715 3
    }
1716
1717 2
    return true;
1718
  }
1719
1720
  /**
1721
   * Check if the current array is sequential [0, 1, 2, 3, 4, 5 ...] or not.
1722
   *
1723
   * @return bool
1724
   */
1725 1
  public function isSequential()
1726
  {
1727 1
    return \array_keys($this->array) === range(0, count($this->array) - 1);
1728
  }
1729
1730
  /**
1731
   * @return array
1732
   */
1733
  public function jsonSerialize()
1734
  {
1735
    return $this->getArray();
1736
  }
1737
1738
  /**
1739
   * Get all keys from the current array.
1740
   *
1741
   * @return static <p>(Immutable)</p>
1742
   */
1743 25
  public function keys()
1744
  {
1745 25
    return static::create(\array_keys($this->array));
1746
  }
1747
1748
  /**
1749
   * Get the last value from the current array.
1750
   *
1751
   * @return mixed <p>Return null if there wasn't a element.</p>
1752
   */
1753 4
  public function last()
1754
  {
1755 4
    return $this->pop();
1756
  }
1757
1758
  /**
1759
   * Get the last value(s) from the current array.
1760
   *
1761
   * @param int|null $number
1762
   *
1763
   * @return static <p>(Immutable)</p>
1764
   */
1765 13
  public function lastsImmutable($number = null)
1766
  {
1767 13
    if ($this->isEmpty()) {
1768 1
      return static::create();
1769
    }
1770
1771 12
    if ($number === null) {
1772 8
      $poppedValue = $this->pop();
1773
1774 8
      if ($poppedValue === null) {
1775 1
        $poppedValue = array($poppedValue);
1776 1
      } else {
1777 7
        $poppedValue = (array)$poppedValue;
1778
      }
1779
1780 8
      $arrayy = static::create($poppedValue);
1781 8
    } else {
1782 4
      $number = (int)$number;
1783 4
      $arrayy = $this->rest(-$number);
1784
    }
1785
1786 12
    return $arrayy;
1787
  }
1788
1789
  /**
1790
   * Get the last value(s) from the current array.
1791
   *
1792
   * @param int|null $number
1793
   *
1794
   * @return static <p>(Mutable)</p>
1795
   */
1796 13
  public function lastsMutable($number = null)
1797
  {
1798 13
    if ($this->isEmpty()) {
1799 1
      return $this;
1800
    }
1801
1802 12
    if ($number === null) {
1803 8
      $poppedValue = $this->pop();
1804
1805 8
      if ($poppedValue === null) {
1806 1
        $poppedValue = array($poppedValue);
1807 1
      } else {
1808 7
        $poppedValue = (array)$poppedValue;
1809
      }
1810
1811 8
      $this->array = static::create($poppedValue)->array;
1812 8
    } else {
1813 4
      $number = (int)$number;
1814 4
      $this->array = $this->rest(-$number)->array;
1815
    }
1816
1817 12
    return $this;
1818
  }
1819
1820
  /**
1821
   * Count the values from the current array.
1822
   *
1823
   * alias: for "Arrayy->size()"
1824
   *
1825
   * @see Arrayy::size()
1826
   *
1827
   * @return int
1828
   */
1829 10
  public function length()
1830
  {
1831 10
    return $this->size();
1832
  }
1833
1834
  /**
1835
   * Apply the given function to the every element of the array,
1836
   * collecting the results.
1837
   *
1838
   * @param callable $callable
1839
   *
1840
   * @return static <p>(Immutable) Arrayy object with modified elements.</p>
1841
   */
1842 4
  public function map($callable)
1843
  {
1844 4
    $result = \array_map($callable, $this->array);
1845
1846 4
    return static::create($result);
1847
  }
1848
1849
  /**
1850
   * Check if all items in current array match a truth test.
1851
   *
1852
   * @param \Closure $closure
1853
   *
1854
   * @return bool
1855
   */
1856 15 View Code Duplication
  public function matches(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1857
  {
1858 15
    if (count($this->array) === 0) {
1859 2
      return false;
1860
    }
1861
1862
    // init
1863 13
    $array = $this->array;
1864
1865 13
    foreach ($array as $key => $value) {
1866 13
      $value = $closure($value, $key);
1867
1868 13
      if ($value === false) {
1869 7
        return false;
1870
      }
1871 9
    }
1872
1873 7
    return true;
1874
  }
1875
1876
  /**
1877
   * Check if any item in the current array matches a truth test.
1878
   *
1879
   * @param \Closure $closure
1880
   *
1881
   * @return bool
1882
   */
1883 14 View Code Duplication
  public function matchesAny(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1884
  {
1885 14
    if (count($this->array) === 0) {
1886 2
      return false;
1887
    }
1888
1889
    // init
1890 12
    $array = $this->array;
1891
1892 12
    foreach ($array as $key => $value) {
1893 12
      $value = $closure($value, $key);
1894
1895 12
      if ($value === true) {
1896 9
        return true;
1897
      }
1898 5
    }
1899
1900 4
    return false;
1901
  }
1902
1903
  /**
1904
   * Get the max value from an array.
1905
   *
1906
   * @return mixed
1907
   */
1908 10
  public function max()
1909
  {
1910 10
    if ($this->count() === 0) {
1911 1
      return false;
1912
    }
1913
1914 9
    return max($this->array);
1915
  }
1916
1917
  /**
1918
   * Merge the new $array into the current array.
1919
   *
1920
   * - keep key,value from the current array, also if the index is in the new $array
1921
   *
1922
   * @param array $array
1923
   * @param bool  $recursive
1924
   *
1925
   * @return static <p>(Immutable)</p>
1926
   */
1927 25 View Code Duplication
  public function mergeAppendKeepIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1928
  {
1929 25
    if (true === $recursive) {
1930 4
      $result = \array_replace_recursive($this->array, $array);
1931 4
    } else {
1932 21
      $result = \array_replace($this->array, $array);
1933
    }
1934
1935 25
    return static::create($result);
1936
  }
1937
1938
  /**
1939
   * Merge the new $array into the current array.
1940
   *
1941
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1942
   * - create new indexes
1943
   *
1944
   * @param array $array
1945
   * @param bool  $recursive
1946
   *
1947
   * @return static <p>(Immutable)</p>
1948
   */
1949 16 View Code Duplication
  public function mergeAppendNewIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1950
  {
1951 16
    if (true === $recursive) {
1952 4
      $result = \array_merge_recursive($this->array, $array);
1953 4
    } else {
1954 12
      $result = \array_merge($this->array, $array);
1955
    }
1956
1957 16
    return static::create($result);
1958
  }
1959
1960
  /**
1961
   * Merge the the current array into the $array.
1962
   *
1963
   * - use key,value from the new $array, also if the index is in the current array
1964
   *
1965
   * @param array $array
1966
   * @param bool  $recursive
1967
   *
1968
   * @return static <p>(Immutable)</p>
1969
   */
1970 16 View Code Duplication
  public function mergePrependKeepIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1971
  {
1972 16
    if (true === $recursive) {
1973 4
      $result = \array_replace_recursive($array, $this->array);
1974 4
    } else {
1975 12
      $result = \array_replace($array, $this->array);
1976
    }
1977
1978 16
    return static::create($result);
1979
  }
1980
1981
  /**
1982
   * Merge the current array into the new $array.
1983
   *
1984
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1985
   * - create new indexes
1986
   *
1987
   * @param array $array
1988
   * @param bool  $recursive
1989
   *
1990
   * @return static <p>(Immutable)</p>
1991
   */
1992 16 View Code Duplication
  public function mergePrependNewIndex(array $array = array(), $recursive = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1993
  {
1994 16
    if (true === $recursive) {
1995 4
      $result = \array_merge_recursive($array, $this->array);
1996 4
    } else {
1997 12
      $result = \array_merge($array, $this->array);
1998
    }
1999
2000 16
    return static::create($result);
2001
  }
2002
2003
  /**
2004
   * Get the min value from an array.
2005
   *
2006
   * @return mixed
2007
   */
2008 10
  public function min()
2009
  {
2010 10
    if ($this->count() === 0) {
2011 1
      return false;
2012
    }
2013
2014 9
    return min($this->array);
2015
  }
2016
2017
  /**
2018
   * Move an array element to a new index.
2019
   *
2020
   * cherry-picked from: http://stackoverflow.com/questions/12624153/move-an-array-element-to-a-new-index-in-php
2021
   *
2022
   * @param int|string $from
2023
   * @param int|string $to
2024
   *
2025
   * @return static <p>(Immutable)</p>
2026
   */
2027 1
  public function moveElement($from, $to)
2028
  {
2029 1
    $array = $this->array;
2030
2031 1
    if (is_int($from)) {
2032 1
      $tmp = \array_splice($array, $from, 1);
2033 1
      \array_splice($array, $to, 0, $tmp);
2034 1
      $output = $array;
2035 1
    } elseif (is_string($from)) {
2036 1
      $indexToMove = \array_search($from, \array_keys($array), true);
2037 1
      $itemToMove = $array[$from];
2038 1
      \array_splice($array, $indexToMove, 1);
2039 1
      $i = 0;
2040 1
      $output = array();
2041 1
      foreach ($array as $key => $item) {
2042 1
        if ($i == $to) {
2043 1
          $output[$from] = $itemToMove;
2044 1
        }
2045 1
        $output[$key] = $item;
2046 1
        $i++;
2047 1
      }
2048 1
    } else {
2049
      $output = array();
2050
    }
2051
2052 1
    return static::create($output);
2053
  }
2054
2055
  /**
2056
   * Get a subset of the items from the given array.
2057
   *
2058
   * @param mixed[] $keys
2059
   *
2060
   * @return static <p>(Immutable)</p>
2061
   */
2062
  public function only(array $keys)
2063
  {
2064
    $array = $this->array;
2065
2066
    return static::create(\array_intersect_key($array, \array_flip($keys)));
2067
  }
2068
2069
  /**
2070
   * Pad array to the specified size with a given value.
2071
   *
2072
   * @param int   $size  <p>Size of the result array.</p>
2073
   * @param mixed $value <p>Empty value by default.</p>
2074
   *
2075
   * @return static <p>(Immutable) Arrayy object padded to $size with $value.</p>
2076
   */
2077 4
  public function pad($size, $value)
2078
  {
2079 4
    $result = \array_pad($this->array, $size, $value);
2080
2081 4
    return static::create($result);
2082
  }
2083
2084
  /**
2085
   * Pop a specified value off the end of the current array.
2086
   *
2087
   * @return mixed <p>(Mutable) The popped element from the current array.</p>
2088
   */
2089 16
  public function pop()
2090
  {
2091 16
    return \array_pop($this->array);
2092
  }
2093
2094
  /**
2095
   * Prepend a value to the current array.
2096
   *
2097
   * @param mixed $value
2098
   * @param mixed $key
2099
   *
2100
   * @return static <p>(Mutable) Return this Arrayy object, with the prepended value.</p>
2101
   */
2102 8
  public function prepend($value, $key = null)
2103
  {
2104 8
    if ($key === null) {
2105 8
      \array_unshift($this->array, $value);
2106 8
    } else {
2107
      /** @noinspection AdditionOperationOnArraysInspection */
2108 1
      $this->array = array($key => $value) + $this->array;
2109
    }
2110
2111 8
    return $this;
2112
  }
2113
2114
  /**
2115
   * Push one or more values onto the end of array at once.
2116
   *
2117
   * @return static <p>(Mutable) Return this Arrayy object, with pushed elements to the end of array.</p>
2118
   */
2119 4 View Code Duplication
  public function push(/* variadic arguments allowed */)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2120
  {
2121 4
    if (func_num_args()) {
2122 4
      $args = \array_merge(array(&$this->array), func_get_args());
2123 4
      call_user_func_array('array_push', $args);
2124 4
    }
2125
2126 4
    return $this;
2127
  }
2128
2129
  /**
2130
   * Get a random value from the current array.
2131
   *
2132
   * @param null|int $number <p>How many values you will take?</p>
2133
   *
2134
   * @return static <p>(Immutable)</p>
2135
   */
2136 17
  public function randomImmutable($number = null)
2137
  {
2138 17
    if ($this->count() === 0) {
2139
      return static::create();
2140
    }
2141
2142 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2143 14
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2144
2145 14
      return static::create($arrayRandValue);
2146
    }
2147
2148 5
    $arrayTmp = $this->array;
2149 5
    shuffle($arrayTmp);
2150
2151 5
    return static::create($arrayTmp)->firstsImmutable($number);
2152
  }
2153
2154
  /**
2155
   * Pick a random key/index from the keys of this array.
2156
   *
2157
   * @return mixed <p>Get a key/index or null if there wasn't a key/index.</p>
2158
   *
2159
   * @throws \RangeException If array is empty
2160
   */
2161 4
  public function randomKey()
2162
  {
2163 4
    $result = $this->randomKeys(1);
2164
2165 4
    if (!isset($result[0])) {
2166
      $result[0] = null;
2167
    }
2168
2169 4
    return $result[0];
2170
  }
2171
2172
  /**
2173
   * Pick a given number of random keys/indexes out of this array.
2174
   *
2175
   * @param int $number <p>The number of keys/indexes (should be <= $this->count())</p>
2176
   *
2177
   * @return static <p>(Immutable)</p>
2178
   *
2179
   * @throws \RangeException If array is empty
2180
   */
2181 14
  public function randomKeys($number)
2182
  {
2183 14
    $number = (int)$number;
2184 14
    $count = $this->count();
2185
2186 14
    if ($number === 0 || $number > $count) {
2187 3
      throw new \RangeException(
2188 3
          sprintf(
2189 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
2190 3
              $number,
2191
              $count
2192 3
          )
2193 3
      );
2194
    }
2195
2196 11
    $result = (array)\array_rand($this->array, $number);
2197
2198 11
    return static::create($result);
2199
  }
2200
2201
  /**
2202
   * Get a random value from the current array.
2203
   *
2204
   * @param null|int $number <p>How many values you will take?</p>
2205
   *
2206
   * @return static <p>(Mutable)</p>
2207
   */
2208 17
  public function randomMutable($number = null)
2209
  {
2210 17
    if ($this->count() === 0) {
2211
      return static::create();
2212
    }
2213
2214 17 View Code Duplication
    if ($number === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2215 7
      $arrayRandValue = array($this->array[\array_rand($this->array)]);
2216 7
      $this->array = $arrayRandValue;
2217
2218 7
      return $this;
2219
    }
2220
2221 11
    shuffle($this->array);
2222
2223 11
    return $this->firstsMutable($number);
2224
  }
2225
2226
  /**
2227
   * Pick a random value from the values of this array.
2228
   *
2229
   * @return mixed <p>Get a random value or null if there wasn't a value.</p>
2230
   */
2231 4
  public function randomValue()
2232
  {
2233 4
    $result = $this->randomImmutable();
2234
2235 4
    if (!isset($result[0])) {
2236
      $result[0] = null;
2237
    }
2238
2239 4
    return $result[0];
2240
  }
2241
2242
  /**
2243
   * Pick a given number of random values out of this array.
2244
   *
2245
   * @param int $number
2246
   *
2247
   * @return static <p>(Mutable)</p>
2248
   */
2249 7
  public function randomValues($number)
2250
  {
2251 7
    $number = (int)$number;
2252
2253 7
    return $this->randomMutable($number);
2254
  }
2255
2256
  /**
2257
   * Get a random value from an array, with the ability to skew the results.
2258
   *
2259
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
2260
   *
2261
   * @param array    $array
2262
   * @param null|int $number <p>How many values you will take?</p>
2263
   *
2264
   * @return static <p>(Immutable)</p>
2265
   */
2266 9
  public function randomWeighted(array $array, $number = null)
2267
  {
2268 9
    $options = array();
2269 9
    foreach ($array as $option => $weight) {
2270 9
      if ($this->searchIndex($option) !== false) {
2271 2
        for ($i = 0; $i < $weight; ++$i) {
2272 1
          $options[] = $option;
2273 1
        }
2274 2
      }
2275 9
    }
2276
2277 9
    return $this->mergeAppendKeepIndex($options)->randomImmutable($number);
2278
  }
2279
2280
  /**
2281
   * Reduce the current array via callable e.g. anonymous-function.
2282
   *
2283
   * @param mixed $callable
2284
   * @param array $init
2285
   *
2286
   * @return static <p>(Immutable)</p>
2287
   */
2288 3
  public function reduce($callable, array $init = array())
2289
  {
2290 3
    $result = \array_reduce($this->array, $callable, $init);
2291
2292 3
    if ($result === null) {
2293
      $this->array = array();
2294
    } else {
2295 3
      $this->array = (array)$result;
2296
    }
2297
2298 3
    return static::create($this->array);
2299
  }
2300
2301
  /**
2302
   * Create a numerically re-indexed Arrayy object.
2303
   *
2304
   * @return static <p>(Mutable) Return this Arrayy object, with re-indexed array-elements.</p>
2305
   */
2306 9
  public function reindex()
2307
  {
2308 9
    $this->array = \array_values($this->array);
2309
2310 9
    return $this;
2311
  }
2312
2313
  /**
2314
   * Return all items that fail the truth test.
2315
   *
2316
   * @param \Closure $closure
2317
   *
2318
   * @return static <p>(Immutable)</p>
2319
   */
2320 1 View Code Duplication
  public function reject(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2321
  {
2322 1
    $filtered = array();
2323
2324 1
    foreach ($this->array as $key => $value) {
2325 1
      if (!$closure($value, $key)) {
2326 1
        $filtered[$key] = $value;
2327 1
      }
2328 1
    }
2329
2330 1
    return static::create($filtered);
2331
  }
2332
2333
  /**
2334
   * Remove a value from the current array (optional using dot-notation).
2335
   *
2336
   * @param mixed $key
2337
   *
2338
   * @return static <p>(Immutable)</p>
2339
   */
2340 18
  public function remove($key)
2341
  {
2342
    // Recursive call
2343 18
    if (is_array($key)) {
2344
      foreach ($key as $k) {
2345
        $this->internalRemove($k);
2346
      }
2347
2348
      return static::create($this->array);
2349
    }
2350
2351 18
    $this->internalRemove($key);
2352
2353 18
    return static::create($this->array);
2354
  }
2355
2356
  /**
2357
   * Remove the first value from the current array.
2358
   *
2359
   * @return static <p>(Immutable)</p>
2360
   */
2361 7
  public function removeFirst()
2362
  {
2363 7
    $tmpArray = $this->array;
2364 7
    \array_shift($tmpArray);
2365
2366 7
    return static::create($tmpArray);
2367
  }
2368
2369
  /**
2370
   * Remove the last value from the current array.
2371
   *
2372
   * @return static <p>(Immutable)</p>
2373
   */
2374 7
  public function removeLast()
2375
  {
2376 7
    $tmpArray = $this->array;
2377 7
    \array_pop($tmpArray);
2378
2379 7
    return static::create($tmpArray);
2380
  }
2381
2382
  /**
2383
   * Removes a particular value from an array (numeric or associative).
2384
   *
2385
   * @param mixed $value
2386
   *
2387
   * @return static <p>(Immutable)</p>
2388
   */
2389 7
  public function removeValue($value)
2390
  {
2391 7
    $isNumericArray = true;
2392 7
    foreach ($this->array as $key => $item) {
2393 6
      if ($item === $value) {
2394 6
        if (!is_int($key)) {
2395
          $isNumericArray = false;
2396
        }
2397 6
        unset($this->array[$key]);
2398 6
      }
2399 7
    }
2400
2401 7
    if ($isNumericArray) {
2402 7
      $this->array = \array_values($this->array);
2403 7
    }
2404
2405 7
    return static::create($this->array);
2406
  }
2407
2408
  /**
2409
   * Generate array of repeated arrays.
2410
   *
2411
   * @param int $times <p>How many times has to be repeated.</p>
2412
   *
2413
   * @return Arrayy
2414
   */
2415 1
  public function repeat($times)
2416
  {
2417 1
    if ($times === 0) {
2418 1
      return new static();
2419
    }
2420
2421 1
    return static::create(\array_fill(0, (int)$times, $this->array));
2422
  }
2423
2424
  /**
2425
   * Replace a key with a new key/value pair.
2426
   *
2427
   * @param $replace
2428
   * @param $key
2429
   * @param $value
2430
   *
2431
   * @return static <p>(Immutable)</p>
2432
   */
2433 2
  public function replace($replace, $key, $value)
2434
  {
2435 2
    $this->remove($replace);
2436
2437 2
    return $this->set($key, $value);
2438
  }
2439
2440
  /**
2441
   * Create an array using the current array as values and the other array as keys.
2442
   *
2443
   * @param array $keys <p>An array of keys.</p>
2444
   *
2445
   * @return static <p>(Immutable) Arrayy object with keys from the other array.</p>
2446
   */
2447 2
  public function replaceAllKeys(array $keys)
2448
  {
2449 2
    $result = \array_combine($keys, $this->array);
2450
2451 2
    return static::create($result);
2452
  }
2453
2454
  /**
2455
   * Create an array using the current array as keys and the other array as values.
2456
   *
2457
   * @param array $array <p>An array o values.</p>
2458
   *
2459
   * @return static <p>(Immutable) Arrayy object with values from the other array.</p>
2460
   */
2461 2
  public function replaceAllValues(array $array)
2462
  {
2463 2
    $result = \array_combine($this->array, $array);
2464
2465 2
    return static::create($result);
2466
  }
2467
2468
  /**
2469
   * Replace the keys in an array with another set.
2470
   *
2471
   * @param array $keys <p>An array of keys matching the array's size</p>
2472
   *
2473
   * @return static <p>(Immutable)</p>
2474
   */
2475 1
  public function replaceKeys(array $keys)
2476
  {
2477 1
    $values = \array_values($this->array);
2478 1
    $result = \array_combine($keys, $values);
2479
2480 1
    return static::create($result);
2481
  }
2482
2483
  /**
2484
   * Replace the first matched value in an array.
2485
   *
2486
   * @param mixed $search
2487
   * @param mixed $replacement
2488
   *
2489
   * @return static <p>(Immutable)</p>
2490
   */
2491 3
  public function replaceOneValue($search, $replacement = '')
2492
  {
2493 3
    $array = $this->array;
2494 3
    $key = \array_search($search, $array, true);
2495
2496 3
    if ($key !== false) {
2497 3
      $array[$key] = $replacement;
2498 3
    }
2499
2500 3
    return static::create($array);
2501
  }
2502
2503
  /**
2504
   * Replace values in the current array.
2505
   *
2506
   * @param string $search      <p>The string to replace.</p>
2507
   * @param string $replacement <p>What to replace it with.</p>
2508
   *
2509
   * @return static <p>(Immutable)</p>
2510
   */
2511 1
  public function replaceValues($search, $replacement = '')
2512
  {
2513 1
    $array = $this->each(
2514
        function ($value) use ($search, $replacement) {
2515 1
          return UTF8::str_replace($search, $replacement, $value);
2516
        }
2517 1
    );
2518
2519 1
    return $array;
2520
  }
2521
2522
  /**
2523
   * Get the last elements from index $from until the end of this array.
2524
   *
2525
   * @param int $from
2526
   *
2527
   * @return static <p>(Immutable)</p>
2528
   */
2529 15
  public function rest($from = 1)
2530
  {
2531 15
    $tmpArray = $this->array;
2532
2533 15
    return static::create(\array_splice($tmpArray, $from));
2534
  }
2535
2536
  /**
2537
   * Return the array in the reverse order.
2538
   *
2539
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2540
   */
2541 7
  public function reverse()
2542
  {
2543 7
    $this->array = \array_reverse($this->array);
2544
2545 7
    return $this;
2546
  }
2547
2548
  /**
2549
   * Search for the first index of the current array via $value.
2550
   *
2551
   * @param mixed $value
2552
   *
2553
   * @return int|float|string
2554
   */
2555 20
  public function searchIndex($value)
2556
  {
2557 20
    return \array_search($value, $this->array, true);
2558
  }
2559
2560
  /**
2561
   * Search for the value of the current array via $index.
2562
   *
2563
   * @param mixed $index
2564
   *
2565
   * @return static <p>(Immutable) Will return a empty Arrayy if the value wasn't found.</p>
2566
   */
2567 9
  public function searchValue($index)
2568
  {
2569
    // init
2570 9
    $return = array();
2571
2572 9
    if ($this->isEmpty()) {
2573
      return static::create();
2574
    }
2575
2576
    // php cast "bool"-index into "int"-index
2577 9
    if ((bool)$index === $index) {
2578 1
      $index = (int)$index;
2579 1
    }
2580
2581 9
    if (\array_key_exists($index, $this->array) === true) {
2582 7
      $return = array($this->array[$index]);
2583 7
    }
2584
2585
2586 9
    return static::create($return);
2587
  }
2588
2589
  /**
2590
   * Set a value for the current array (optional using dot-notation).
2591
   *
2592
   * @param string $key   <p>The key to set.</p>
2593
   * @param mixed  $value <p>Its value.</p>
2594
   *
2595
   * @return static <p>(Immutable)</p>
2596
   */
2597 17
  public function set($key, $value)
2598
  {
2599 17
    $this->internalSet($key, $value);
2600
2601 17
    return static::create($this->array);
2602
  }
2603
2604
  /**
2605
   * Get a value from a array and set it if it was not.
2606
   *
2607
   * WARNING: this method only set the value, if the $key is not already set
2608
   *
2609
   * @param string $key      <p>The key</p>
2610
   * @param mixed  $fallback <p>The default value to set if it isn't.</p>
2611
   *
2612
   * @return mixed <p>(Mutable)</p>
2613
   */
2614 11
  public function setAndGet($key, $fallback = null)
2615
  {
2616
    // If the key doesn't exist, set it.
2617 11
    if (!$this->has($key)) {
2618 4
      $this->array = $this->set($key, $fallback)->getArray();
2619 4
    }
2620
2621 11
    return $this->get($key);
2622
  }
2623
2624
  /**
2625
   * Shifts a specified value off the beginning of array.
2626
   *
2627
   * @return mixed <p>(Mutable) A shifted element from the current array.</p>
2628
   */
2629 4
  public function shift()
2630
  {
2631 4
    return \array_shift($this->array);
2632
  }
2633
2634
  /**
2635
   * Shuffle the current array.
2636
   *
2637
   * @return static <p>(Immutable)</p>
2638
   */
2639 1
  public function shuffle()
2640
  {
2641 1
    $array = $this->array;
2642
2643 1
    shuffle($array);
2644
2645 1
    return static::create($array);
2646
  }
2647
2648
  /**
2649
   * Get the size of an array.
2650
   *
2651
   * @return int
2652
   */
2653 93
  public function size()
2654
  {
2655 93
    return count($this->array);
2656
  }
2657
2658
  /**
2659
   * Extract a slice of the array.
2660
   *
2661
   * @param int      $offset       <p>Slice begin index.</p>
2662
   * @param int|null $length       <p>Length of the slice.</p>
2663
   * @param bool     $preserveKeys <p>Whether array keys are preserved or no.</p>
2664
   *
2665
   * @return static <p>A slice of the original array with length $length.</p>
2666
   */
2667 4
  public function slice($offset, $length = null, $preserveKeys = false)
2668
  {
2669 4
    $result = \array_slice($this->array, $offset, $length, $preserveKeys);
2670
2671 4
    return static::create($result);
2672
  }
2673
2674
  /**
2675
   * Sort the current array and optional you can keep the keys.
2676
   *
2677
   * @param integer $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2678
   * @param integer $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2679
   * @param bool    $keepKeys
2680
   *
2681
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2682
   */
2683 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2684
  {
2685 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2686
2687 19
    return $this;
2688
  }
2689
2690
  /**
2691
   * Sort the current array by key.
2692
   *
2693
   * @link http://php.net/manual/en/function.ksort.php
2694
   * @link http://php.net/manual/en/function.krsort.php
2695
   *
2696
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2697
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2698
   *                              <strong>SORT_NATURAL</strong></p>
2699
   *
2700
   * @return static <p>(Mutable) Return this Arrayy object.</p>
2701
   */
2702 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
2703
  {
2704 18
    $this->sorterKeys($this->array, $direction, $strategy);
2705
2706 18
    return $this;
2707
  }
2708
2709
  /**
2710
   * Sort the current array by value.
2711
   *
2712
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2713
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2714
   *
2715
   * @return static <p>(Immutable)</p>
2716
   */
2717 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2718
  {
2719 1
    return $this->sort($direction, $strategy, true);
2720
  }
2721
2722
  /**
2723
   * Sort the current array by value.
2724
   *
2725
   * @param int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2726
   * @param int $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2727
   *
2728
   * @return static <p>(Immutable)</p>
2729
   */
2730 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2731
  {
2732 1
    return $this->sort($direction, $strategy, false);
2733
  }
2734
2735
  /**
2736
   * Sort a array by value, by a closure or by a property.
2737
   *
2738
   * - If the sorter is null, the array is sorted naturally.
2739
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2740
   *
2741
   * @param null       $sorter
2742
   * @param string|int $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2743
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2744
   *                              <strong>SORT_NATURAL</strong></p>
2745
   *
2746
   * @return static <p>(Immutable)</p>
2747
   */
2748 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2749
  {
2750 1
    $array = (array)$this->array;
2751 1
    $direction = $this->getDirection($direction);
2752
2753
    // Transform all values into their results.
2754 1
    if ($sorter) {
2755 1
      $arrayy = static::create($array);
2756
2757 1
      $that = $this;
2758 1
      $results = $arrayy->each(
2759
          function ($value) use ($sorter, $that) {
2760 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2761
          }
2762 1
      );
2763
2764 1
      $results = $results->getArray();
2765 1
    } else {
2766 1
      $results = $array;
2767
    }
2768
2769
    // Sort by the results and replace by original values
2770 1
    \array_multisort($results, $direction, $strategy, $array);
2771
2772 1
    return static::create($array);
2773
  }
2774
2775
  /**
2776
   * sorting keys
2777
   *
2778
   * @param array $elements
2779
   * @param int   $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2780
   * @param int   $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or <strong>SORT_NATURAL</strong></p>
2781
   *
2782
   * @return void <p>Mutable</p>
2783
   */
2784 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2785
  {
2786 18
    $direction = $this->getDirection($direction);
2787
2788
    switch ($direction) {
2789 18
      case 'desc':
2790 18
      case SORT_DESC:
2791 6
        krsort($elements, $strategy);
2792 6
        break;
2793 13
      case 'asc':
2794 13
      case SORT_ASC:
2795 13
      default:
2796 13
        ksort($elements, $strategy);
2797 13
    }
2798 18
  }
2799
2800
  /**
2801
   * @param array      &$elements
2802
   * @param int|string $direction <p>use <strong>SORT_ASC</strong> (default) or <strong>SORT_DESC</strong></p>
2803
   * @param int        $strategy  <p>use e.g.: <strong>SORT_REGULAR</strong> (default) or
2804
   *                              <strong>SORT_NATURAL</strong></p>
2805
   * @param bool       $keepKeys
2806
   *
2807
   * @return void <p>Mutable</p>
2808
   */
2809 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2810
  {
2811 19
    $direction = $this->getDirection($direction);
2812
2813 19
    if (!$strategy) {
2814 19
      $strategy = SORT_REGULAR;
2815 19
    }
2816
2817
    switch ($direction) {
2818 19
      case 'desc':
2819 19
      case SORT_DESC:
2820 9
        if ($keepKeys) {
2821 5
          arsort($elements, $strategy);
2822 5
        } else {
2823 4
          rsort($elements, $strategy);
2824
        }
2825 9
        break;
2826 10
      case 'asc':
2827 10
      case SORT_ASC:
2828 10
      default:
2829 10
        if ($keepKeys) {
2830 4
          asort($elements, $strategy);
2831 4
        } else {
2832 6
          sort($elements, $strategy);
2833
        }
2834 10
    }
2835 19
  }
2836
2837
  /**
2838
   * Split an array in the given amount of pieces.
2839
   *
2840
   * @param int  $numberOfPieces
2841
   * @param bool $keepKeys
2842
   *
2843
   * @return static <p>(Immutable)</p>
2844
   */
2845 1
  public function split($numberOfPieces = 2, $keepKeys = false)
2846
  {
2847 1
    $arrayCount = $this->count();
2848
2849 1
    if ($arrayCount === 0) {
2850 1
      $result = array();
2851 1
    } else {
2852 1
      $numberOfPieces = (int)$numberOfPieces;
2853 1
      $splitSize = (int)ceil($arrayCount / $numberOfPieces);
2854 1
      $result = \array_chunk($this->array, $splitSize, $keepKeys);
2855
    }
2856
2857 1
    return static::create($result);
2858
  }
2859
2860
  /**
2861
   * Stripe all empty items.
2862
   *
2863
   * @return static <p>(Immutable)</p>
2864
   */
2865 1
  public function stripEmpty()
2866
  {
2867 1
    return $this->filter(
2868
        function ($item) {
2869 1
          if ($item === null) {
2870 1
            return false;
2871
          }
2872
2873 1
          return (bool)trim((string)$item);
2874
        }
2875 1
    );
2876
  }
2877
2878
  /**
2879
   * Swap two values between positions by key.
2880
   *
2881
   * @param string|int $swapA <p>a key in the array</p>
2882
   * @param string|int $swapB <p>a key in the array</p>
2883
   *
2884
   * @return static <p>(Immutable)</p>
2885
   */
2886 1
  public function swap($swapA, $swapB)
2887
  {
2888 1
    $array = $this->array;
2889
2890 1
    list($array[$swapA], $array[$swapB]) = array($array[$swapB], $array[$swapA]);
2891
2892 1
    return static::create($array);
2893
  }
2894
2895
  /**
2896
   * alias: for "Arrayy->getArray()"
2897
   *
2898
   * @see Arrayy::getArray()
2899
   */
2900 142
  public function toArray()
2901
  {
2902 142
    return $this->getArray();
2903
  }
2904
2905
  /**
2906
   * Convert the current array to JSON.
2907
   *
2908
   * @param null|int $options [optional] <p>e.g. JSON_PRETTY_PRINT</p>
2909
   * @param int      $depth   [optional] <p>Set the maximum depth. Must be greater than zero.</p>
2910
   *
2911
   * @return string
2912
   */
2913 6
  public function toJson($options = null, $depth = 512)
2914
  {
2915 6
    return UTF8::json_encode($this->array, $options, $depth);
2916
  }
2917
2918
  /**
2919
   * Implodes array to a string with specified separator.
2920
   *
2921
   * @param string $separator [optional] <p>The element's separator.</p>
2922
   *
2923
   * @return string <p>The string representation of array, separated by ",".</p>
2924
   */
2925 19
  public function toString($separator = ',')
2926
  {
2927 19
    return $this->implode($separator);
2928
  }
2929
2930
  /**
2931
   * Return a duplicate free copy of the current array.
2932
   *
2933
   * @return static <p>(Mutable)</p>
2934
   */
2935 9
  public function unique()
2936
  {
2937 9
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce($this->arr...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

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

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

Loading history...
2938 9
        $this->array,
2939
        function ($resultArray, $value) {
2940 8
          if (!in_array($value, $resultArray, true)) {
2941 8
            $resultArray[] = $value;
2942 8
          }
2943
2944 8
          return $resultArray;
2945 9
        },
2946 9
        array()
2947 9
    );
2948
2949 9 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2950
      $this->array = array();
2951
    } else {
2952 9
      $this->array = (array)$this->array;
2953
    }
2954
2955 9
    return $this;
2956
  }
2957
2958
  /**
2959
   * Return a duplicate free copy of the current array. (with the old keys)
2960
   *
2961
   * @return static <p>(Mutable)</p>
2962
   */
2963 9
  public function uniqueKeepIndex()
2964
  {
2965
    // init
2966 9
    $array = $this->array;
2967
2968 9
    $this->array = \array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like \array_reduce(\array_key...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

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

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

Loading history...
2969 9
        \array_keys($array),
2970 9
        function ($resultArray, $key) use ($array) {
2971 8
          if (!in_array($array[$key], $resultArray, true)) {
2972 8
            $resultArray[$key] = $array[$key];
2973 8
          }
2974
2975 8
          return $resultArray;
2976 9
        },
2977 9
        array()
2978 9
    );
2979
2980 9 View Code Duplication
    if ($this->array === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2981
      $this->array = array();
2982
    } else {
2983 9
      $this->array = (array)$this->array;
2984
    }
2985
2986 9
    return $this;
2987
  }
2988
2989
  /**
2990
   * alias: for "Arrayy->unique()"
2991
   *
2992
   * @see Arrayy::unique()
2993
   *
2994
   * @return static <p>(Mutable) Return this Arrayy object, with the appended values.</p>
2995
   */
2996 9
  public function uniqueNewIndex()
2997
  {
2998 9
    return $this->unique();
2999
  }
3000
3001
  /**
3002
   * Prepends one or more values to the beginning of array at once.
3003
   *
3004
   * @return static <p>(Mutable) Return this Arrayy object, with prepended elements to the beginning of array.</p>
3005
   */
3006 4 View Code Duplication
  public function unshift(/* variadic arguments allowed */)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3007
  {
3008 4
    if (func_num_args()) {
3009 4
      $args = \array_merge(array(&$this->array), func_get_args());
3010 4
      call_user_func_array('array_unshift', $args);
3011 4
    }
3012
3013 4
    return $this;
3014
  }
3015
3016
  /**
3017
   * Get all values from a array.
3018
   *
3019
   * @return static <p>(Immutable)</p>
3020
   */
3021 2
  public function values()
3022
  {
3023 2
    return static::create(\array_values((array)$this->array));
3024
  }
3025
3026
  /**
3027
   * Apply the given function to every element in the array, discarding the results.
3028
   *
3029
   * @param callable $callable
3030
   * @param bool     $recursive <p>Whether array will be walked recursively or no</p>
3031
   *
3032
   * @return static <p>(Mutable) Return this Arrayy object, with modified elements.</p>
3033
   */
3034 9
  public function walk($callable, $recursive = false)
3035
  {
3036 9
    if (true === $recursive) {
3037 4
      \array_walk_recursive($this->array, $callable);
3038 4
    } else {
3039 5
      \array_walk($this->array, $callable);
3040
    }
3041
3042 9
    return $this;
3043
  }
3044
}
3045