Completed
Push — master ( 0b96f0...3fc4b9 )
by Lars
02:12
created

Arrayy::offsetGet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 2
eloc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Arrayy;
4
5
use ArrayAccess;
6
use Closure;
7
use voku\helper\UTF8;
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 \Countable, \IteratorAggregate, \ArrayAccess, \Serializable
16
{
17
  /**
18
   * @var array
19
   */
20
  protected $array = array();
21
22
  /**
23
   * Initializes
24
   *
25
   * @param array $array
26
   */
27 667
  public function __construct($array = array())
28
  {
29 667
    $array = $this->fallbackForArray($array);
30
31 665
    $this->array = $array;
32 665
  }
33
34
  /**
35
   * create a fallback for array
36
   *
37
   * 1. fallback to empty array, if there is nothing
38
   * 2. cast a String or Object with "__toString" into an array
39
   * 3. call "__toArray" on Object, if the method exists
40
   * 4. throw a "InvalidArgumentException"-Exception
41
   *
42
   * @param $array
43
   *
44
   * @return array
45
   */
46 667
  protected function fallbackForArray(&$array)
47
  {
48 667
    if (is_array($array)) {
49 665
      return $array;
50
    }
51
52 5
    if ($array instanceof self) {
53 1
      return $array->getArray();
54
    }
55
56 4
    if (!$array) {
57 1
      return array();
58
    }
59
60
    if (
61 3
        is_string($array)
62
        ||
63 3
        (is_object($array) && method_exists($array, '__toString'))
64
    ) {
65 1
      return (array)$array;
66
    }
67
68 2
    if (is_object($array) && method_exists($array, '__toArray')) {
69
      return (array)$array->__toArray();
70
    }
71
72 2
    throw new \InvalidArgumentException(
73 2
        'Passed value must be a array'
74
    );
75
  }
76
77
  /**
78
   * Get the current array from the "Arrayy"-object
79
   *
80
   * @return array
81
   */
82 470
  public function getArray()
83
  {
84 470
    return $this->array;
85
  }
86
87
  /**
88
   * Create a new Arrayy object via string.
89
   *
90
   * @param string      $str       The input string.
91
   * @param string|null $delimiter The boundary string.
92
   * @param string|null $regEx     Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be used.
93
   *
94
   * @return Arrayy Returns created instance
95
   */
96 8
  public static function createFromString($str, $delimiter, $regEx = null)
97
  {
98 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...
99 1
      preg_match_all($regEx, $str, $array);
100
101 1
      if (count($array) > 0) {
102 1
        $array = $array[0];
103
      }
104
105
    } else {
106 7
      $array = explode($delimiter, $str);
107
    }
108
109
    // trim all string in the array
110 8
    array_walk(
111
        $array,
112
        function (&$val) {
113 8
          if (is_string($val)) {
114 8
            $val = trim($val);
115
          }
116 8
        }
117
    );
118
119 8
    return static::create($array);
120
  }
121
122
  /**
123
   * Creates a Arrayy object.
124
   *
125
   * @param array $array
126
   *
127
   * @return Arrayy Returns created instance
128
   */
129 433
  public static function create($array = array())
130
  {
131 433
    return new static($array);
132
  }
133
134
  /**
135
   * create a new Arrayy object via JSON,
136
   *
137
   * @param string $json
138
   *
139
   * @return Arrayy Returns created instance
140
   */
141 5
  public static function createFromJson($json)
142
  {
143 5
    $array = UTF8::json_decode($json, true);
144
145 5
    return static::create($array);
146
  }
147
148
  /**
149
   * Create a new instance filled with values from an object implementing ArrayAccess.
150
   *
151
   * @param ArrayAccess $elements Object that implements ArrayAccess
152
   *
153
   * @return Arrayy Returns created instance
154
   */
155 4
  public static function createFromObject(ArrayAccess $elements)
156
  {
157 4
    $array = new static();
158 4
    foreach ($elements as $key => $value) {
159
      /** @noinspection OffsetOperationsInspection */
160 3
      $array[$key] = $value;
161
    }
162
163 4
    return $array;
164
  }
165
166
  /**
167
   * Create a new instance containing a range of elements.
168
   *
169
   * @param mixed $low  First value of the sequence
170
   * @param mixed $high The sequence is ended upon reaching the end value
171
   * @param int   $step Used as the increment between elements in the sequence
172
   *
173
   * @return Arrayy The created array
174
   */
175 1
  public static function createWithRange($low, $high, $step = 1)
176
  {
177 1
    return static::create(range($low, $high, $step));
178
  }
179
180
  /**
181
   * alias: for "Arrayy->random()"
182
   *
183
   * @return Arrayy
184
   */
185 3
  public function getRandom()
186
  {
187 3
    return $this->random();
188
  }
189
190
  /**
191
   * Get a random value from the current array.
192
   *
193
   * @param null|int $number how many values you will take?
194
   *
195
   * @return Arrayy
196
   */
197 27
  public function random($number = null)
198
  {
199 27
    if ($this->count() === 0) {
200
      return static::create();
201
    }
202
203 27
    if ($number === null) {
204 15
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
205
206 15
      return static::create($arrayRandValue);
207
    }
208
209 14
    shuffle($this->array);
210
211 14
    return $this->first($number);
212
  }
213
214
  /**
215
   * Count the values from the current array.
216
   *
217
   * INFO: only a alias for "$arrayy->size()"
218
   *
219
   * @return int
220
   */
221 102
  public function count()
222
  {
223 102
    return $this->size();
224
  }
225
226
  /**
227
   * Get the size of an array.
228
   *
229
   * @return int
230
   */
231 102
  public function size()
232
  {
233 102
    return count($this->array);
234
  }
235
236
  /**
237
   * Get the first value(s) from the current array.
238
   *
239
   * @param int|null $number how many values you will take?
240
   *
241
   * @return Arrayy
242
   */
243 43
  public function first($number = null)
244
  {
245 43
    if ($number === null) {
246 12
      $array = (array)array_shift($this->array);
247
    } else {
248 31
      $number = (int)$number;
249 31
      $array = array_splice($this->array, 0, $number, true);
250
    }
251
252 43
    return static::create($array);
253
  }
254
255
  /**
256
   * Append a value to an array.
257
   *
258
   * @param mixed $value
259
   *
260
   * @return Arrayy
261
   */
262 8
  public function append($value)
263
  {
264 8
    $this->array[] = $value;
265
266 8
    return static::create($this->array);
267
  }
268
269
  /**
270
   * @return mixed
271
   */
272
  public function serialize()
273
  {
274
    return serialize($this->array);
275
  }
276
277
  /**
278
   * @param string $array
279
   */
280
  public function unserialize($array)
281
  {
282
    $this->array = unserialize($array);
283
  }
284
285
  /**
286
   * Assigns a value to the specified offset.
287
   *
288
   * @param mixed $offset
289
   * @param mixed $value
290
   */
291 13
  public function offsetSet($offset, $value)
292
  {
293 13
    if (null === $offset) {
294 4
      $this->array[] = $value;
295
    } else {
296 9
      $this->array[$offset] = $value;
297
    }
298 13
  }
299
300
  /**
301
   * alias: for "Arrayy->randomValue()"
302
   *
303
   * @return mixed get a random value or null if there wasn't a value
304
   */
305
  public function getRandomValue()
306
  {
307
    return $this->randomValue();
308
  }
309
310
  /**
311
   * Pick a random value from the values of this array.
312
   *
313
   * @return mixed get a random value or null if there wasn't a value
314
   */
315 View Code Duplication
  public function randomValue()
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...
316
  {
317
    $result = $this->random(1);
318
319
    if (!isset($result[0])) {
320
      $result[0] = null;
321
    }
322
323
    return $result[0];
324
  }
325
326
  /**
327
   * alias: for "Arrayy->randomValues()"
328
   *
329
   * @param int $number
330
   *
331
   * @return Arrayy
332
   */
333 6
  public function getRandomValues($number)
334
  {
335 6
    return $this->randomValues($number);
336
  }
337
338
  /**
339
   * Pick a given number of random values out of this array.
340
   *
341
   * @param int $number
342
   *
343
   * @return Arrayy
344
   */
345 6
  public function randomValues($number)
346
  {
347 6
    $number = (int)$number;
348
349 6
    return $this->random($number);
350
  }
351
352
  /**
353
   * alias: for "Arrayy->randomKey()"
354
   *
355
   * @return mixed get a key/index or null if there wasn't a key/index
356
   */
357 3
  public function getRandomKey()
358
  {
359 3
    return $this->randomKey();
360
  }
361
362
  /**
363
   * Pick a random key/index from the keys of this array.
364
   *
365
   *
366
   * @return mixed get a key/index or null if there wasn't a key/index
367
   *
368
   * @throws \RangeException If array is empty
369
   */
370 3 View Code Duplication
  public function randomKey()
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...
371
  {
372 3
    $result = $this->randomKeys(1);
373
374 3
    if (!isset($result[0])) {
375
      $result[0] = null;
376
    }
377
378 3
    return $result[0];
379
  }
380
381
  /**
382
   * Pick a given number of random keys/indexes out of this array.
383
   *
384
   * @param int $number The number of keys/indexes (should be <= $this->count())
385
   *
386
   * @return Arrayy
387
   *
388
   * @throws \RangeException If array is empty
389
   */
390 12
  public function randomKeys($number)
391
  {
392 12
    $number = (int)$number;
393 12
    $count = $this->count();
394
395 12
    if ($number === 0 || $number > $count) {
396 3
      throw new \RangeException(
397
          sprintf(
398 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
399
              $number,
400
              $count
401
          )
402
      );
403
    }
404
405 9
    $result = (array)array_rand($this->array, $number);
406
407 9
    return static::create($result);
408
  }
409
410
  /**
411
   * alias: for "Arrayy->randomKeys()"
412
   *
413
   * @param int $number
414
   *
415
   * @return Arrayy
416
   */
417 9
  public function getRandomKeys($number)
418
  {
419 9
    return $this->randomKeys($number);
420
  }
421
422
  /**
423
   * find by ...
424
   *
425
   * @param        $property
426
   * @param        $value
427
   * @param string $comparisonOp
428
   *
429
   * @return Arrayy
430
   */
431
  public function findBy($property, $value, $comparisonOp = 'eq')
432
  {
433
    $array = $this->filterBy($property, $value, $comparisonOp);
434
435
    return static::create($array);
0 ignored issues
show
Documentation introduced by
$array is of type object<Arrayy\Arrayy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
436
  }
437
438
  /**
439
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
440
   * within that.
441
   *
442
   * @param        $property
443
   * @param        $value
444
   * @param string $comparisonOp
445
   *
446
   * @return Arrayy
447
   */
448 1
  public function filterBy($property, $value, $comparisonOp = null)
449
  {
450 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...
451 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
452
    }
453
454
    $ops = array(
455
        'eq'          => function ($item, $prop, $value) {
456 1
          return $item[$prop] === $value;
457 1
        },
458
        'gt'          => function ($item, $prop, $value) {
459
          return $item[$prop] > $value;
460 1
        },
461
        'gte'         => function ($item, $prop, $value) {
462
          return $item[$prop] >= $value;
463 1
        },
464
        'lt'          => function ($item, $prop, $value) {
465 1
          return $item[$prop] < $value;
466 1
        },
467
        'lte'         => function ($item, $prop, $value) {
468
          return $item[$prop] <= $value;
469 1
        },
470
        'ne'          => function ($item, $prop, $value) {
471
          return $item[$prop] !== $value;
472 1
        },
473
        'contains'    => function ($item, $prop, $value) {
474 1
          return in_array($item[$prop], (array)$value, true);
475 1
        },
476
        'notContains' => function ($item, $prop, $value) {
477
          return !in_array($item[$prop], (array)$value, true);
478 1
        },
479
        'newer'       => function ($item, $prop, $value) {
480
          return strtotime($item[$prop]) > strtotime($value);
481 1
        },
482
        'older'       => function ($item, $prop, $value) {
483
          return strtotime($item[$prop]) < strtotime($value);
484 1
        },
485
    );
486
487 1
    $result = array_values(
488
        array_filter(
489 1
            (array)$this->array,
490
            function ($item) use (
491 1
                $property,
492 1
                $value,
493 1
                $ops,
494 1
                $comparisonOp
495
            ) {
496 1
              $item = (array)$item;
497 1
              $itemArrayy = new Arrayy($item);
498 1
              $item[$property] = $itemArrayy->get($property, array());
499
500 1
              return $ops[$comparisonOp]($item, $property, $value);
501 1
            }
502
        )
503
    );
504
505 1
    return static::create($result);
506
  }
507
508
  /**
509
   * Get a value from an array (optional using dot-notation).
510
   *
511
   * @param string $key     The key to look for
512
   * @param mixed  $default Default value to fallback to
513
   * @param array  $array   The array to get from,
514
   *                        if it's set to "null" we use the current array from the class
515
   *
516
   * @return mixed
517
   */
518 31
  public function get($key, $default = null, $array = null)
519
  {
520 31
    if (is_array($array) === true) {
521 3
      $usedArray = $array;
522
    } else {
523 29
      $usedArray = $this->array;
524
    }
525
526 31
    if (null === $key) {
527 1
      return $usedArray;
528
    }
529
530 31
    if (isset($usedArray[$key])) {
531 22
      return $usedArray[$key];
532
    }
533
534
    // Crawl through array, get key according to object or not
535 16
    foreach (explode('.', $key) as $segment) {
536 16
      if (!isset($usedArray[$segment])) {
537 16
        return $default instanceof Closure ? $default() : $default;
538
      }
539
540
      $usedArray = $usedArray[$segment];
541
    }
542
543
    return $usedArray;
544
  }
545
546
  /**
547
   * WARNING: Creates a Arrayy object by reference.
548
   *
549
   * @param array $array
550
   *
551
   * @return $this
552
   */
553
  public function createByReference(&$array = array())
554
  {
555
    $array = $this->fallbackForArray($array);
556
557
    $this->array = &$array;
558
559
    return $this;
560
  }
561
562
  /**
563
   * Get all values from a array.
564
   *
565
   * @return Arrayy
566
   */
567 1
  public function values()
568
  {
569 1
    $array = array_values((array)$this->array);
570
571 1
    return static::create($array);
572
  }
573
574
  /**
575
   * Group values from a array according to the results of a closure.
576
   *
577
   * @param string $grouper a callable function name
578
   * @param bool   $saveKeys
579
   *
580
   * @return Arrayy
581
   */
582 3
  public function group($grouper, $saveKeys = false)
583
  {
584 3
    $array = (array)$this->array;
585 3
    $result = array();
586
587
    // Iterate over values, group by property/results from closure
588 3
    foreach ($array as $key => $value) {
589 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
590 3
      $newValue = $this->get($groupKey, null, $result);
591
592
      // Add to results
593 3
      if ($groupKey !== null) {
594 2
        if ($saveKeys) {
595 1
          $result[$groupKey] = $newValue;
596 1
          $result[$groupKey][$key] = $value;
597
        } else {
598 1
          $result[$groupKey] = $newValue;
599 3
          $result[$groupKey][] = $value;
600
        }
601
      }
602
603
    }
604
605 3
    return static::create($result);
606
  }
607
608
  /**
609
   * Given a list and an iterate-function that returns
610
   * a key for each element in the list (or a property name),
611
   * returns an object with an index of each item.
612
   *
613
   * Just like groupBy, but for when you know your keys are unique.
614
   *
615
   * @param mixed $key
616
   *
617
   * @return Arrayy
618
   */
619 3
  public function indexBy($key)
620
  {
621 3
    $results = array();
622
623 3
    foreach ($this->array as $a) {
624 3
      if (isset($a[$key])) {
625 3
        $results[$a[$key]] = $a;
626
      }
627
    }
628
629 3
    return static::create($results);
630
  }
631
632
  /**
633
   * magic to string
634
   *
635
   * @return string
636
   */
637 17
  public function __toString()
638
  {
639 17
    return $this->toString();
640
  }
641
642
  /**
643
   * Implodes array to a string with specified separator.
644
   *
645
   * @param string $separator The element's separator
646
   *
647
   * @return string The string representation of array, separated by ","
648
   */
649 17
  public function toString($separator = ',')
650
  {
651 17
    return $this->implode($separator);
652
  }
653
654
  /**
655
   * Implodes an array.
656
   *
657
   * @param string $with What to implode it with
658
   *
659
   * @return string
660
   */
661 25
  public function implode($with = '')
662
  {
663 25
    return implode($with, $this->array);
664
  }
665
666
  /**
667
   * Push one or more values onto the end of array at once.
668
   *
669
   * @return $this An Arrayy object with pushed elements to the end of array
670
   */
671 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...
672
  {
673 4
    if (func_num_args()) {
674 4
      $args = array_merge(array(&$this->array), func_get_args());
675 4
      call_user_func_array('array_push', $args);
676
    }
677
678 4
    return $this;
679
  }
680
681
  /**
682
   * Shifts a specified value off the beginning of array.
683
   *
684
   * @return mixed A shifted element from the current array.
685
   */
686 4
  public function shift()
687
  {
688 4
    return array_shift($this->array);
689
  }
690
691
  /**
692
   * Prepends one or more values to the beginning of array at once.
693
   *
694
   * @return Arrayy Array object with prepended elements to the beginning of array
695
   */
696 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...
697
  {
698 4
    if (func_num_args()) {
699 4
      $args = array_merge(array(&$this->array), func_get_args());
700 4
      call_user_func_array('array_unshift', $args);
701
    }
702
703 4
    return $this;
704
  }
705
706
  /**
707
   * Get a value by key.
708
   *
709
   * @param $key
710
   *
711
   * @return mixed
712
   */
713
  public function &__get($key)
714
  {
715
    return $this->array[$key];
716
  }
717
718
  /**
719
   * Assigns a value to the specified element.
720
   *
721
   * @param $key
722
   * @param $value
723
   */
724
  public function __set($key, $value)
725
  {
726
    $this->array[$key] = $value;
727
  }
728
729
  /**
730
   * Whether or not an element exists by key.
731
   *
732
   * @param $key
733
   *
734
   * @return bool
735
   */
736
  public function __isset($key)
737
  {
738
    return isset($this->array[$key]);
739
  }  /**
740
   * Whether or not an offset exists.
741
   *
742
   * @param mixed $offset
743
   *
744
   * @return bool
745
   */
746 24
  public function offsetExists($offset)
747
  {
748 24
    return isset($this->array[$offset]);
749
  }
750
751
  /**
752
   * Unset element by key
753
   *
754
   * @param mixed $key
755
   */
756
  public function __unset($key)
757
  {
758
    unset($this->array[$key]);
759
  }
760
761
  /**
762
   * Call object as function.
763
   *
764
   * @param mixed $key
765
   *
766
   * @return mixed
767
   */
768
  public function __invoke($key = null)
769
  {
770
    if ($key !== null) {
771
      if (isset($this->array[$key])) {
772
        return $this->array[$key];
773
      } else {
774
        return false;
775
      }
776
    }
777
778
    return (array)$this->array;
779
  }
780
781
  /**
782
   * Search for the value of the current array via $index.
783
   *
784
   * @param mixed $index
785
   *
786
   * @return Arrayy will return a empty Arrayy if the value wasn't found
787
   */
788 7
  public function searchValue($index)
789
  {
790
    // init
791 7
    $return = array();
792
793 7
    if (null !== $index) {
794 7
      $keyExists = isset($this->array[$index]);
795
796 7
      if ($keyExists !== false) {
797 5
        $return = array($this->array[$index]);
798
      }
799
    }
800
801 7
    return static::create($return);
802
  }
803
804
  /**
805
   * Check if all items in current array match a truth test.
806
   *
807
   * @param \Closure $closure
808
   *
809
   * @return bool
810
   */
811 9 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...
812
  {
813
    // Reduce the array to only booleans
814 9
    $array = $this->each($closure);
815
816
    // Check the results
817 9
    if (count($array) === 0) {
818 2
      return true;
819
    }
820
821 7
    $array = array_search(false, $array->toArray(), false);
822
823 7
    return is_bool($array);
824
  }
825
826
  /**
827
   * Iterate over the current array and modify the array's value.
828
   *
829
   * @param \Closure $closure
830
   *
831
   * @return Arrayy
832
   */
833 22 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...
834
  {
835 22
    $array = $this->array;
836
837 22
    foreach ($array as $key => &$value) {
838 18
      $value = $closure($value, $key);
839
    }
840
841 22
    return static::create($array);
842
  }
843
844
  /**
845
   * alias: for "Arrayy->getArray()"
846
   */
847 153
  public function toArray()
848
  {
849 153
    return $this->getArray();
850
  }
851
852
  /**
853
   * Check if any item in the current array matches a truth test.
854
   *
855
   * @param \Closure $closure
856
   *
857
   * @return bool
858
   */
859 9 View Code Duplication
  public function matchesAny(\Closure $closure)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
860
  {
861
    // Reduce the array to only booleans
862 9
    $array = $this->each($closure);
863
864
    // Check the results
865 9
    if (count($array) === 0) {
866 2
      return true;
867
    }
868
869 7
    $array = array_search(true, $array->toArray(), false);
870
871 7
    return is_int($array);
872
  }
873
874
  /**
875
   * Check whether array is associative or not.
876
   *
877
   * @return bool Returns true if associative, false otherwise
878
   */
879 14
  public function isAssoc()
880
  {
881 14
    if ($this->isEmpty()) {
882 2
      return false;
883
    }
884
885 12
    foreach ($this->getKeys()->getArray() as $key) {
886 12
      if (!is_string($key)) {
887 12
        return false;
888
      }
889
    }
890
891 2
    return true;
892
  }
893
894
  /**
895
   * Unset an offset.
896
   *
897
   * @param mixed $offset
898
   */
899 5
  public function offsetUnset($offset)
900
  {
901 5
    if ($this->offsetExists($offset)) {
902 3
      unset($this->array[$offset]);
903
    }
904 5
  }
905
906
  /**
907
   * Check whether the array is empty or not.
908
   *
909
   * @return bool Returns true if empty, false otherwise
910
   */
911 22
  public function isEmpty()
912
  {
913 22
    return !$this->array;
914
  }
915
916
  /**
917
   * alias: for "Arrayy->keys()"
918
   *
919
   * @return Arrayy
920
   */
921 15
  public function getKeys()
922
  {
923 15
    return $this->keys();
924
  }
925
926
  /**
927
   * Get all keys from the current array.
928
   *
929
   * @return Arrayy
930
   */
931 20
  public function keys()
932
  {
933 20
    $array = array_keys((array)$this->array);
934
935 20
    return static::create($array);
936
  }
937
938
  /**
939
   * Check whether array is numeric or not.
940
   *
941
   * @return bool Returns true if numeric, false otherwise
942
   */
943 4
  public function isNumeric()
944
  {
945 4
    if ($this->isEmpty()) {
946 1
      return false;
947
    }
948
949 3
    foreach ($this->getKeys() as $key) {
950 3
      if (!is_int($key)) {
951 3
        return false;
952
      }
953
    }
954
955 1
    return true;
956
  }
957
958
  /**
959
   * Check if the current array is a multi-array.
960
   *
961
   * @return bool
962
   */
963 13
  public function isMultiArray()
964
  {
965 13
    return !(count($this->array) === count($this->array, COUNT_RECURSIVE));
966
  }
967
968
  /**
969
   * Check if an item is in the current array.
970
   *
971
   * @param mixed $value
972
   *
973
   * @return bool
974
   */
975 13
  public function contains($value)
976
  {
977 13
    return in_array($value, $this->array, true);
978
  }
979
980
  /**
981
   * Check if the given key/index exists in the array.
982
   *
983
   * @param mixed $key Key/index to search for
984
   *
985
   * @return bool Returns true if the given key/index exists in the array, false otherwise
986
   */
987 4
  public function containsKey($key)
988
  {
989 4
    return array_key_exists($key, $this->array);
990
  }
991
992
  /**
993
   * Returns the average value of the current array.
994
   *
995
   * @param int $decimals The number of decimals to return
996
   *
997
   * @return int|double The average value
998
   */
999 10
  public function average($decimals = null)
1000
  {
1001 10
    $count = $this->count();
1002
1003 10
    if (!$count) {
1004 2
      return 0;
1005
    }
1006
1007 8
    if (!is_int($decimals)) {
1008 3
      $decimals = null;
1009
    }
1010
1011 8
    return round(array_sum($this->array) / $count, $decimals);
1012
  }  /**
1013
   * Returns the value at specified offset.
1014
   *
1015
   * @param mixed $offset
1016
   *
1017
   * @return mixed return null if the offset did not exists
1018
   */
1019 15
  public function offsetGet($offset)
1020
  {
1021 15
    return $this->offsetExists($offset) ? $this->array[$offset] : null;
1022
  }
1023
1024
  /**
1025
   * Count the values from the current array.
1026
   *
1027
   * INFO: only a alias for "$arrayy->size()"
1028
   *
1029
   * @return int
1030
   */
1031 10
  public function length()
1032
  {
1033 10
    return $this->size();
1034
  }
1035
1036
  /**
1037
   * Get the max value from an array.
1038
   *
1039
   * @return mixed
1040
   */
1041 10
  public function max()
1042
  {
1043 10
    if ($this->count() === 0) {
1044 1
      return false;
1045
    }
1046
1047 9
    return max($this->array);
1048
  }
1049
1050
  /**
1051
   * Get the min value from an array.
1052
   *
1053
   * @return mixed
1054
   */
1055 10
  public function min()
1056
  {
1057 10
    if ($this->count() === 0) {
1058 1
      return false;
1059
    }
1060
1061 9
    return min($this->array);
1062
  }
1063
1064
  /**
1065
   * Find the first item in an array that passes the truth test,
1066
   *  otherwise return false
1067
   *
1068
   * @param \Closure $closure
1069
   *
1070
   * @return mixed|false false if we did not find the value
1071
   */
1072 8
  public function find(\Closure $closure)
1073
  {
1074 8
    foreach ($this->array as $key => $value) {
1075 6
      if ($closure($value, $key)) {
1076 6
        return $value;
1077
      }
1078
    }
1079
1080 3
    return false;
1081
  }
1082
1083
  /**
1084
   * WARNING!!! -> Clear the current array.
1085
   *
1086
   * @return $this will always return an empty Arrayy object
1087
   */
1088 4
  public function clear()
1089
  {
1090 4
    $this->array = array();
1091
1092 4
    return $this;
1093
  }
1094
1095
  /**
1096
   * Clean all falsy values from an array.
1097
   *
1098
   * @return Arrayy
1099
   */
1100 8
  public function clean()
1101
  {
1102 8
    return $this->filter(
1103
        function ($value) {
1104 7
          return (bool)$value;
1105 8
        }
1106
    );
1107
  }
1108
1109
  /**
1110
   * Find all items in an array that pass the truth test.
1111
   *
1112
   * @param \Closure|null $closure
1113
   *
1114
   * @return Arrayy
1115
   */
1116 8
  public function filter($closure = null)
1117
  {
1118 8
    if (!$closure) {
1119 1
      return $this->clean();
1120
    }
1121
1122 8
    $array = array_filter($this->array, $closure);
1123
1124 8
    return static::create($array);
1125
  }
1126
1127
  /**
1128
   * Get a random value from an array, with the ability to skew the results.
1129
   *
1130
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
1131
   *
1132
   * @param array    $array
1133
   * @param null|int $number how many values you will take?
1134
   *
1135
   * @return Arrayy
1136
   */
1137 9
  public function randomWeighted(array $array, $number = null)
1138
  {
1139 9
    $options = array();
1140 9
    foreach ($array as $option => $weight) {
1141 9
      if ($this->searchIndex($option) !== false) {
1142 9
        for ($i = 0; $i < $weight; ++$i) {
1143 1
          $options[] = $option;
1144
        }
1145
      }
1146
    }
1147
1148 9
    return $this->mergeAppendKeepIndex($options)->random($number);
1149
  }  /**
1150
   * Returns a new ArrayIterator, thus implementing the IteratorAggregate interface.
1151
   *
1152
   * @return \ArrayIterator An iterator for the values in the array.
1153
   */
1154 16
  public function getIterator()
1155
  {
1156 16
    return new \ArrayIterator($this->array);
1157
  }
1158
1159
  /**
1160
   * Search for the first index of the current array via $value.
1161
   *
1162
   * @param mixed $value
1163
   *
1164
   * @return mixed
1165
   */
1166 20
  public function searchIndex($value)
1167
  {
1168 20
    return array_search($value, $this->array, true);
1169
  }
1170
1171
  /**
1172
   * Merge the new $array into the current array.
1173
   *
1174
   * - keep key,value from the current array, also if the index is in the new $array
1175
   *
1176
   * @param array $array
1177
   * @param bool  $recursive
1178
   *
1179
   * @return Arrayy
1180
   */
1181 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...
1182
  {
1183 25
    if (true === $recursive) {
1184 4
      $result = array_replace_recursive($this->array, $array);
1185
    } else {
1186 21
      $result = array_replace($this->array, $array);
1187
    }
1188
1189 25
    return static::create($result);
1190
  }
1191
1192
  /**
1193
   * alias: for "Arrayy->searchIndex()"
1194
   *
1195
   * @param mixed $value Value to search for
1196
   *
1197
   * @return mixed
1198
   */
1199 4
  public function indexOf($value)
1200
  {
1201 4
    return $this->searchIndex($value);
1202
  }
1203
1204
  /**
1205
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1206
   *
1207
   * @param array $search
1208
   *
1209
   * @return bool
1210
   */
1211 1
  public function intersects(array $search)
1212
  {
1213 1
    return count($this->intersection($search)->array) > 0;
1214
  }
1215
1216
  /**
1217
   * Return an array with all elements found in input array.
1218
   *
1219
   * @param array $search
1220
   *
1221
   * @return Arrayy
1222
   */
1223 2
  public function intersection(array $search)
1224
  {
1225 2
    $result = array_values(array_intersect($this->array, $search));
1226
1227 2
    return static::create($result);
1228
  }
1229
1230
  /**
1231
   * Get the last value(s) from the current array.
1232
   *
1233
   * @param int|null $number
1234
   *
1235
   * @return Arrayy
1236
   */
1237 15
  public function last($number = null)
1238
  {
1239 15
    if ($number === null) {
1240 11
      $poppedValue = (array)$this->pop();
1241 11
      $arrayy = static::create($poppedValue);
1242
    } else {
1243 4
      $number = (int)$number;
1244 4
      $arrayy = $this->rest(-$number);
1245
    }
1246
1247 15
    return $arrayy;
1248
  }
1249
1250
  /**
1251
   * Pop a specified value off the end of the current array.
1252
   *
1253
   * @return mixed The popped element from the current array.
1254
   */
1255 15
  public function pop()
1256
  {
1257 15
    return array_pop($this->array);
1258
  }
1259
1260
  /**
1261
   * Get the last elements from index $from until the end of this array.
1262
   *
1263
   * @param int $from
1264
   *
1265
   * @return Arrayy
1266
   */
1267 16
  public function rest($from = 1)
1268
  {
1269 16
    $result = array_splice($this->array, $from);
1270
1271 16
    return static::create($result);
1272
  }
1273
1274
  /**
1275
   * Get everything but the last..$to items.
1276
   *
1277
   * @param int $to
1278
   *
1279
   * @return Arrayy
1280
   */
1281 12
  public function initial($to = 1)
1282
  {
1283 12
    $slice = count($this->array) - $to;
1284
1285 12
    return $this->first($slice);
1286
  }
1287
1288
  /**
1289
   * Extract a slice of the array.
1290
   *
1291
   * @param int      $offset       Slice begin index
1292
   * @param int|null $length       Length of the slice
1293
   * @param bool     $preserveKeys Whether array keys are preserved or no
1294
   *
1295
   * @return static A slice of the original array with length $length
1296
   */
1297 4
  public function slice($offset, $length = null, $preserveKeys = false)
1298
  {
1299 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
1300
1301 4
    return static::create($result);
1302
  }
1303
1304
  /**
1305
   * Iterate over an array and execute a callback for each loop.
1306
   *
1307
   * @param \Closure $closure
1308
   *
1309
   * @return Arrayy
1310
   */
1311 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...
1312
  {
1313 2
    $array = $this->array;
1314
1315 2
    foreach ($array as $key => $value) {
1316 2
      $closure($value, $key);
1317
    }
1318
1319 2
    return static::create($array);
1320
  }
1321
1322
  /**
1323
   * Merge the new $array into the current array.
1324
   *
1325
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1326
   * - create new indexes
1327
   *
1328
   * @param array $array
1329
   * @param bool  $recursive
1330
   *
1331
   * @return Arrayy
1332
   */
1333 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...
1334
  {
1335 16
    if (true === $recursive) {
1336 4
      $result = array_merge_recursive($this->array, $array);
1337
    } else {
1338 12
      $result = array_merge($this->array, $array);
1339
    }
1340
1341 16
    return static::create($result);
1342
  }
1343
1344
  /**
1345
   * Merge the current array into the new $array.
1346
   *
1347
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1348
   * - create new indexes
1349
   *
1350
   * @param array $array
1351
   * @param bool  $recursive
1352
   *
1353
   * @return Arrayy
1354
   */
1355 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...
1356
  {
1357 16
    if (true === $recursive) {
1358 4
      $result = array_merge_recursive($array, $this->array);
1359
    } else {
1360 12
      $result = array_merge($array, $this->array);
1361
    }
1362
1363 16
    return static::create($result);
1364
  }
1365
1366
  /**
1367
   * Merge the the current array into the $array.
1368
   *
1369
   * - use key,value from the new $array, also if the index is in the current array
1370
   *
1371
   * @param array $array
1372
   * @param bool  $recursive
1373
   *
1374
   * @return Arrayy
1375
   */
1376 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...
1377
  {
1378 16
    if (true === $recursive) {
1379 4
      $result = array_replace_recursive($array, $this->array);
1380
    } else {
1381 12
      $result = array_replace($array, $this->array);
1382
    }
1383
1384 16
    return static::create($result);
1385
  }
1386
1387
  /**
1388
   * Return values that are only in the current array.
1389
   *
1390
   * @param array $array
1391
   *
1392
   * @return Arrayy
1393
   */
1394 12
  public function diff(array $array = array())
1395
  {
1396 12
    $result = array_diff($this->array, $array);
1397
1398 12
    return static::create($result);
1399
  }
1400
1401
  /**
1402
   * Return values that are only in the new $array.
1403
   *
1404
   * @param array $array
1405
   *
1406
   * @return Arrayy
1407
   */
1408 8
  public function diffReverse(array $array = array())
1409
  {
1410 8
    $result = array_diff($array, $this->array);
1411
1412 8
    return static::create($result);
1413
  }
1414
1415
  /**
1416
   * Replace the first matched value in an array.
1417
   *
1418
   * @param mixed $search
1419
   * @param mixed $replacement
1420
   *
1421
   * @return Arrayy
1422
   */
1423 3
  public function replaceOneValue($search, $replacement = '')
1424
  {
1425 3
    $array = $this->array;
1426 3
    $key = array_search($search, $array, true);
1427
1428 3
    if ($key !== false) {
1429 3
      $array[$key] = $replacement;
1430
    }
1431
1432 3
    return static::create($array);
1433
  }
1434
1435
  /**
1436
   * Replace values in the current array.
1437
   *
1438
   * @param string $search      The string to replace.
1439
   * @param string $replacement What to replace it with.
1440
   *
1441
   * @return Arrayy
1442
   */
1443 1
  public function replaceValues($search, $replacement = '')
1444
  {
1445 1
    $array = $this->each(
1446
        function ($value) use ($search, $replacement) {
1447 1
          return UTF8::str_replace($search, $replacement, $value);
1448 1
        }
1449
    );
1450
1451 1
    return static::create($array);
0 ignored issues
show
Documentation introduced by
$array is of type object<Arrayy\Arrayy>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1452
  }
1453
1454
  /**
1455
   * Replace the keys in an array with another set.
1456
   *
1457
   * @param array $keys An array of keys matching the array's size
1458
   *
1459
   * @return Arrayy
1460
   */
1461 1
  public function replaceKeys(array $keys)
1462
  {
1463 1
    $values = array_values($this->array);
1464 1
    $result = array_combine($keys, $values);
1465
1466 1
    return static::create($result);
1467
  }
1468
1469
  /**
1470
   * Create an array using the current array as keys and the other array as values.
1471
   *
1472
   * @param array $array Values array
1473
   *
1474
   * @return Arrayy Arrayy object with values from the other array.
1475
   */
1476 1
  public function replaceAllValues(array $array)
1477
  {
1478 1
    $result = array_combine($this->array, $array);
1479
1480 1
    return static::create($result);
1481
  }
1482
1483
  /**
1484
   * Create an array using the current array as values and the other array as keys.
1485
   *
1486
   * @param array $keys Keys array
1487
   *
1488
   * @return Arrayy Arrayy object with keys from the other array.
1489
   */
1490 1
  public function replaceAllKeys(array $keys)
1491
  {
1492 1
    $result = array_combine($keys, $this->array);
1493
1494 1
    return static::create($result);
1495
  }
1496
1497
  /**
1498
   * Shuffle the current array.
1499
   *
1500
   * @return Arrayy
1501
   */
1502 1
  public function shuffle()
1503
  {
1504 1
    $array = $this->array;
1505
1506 1
    shuffle($array);
1507
1508 1
    return static::create($array);
1509
  }
1510
1511
  /**
1512
   * Split an array in the given amount of pieces.
1513
   *
1514
   * @param int  $numberOfPieces
1515
   * @param bool $keepKeys
1516
   *
1517
   * @return array
1518
   */
1519 1
  public function split($numberOfPieces = 2, $keepKeys = false)
1520
  {
1521 1
    if (count($this->array) === 0) {
1522 1
      $result = array();
1523
    } else {
1524 1
      $numberOfPieces = (int)$numberOfPieces;
1525 1
      $splitSize = ceil(count($this->array) / $numberOfPieces);
1526 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
1527
    }
1528
1529 1
    return static::create($result);
1530
  }
1531
1532
  /**
1533
   * Create a chunked version of this array.
1534
   *
1535
   * @param int  $size         Size of each chunk
1536
   * @param bool $preserveKeys Whether array keys are preserved or no
1537
   *
1538
   * @return static A new array of chunks from the original array
1539
   */
1540 4
  public function chunk($size, $preserveKeys = false)
1541
  {
1542 4
    $result = array_chunk($this->array, $size, $preserveKeys);
1543
1544 4
    return static::create($result);
1545
  }
1546
1547
  /**
1548
   * Returns the values from a single column of the input array, identified by
1549
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1550
   *
1551
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1552
   * array by the values from the $indexKey column in the input array.
1553
   *
1554
   * @param mixed $columnKey
1555
   * @param mixed $indexKey
1556
   *
1557
   * @return Arrayy
1558
   */
1559 1
  public function getColumn($columnKey = null, $indexKey = null)
1560
  {
1561 1
    $result = array_column($this->array, $columnKey, $indexKey);
1562
1563 1
    return static::create($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by array_column($this->array, $columnKey, $indexKey) on line 1561 can also be of type false or null; however, Arrayy\Arrayy::create() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1564
  }
1565
1566
  /**
1567
   * Invoke a function on all of an array's values.
1568
   *
1569
   * @param mixed $callable
1570
   * @param array $arguments
1571
   *
1572
   * @return Arrayy
1573
   */
1574 1
  public function invoke($callable, $arguments = array())
1575
  {
1576
    // If one argument given for each iteration, create an array for it.
1577 1
    if (!is_array($arguments)) {
1578 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1579
    }
1580
1581
    // If the callable has arguments, pass them.
1582 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...
1583 1
      $array = array_map($callable, $this->array, $arguments);
1584
    } else {
1585 1
      $array = array_map($callable, $this->array);
1586
    }
1587
1588 1
    return static::create($array);
1589
  }
1590
1591
  /**
1592
   * Apply the given function to the every element of the array,
1593
   * collecting the results.
1594
   *
1595
   * @param callable $callable
1596
   *
1597
   * @return Arrayy Arrayy object with modified elements
1598
   */
1599 4
  public function map($callable)
1600
  {
1601 4
    $result = array_map($callable, $this->array);
1602
1603 4
    return static::create($result);
1604
  }
1605
1606
  /**
1607
   * Check if a value is in the current array using a closure.
1608
   *
1609
   * @param \Closure $closure
1610
   *
1611
   * @return bool Returns true if the given value is found, false otherwise
1612
   */
1613 4
  public function exists(\Closure $closure)
1614
  {
1615 4
    $isExists = false;
1616 4
    foreach ($this->array as $key => $value) {
1617 3
      if ($closure($value, $key)) {
1618 1
        $isExists = true;
1619 3
        break;
1620
      }
1621
    }
1622
1623 4
    return $isExists;
1624
  }
1625
1626
  /**
1627
   * Return all items that fail the truth test.
1628
   *
1629
   * @param \Closure $closure
1630
   *
1631
   * @return Arrayy
1632
   */
1633 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...
1634
  {
1635 1
    $filtered = array();
1636
1637 1
    foreach ($this->array as $key => $value) {
1638 1
      if (!$closure($value, $key)) {
1639 1
        $filtered[$key] = $value;
1640
      }
1641
    }
1642
1643 1
    return static::create($filtered);
1644
  }
1645
1646
  /**
1647
   * Replace a key with a new key/value pair.
1648
   *
1649
   * @param $replace
1650
   * @param $key
1651
   * @param $value
1652
   *
1653
   * @return Arrayy
1654
   */
1655 1
  public function replace($replace, $key, $value)
1656
  {
1657 1
    $this->remove($replace);
1658
1659 1
    return $this->set($key, $value);
1660
  }
1661
1662
  /**
1663
   * Remove a value from the current array (optional using dot-notation).
1664
   *
1665
   * @param mixed $key
1666
   *
1667
   * @return Arrayy
1668
   */
1669 17
  public function remove($key)
1670
  {
1671
    // Recursive call
1672 17
    if (is_array($key)) {
1673
      foreach ($key as $k) {
1674
        $this->internalRemove($k);
1675
      }
1676
1677
      return static::create($this->array);
1678
    }
1679
1680 17
    $this->internalRemove($key);
1681
1682 17
    return static::create($this->array);
1683
  }
1684
1685
  /**
1686
   * Internal mechanics of remove method.
1687
   *
1688
   * @param $key
1689
   *
1690
   * @return boolean
1691
   */
1692 17
  protected function internalRemove($key)
1693
  {
1694
    // Explode keys
1695 17
    $keys = explode('.', $key);
1696
1697
    // Crawl though the keys
1698 17 View Code Duplication
    while (count($keys) > 1) {
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...
1699
      $key = array_shift($keys);
1700
1701
      if (!$this->has($key)) {
1702
        return false;
1703
      }
1704
1705
      $this->array = &$this->array[$key];
1706
    }
1707
1708 17
    $key = array_shift($keys);
1709
1710 17
    unset($this->array[$key]);
1711
1712 17
    return true;
1713
  }
1714
1715
  /**
1716
   * Check if an array has a given key.
1717
   *
1718
   * @param mixed $key
1719
   *
1720
   * @return bool
1721
   */
1722 18
  public function has($key)
1723
  {
1724
    // Generate unique string to use as marker.
1725 18
    $unFound = (string)uniqid('arrayy', true);
1726
1727 18
    return $this->get($key, $unFound) !== $unFound;
1728
  }
1729
1730
  /**
1731
   * Set a value for the current array (optional using dot-notation).
1732
   *
1733
   * @param string $key   The key to set
1734
   * @param mixed  $value Its value
1735
   *
1736
   * @return Arrayy
1737
   */
1738 14
  public function set($key, $value)
1739
  {
1740 14
    $this->internalSet($key, $value);
1741
1742 14
    return static::create($this->array);
1743
  }
1744
1745
  /**
1746
   * Internal mechanic of set method.
1747
   *
1748
   * @param mixed $key
1749
   * @param mixed $value
1750
   *
1751
   * @return bool
1752
   */
1753 14
  protected function internalSet($key, $value)
1754
  {
1755 14
    if (null === $key) {
1756
      return false;
1757
    }
1758
1759
    // Explode the keys
1760 14
    $keys = explode('.', $key);
1761
1762
    // Crawl through the keys
1763 14 View Code Duplication
    while (count($keys) > 1) {
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...
1764
      $key = array_shift($keys);
1765
1766
      $this->array[$key] = $this->get(array(), null, $key);
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1767
      $this->array = &$this->array[$key];
1768
    }
1769
1770
    // Bind final tree on the array
1771 14
    $key = array_shift($keys);
1772
1773 14
    $this->array[$key] = $value;
1774
1775 14
    return true;
1776
  }
1777
1778
  /**
1779
   * Get a value from a array and set it if it was not.
1780
   *
1781
   * WARNING: this method only set the value, if the $key is not already set
1782
   *
1783
   * @param string $key     The key
1784
   * @param mixed  $default The default value to set if it isn't
1785
   *
1786
   * @return mixed
1787
   */
1788 9
  public function setAndGet($key, $default = null)
1789
  {
1790
    // If the key doesn't exist, set it
1791 9
    if (!$this->has($key)) {
1792 4
      $this->array = $this->set($key, $default)->getArray();
1793
    }
1794
1795 9
    return $this->get($key);
1796
  }
1797
1798
  /**
1799
   * Remove the first value from the current array.
1800
   *
1801
   * @return Arrayy
1802
   */
1803 7
  public function removeFirst()
1804
  {
1805 7
    array_shift($this->array);
1806
1807 7
    return static::create($this->array);
1808
  }
1809
1810
  /**
1811
   * Remove the last value from the current array.
1812
   *
1813
   * @return Arrayy
1814
   */
1815 7
  public function removeLast()
1816
  {
1817 7
    array_pop($this->array);
1818
1819 7
    return static::create($this->array);
1820
  }
1821
1822
  /**
1823
   * Removes a particular value from an array (numeric or associative).
1824
   *
1825
   * @param mixed $value
1826
   *
1827
   * @return Arrayy
1828
   */
1829 7
  public function removeValue($value)
1830
  {
1831 7
    $isNumericArray = true;
1832 7
    foreach ($this->array as $key => $item) {
1833 6
      if ($item === $value) {
1834 6
        if (!is_int($key)) {
1835
          $isNumericArray = false;
1836
        }
1837 6
        unset($this->array[$key]);
1838
      }
1839
    }
1840
1841 7
    if ($isNumericArray) {
1842 7
      $this->array = array_values($this->array);
1843
    }
1844
1845 7
    return static::create($this->array);
1846
  }
1847
1848
  /**
1849
   * Pad array to the specified size with a given value.
1850
   *
1851
   * @param int   $size  Size of the result array
1852
   * @param mixed $value Empty value by default
1853
   *
1854
   * @return Arrayy Arrayy object padded to $size with $value
1855
   */
1856 4
  public function pad($size, $value)
1857
  {
1858 4
    $result = array_pad($this->array, $size, $value);
1859
1860 4
    return static::create($result);
1861
  }
1862
1863
  /**
1864
   * Prepend a value to an array.
1865
   *
1866
   * @param mixed $value
1867
   *
1868
   * @return Arrayy
1869
   */
1870 7
  public function prepend($value)
1871
  {
1872 7
    array_unshift($this->array, $value);
1873
1874 7
    return static::create($this->array);
1875
  }
1876
1877
  /**
1878
   * alias: for "Arrayy->append()"
1879
   *
1880
   * @param $value
1881
   *
1882
   * @return $this
1883
   */
1884 1
  public function add($value)
1885
  {
1886 1
    $this->array[] = $value;
1887
1888 1
    return $this;
1889
  }
1890
1891
  /**
1892
   * Create a numerically re-indexed Arrayy object.
1893
   *
1894
   * @return Arrayy The new instance with re-indexed array-elements
1895
   */
1896 8
  public function reindex()
1897
  {
1898 8
    $this->array = array_values($this->array);
1899
1900 8
    return static::create($this->array);
1901
  }
1902
1903
  /**
1904
   * Return the array in the reverse order.
1905
   *
1906
   * @return Arrayy
1907
   */
1908 7
  public function reverse()
1909
  {
1910 7
    $this->array = array_reverse($this->array);
1911
1912 7
    return static::create($this->array);
1913
  }
1914
1915
  /**
1916
   * Custom sort by value via "usort"
1917
   *
1918
   * @link http://php.net/manual/en/function.usort.php
1919
   *
1920
   * @param callable $func
1921
   *
1922
   * @return $this
1923
   */
1924 4
  public function customSortValues($func)
1925
  {
1926 4
    usort($this->array, $func);
1927
1928 4
    return $this;
1929
  }
1930
1931
  /**
1932
   * Custom sort by index via "uksort"
1933
   *
1934
   * @link http://php.net/manual/en/function.uksort.php
1935
   *
1936
   * @param callable $func
1937
   *
1938
   * @return $this
1939
   */
1940 4
  public function customSortKeys($func)
1941
  {
1942 4
    uksort($this->array, $func);
1943
1944 4
    return $this;
1945
  }
1946
1947
  /**
1948
   * Sort the current array by key.
1949
   *
1950
   * @link http://php.net/manual/en/function.ksort.php
1951
   * @link http://php.net/manual/en/function.krsort.php
1952
   *
1953
   * @param int|string $direction use SORT_ASC or SORT_DESC
1954
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
1955
   *
1956
   * @return $this
1957
   */
1958 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
1959
  {
1960 18
    $this->sorterKeys($this->array, $direction, $strategy);
1961
1962 18
    return $this;
1963
  }
1964
1965
  /**
1966
   * sorting keys
1967
   *
1968
   * @param array $elements
1969
   * @param int   $direction
1970
   * @param int   $strategy
1971
   */
1972 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
1973
  {
1974 18
    $direction = $this->getDirection($direction);
1975
1976
    switch ($direction) {
1977 18
      case 'desc':
1978 18
      case SORT_DESC:
1979 6
        krsort($elements, $strategy);
1980 6
        break;
1981 13
      case 'asc':
1982 13
      case SORT_ASC:
1983
      default:
1984 13
        ksort($elements, $strategy);
1985
    }
1986 18
  }
1987
1988
  /**
1989
   * Get correct PHP constant for direction.
1990
   *
1991
   * @param int|string $direction
1992
   *
1993
   * @return int
1994
   */
1995 38
  protected function getDirection($direction)
1996
  {
1997 38
    if (is_string($direction)) {
1998 10
      $direction = strtolower($direction);
1999
2000 10
      if ($direction === 'desc') {
2001 2
        $direction = SORT_DESC;
2002
      } else {
2003 8
        $direction = SORT_ASC;
2004
      }
2005
    }
2006
2007
    if (
2008 38
        $direction !== SORT_DESC
2009
        &&
2010 38
        $direction !== SORT_ASC
2011
    ) {
2012
      $direction = SORT_ASC;
2013
    }
2014
2015 38
    return $direction;
2016
  }
2017
2018
  /**
2019
   * Sort the current array by value.
2020
   *
2021
   * @param int $direction use SORT_ASC or SORT_DESC
2022
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2023
   *
2024
   * @return Arrayy
2025
   */
2026 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2027
  {
2028 1
    return $this->sort($direction, $strategy, true);
2029
  }
2030
2031
  /**
2032
   * Sort the current array and optional you can keep the keys.
2033
   *
2034
   * @param string|int $direction use SORT_ASC or SORT_DESC
2035
   * @param int|string $strategy
2036
   * @param bool       $keepKeys
2037
   *
2038
   * @return Arrayy
2039
   */
2040 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2041
  {
2042 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2043
2044 19
    return $this;
2045
  }
2046
2047
  /**
2048
   * @param array      &$elements
2049
   * @param int|string $direction
2050
   * @param int        $strategy
2051
   * @param bool       $keepKeys
2052
   */
2053 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2054
  {
2055 19
    $direction = $this->getDirection($direction);
2056
2057 19
    if (!$strategy) {
2058 19
      $strategy = SORT_REGULAR;
2059
    }
2060
2061
    switch ($direction) {
2062 19
      case 'desc':
2063 19
      case SORT_DESC:
2064 9
        if ($keepKeys) {
2065 5
          arsort($elements, $strategy);
2066
        } else {
2067 4
          rsort($elements, $strategy);
2068
        }
2069 9
        break;
2070 10
      case 'asc':
2071 10
      case SORT_ASC:
2072
      default:
2073 10
        if ($keepKeys) {
2074 4
          asort($elements, $strategy);
2075
        } else {
2076 6
          sort($elements, $strategy);
2077
        }
2078
    }
2079 19
  }
2080
2081
  /**
2082
   * Sort the current array by value.
2083
   *
2084
   * @param int $direction use SORT_ASC or SORT_DESC
2085
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2086
   *
2087
   * @return Arrayy
2088
   */
2089 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2090
  {
2091 1
    return $this->sort($direction, $strategy, false);
2092
  }
2093
2094
  /**
2095
   * Sort a array by value, by a closure or by a property.
2096
   *
2097
   * - If the sorter is null, the array is sorted naturally.
2098
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2099
   *
2100
   * @param null       $sorter
2101
   * @param string|int $direction
2102
   * @param int        $strategy
2103
   *
2104
   * @return Arrayy
2105
   */
2106 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2107
  {
2108 1
    $array = (array)$this->array;
2109 1
    $direction = $this->getDirection($direction);
2110
2111
    // Transform all values into their results.
2112 1
    if ($sorter) {
2113 1
      $arrayy = new self($array);
2114
2115 1
      $that = $this;
2116 1
      $results = $arrayy->each(
2117
          function ($value) use ($sorter, $that) {
2118 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2119 1
          }
2120
      );
2121
2122 1
      $results = $results->getArray();
2123
    } else {
2124 1
      $results = $array;
2125
    }
2126
2127
    // Sort by the results and replace by original values
2128 1
    array_multisort($results, $direction, $strategy, $array);
2129
2130 1
    return static::create($array);
2131
  }
2132
2133
  /**
2134
   * Exchanges all keys with their associated values in an array.
2135
   *
2136
   * @return Arrayy
2137
   */
2138 1
  public function flip()
2139
  {
2140 1
    $this->array = array_flip($this->array);
2141
2142 1
    return static::create($this->array);
2143
  }
2144
2145
  /**
2146
   * Apply the given function to every element in the array,
2147
   * discarding the results.
2148
   *
2149
   * @param callable $callable
2150
   * @param bool     $recursive Whether array will be walked recursively or no
2151
   *
2152
   * @return Arrayy An Arrayy object with modified elements
2153
   */
2154 8
  public function walk($callable, $recursive = false)
2155
  {
2156 8
    if (true === $recursive) {
2157 4
      array_walk_recursive($this->array, $callable);
2158
    } else {
2159 4
      array_walk($this->array, $callable);
2160
    }
2161
2162 8
    return $this;
2163
  }
2164
2165
  /**
2166
   * Reduce the current array via callable e.g. anonymous-function.
2167
   *
2168
   * @param mixed $callable
2169
   * @param array $init
2170
   *
2171
   * @return Arrayy
2172
   */
2173 2
  public function reduce($callable, array $init = array())
2174
  {
2175 2
    $this->array = array_reduce($this->array, $callable, $init);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce($this->array, $callable, $init) 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...
2176
2177 2
    return static::create($this->array);
2178
  }
2179
2180
  /**
2181
   * Return a duplicate free copy of the current array.
2182
   *
2183
   * @return Arrayy
2184
   */
2185 7
  public function unique()
2186
  {
2187 7
    $this->array = array_reduce(
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce($this->arra...esultArray; }, array()) of type * is incompatible with the declared type array of property $array.

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

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

Loading history...
2188 7
        $this->array,
2189 7
        function ($resultArray, $value) {
2190 6
          if (in_array($value, $resultArray, true) === false) {
2191 6
            $resultArray[] = $value;
2192
          }
2193
2194 6
          return $resultArray;
2195 7
        },
2196 7
        array()
2197
    );
2198
2199 7
    return static::create($this->array);
2200
  }
2201
2202
  /**
2203
   * Convert the current array to JSON.
2204
   *
2205
   * @param null $options e.g. JSON_PRETTY_PRINT
2206
   *
2207
   * @return string
2208
   */
2209 5
  public function toJson($options = null)
2210
  {
2211 5
    return UTF8::json_encode($this->array, $options);
2212
  }
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
}
2224