Completed
Push — master ( d074f3...e3cc97 )
by Lars
02:17
created

Arrayy::matches()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 6

Duplication

Lines 14
Ratio 100 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 14
loc 14
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 6
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 670
  public function __construct($array = array())
28
  {
29 670
    $array = $this->fallbackForArray($array);
30
31 668
    $this->array = $array;
0 ignored issues
show
Documentation Bug introduced by
It seems like $array can also be of type object<Arrayy\Arrayy>. However, the property $array is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
32 668
  }
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 670
  protected function fallbackForArray(&$array)
47
  {
48 670
    if (is_array($array)) {
49 668
      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 2
        (is_object($array) && method_exists($array, '__toString'))
64 3
    ) {
65 1
      return (array)$array;
66
    }
67
68 2
    if ($array instanceof ArrayAccess) {
69
      return self::createFromObject($array);
70
    }
71
72 2
    if (is_object($array) && method_exists($array, '__toArray')) {
73
      return (array)$array->__toArray();
74
    }
75
76 2
    throw new \InvalidArgumentException(
77
        'Passed value must be a array'
78 2
    );
79
  }
80
81
  /**
82
   * Get the current array from the "Arrayy"-object
83
   *
84
   * @return array
85
   */
86 466
  public function getArray()
87
  {
88 466
    return $this->array;
89
  }
90
91
  /**
92
   * Create a new Arrayy object via string.
93
   *
94
   * @param string      $str       The input string.
95
   * @param string|null $delimiter The boundary string.
96
   * @param string|null $regEx     Use the $delimiter or the $regEx, so if $pattern is null, $delimiter will be used.
97
   *
98
   * @return Arrayy Returns created instance
99
   */
100 8
  public static function createFromString($str, $delimiter, $regEx = null)
101
  {
102 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...
103 1
      preg_match_all($regEx, $str, $array);
104
105 1
      if (count($array) > 0) {
106 1
        $array = $array[0];
107 1
      }
108
109 1
    } else {
110 7
      $array = explode($delimiter, $str);
111
    }
112
113
    // trim all string in the array
114 8
    array_walk(
115 8
        $array,
116
        function (&$val) {
117 8
          if (is_string($val)) {
118 8
            $val = trim($val);
119 8
          }
120 8
        }
121 8
    );
122
123 8
    return static::create($array);
124
  }
125
126
  /**
127
   * Creates a Arrayy object.
128
   *
129
   * @param array $array
130
   *
131
   * @return Arrayy Returns created instance
132
   */
133 432
  public static function create($array = array())
134
  {
135 432
    return new static($array);
136
  }
137
138
  /**
139
   * create a new Arrayy object via JSON,
140
   *
141
   * @param string $json
142
   *
143
   * @return Arrayy Returns created instance
144
   */
145 5
  public static function createFromJson($json)
146
  {
147 5
    $array = UTF8::json_decode($json, true);
148
149 5
    return static::create($array);
150
  }
151
152
  /**
153
   * Create a new instance filled with values from an object implementing ArrayAccess.
154
   *
155
   * @param ArrayAccess $elements Object that implements ArrayAccess
156
   *
157
   * @return Arrayy Returns created instance
158
   */
159 4
  public static function createFromObject(ArrayAccess $elements)
160
  {
161 4
    $array = new static();
162 4
    foreach ($elements as $key => $value) {
163
      /** @noinspection OffsetOperationsInspection */
164 3
      $array[$key] = $value;
165 4
    }
166
167 4
    return $array;
168
  }
169
170
  /**
171
   * Create a new instance containing a range of elements.
172
   *
173
   * @param mixed $low  First value of the sequence
174
   * @param mixed $high The sequence is ended upon reaching the end value
175
   * @param int   $step Used as the increment between elements in the sequence
176
   *
177
   * @return Arrayy The created array
178
   */
179 1
  public static function createWithRange($low, $high, $step = 1)
180
  {
181 1
    return static::create(range($low, $high, $step));
182
  }
183
184
  /**
185
   * alias: for "Arrayy->random()"
186
   *
187
   * @return Arrayy
188
   */
189 3
  public function getRandom()
190
  {
191 3
    return $this->random();
192
  }
193
194
  /**
195
   * Get a random value from the current array.
196
   *
197
   * @param null|int $number how many values you will take?
198
   *
199
   * @return Arrayy
200
   */
201 30
  public function random($number = null)
202
  {
203 30
    if ($this->count() === 0) {
204
      return static::create();
205
    }
206
207 30
    if ($number === null) {
208 15
      $arrayRandValue = (array)$this->array[array_rand($this->array)];
209
210 15
      return static::create($arrayRandValue);
211
    }
212
213 17
    shuffle($this->array);
214
215 17
    return $this->first($number);
216
  }
217
218
  /**
219
   * Count the values from the current array.
220
   *
221
   * INFO: only a alias for "$arrayy->size()"
222
   *
223
   * @return int
224
   */
225 105
  public function count()
226
  {
227 105
    return $this->size();
228
  }
229
230
  /**
231
   * Get the size of an array.
232
   *
233
   * @return int
234
   */
235 105
  public function size()
236
  {
237 105
    return count($this->array);
238
  }
239
240
  /**
241
   * Get the first value(s) from the current array.
242
   *
243
   * @param int|null $number how many values you will take?
244
   *
245
   * @return Arrayy
246
   */
247 46
  public function first($number = null)
248
  {
249 46
    if ($number === null) {
250 12
      $array = (array)array_shift($this->array);
251 12
    } else {
252 34
      $number = (int)$number;
253 34
      $array = array_splice($this->array, 0, $number, true);
254
    }
255
256 46
    return static::create($array);
257
  }
258
259
  /**
260
   * Append a value to an array.
261
   *
262
   * @param mixed $value
263
   *
264
   * @return $this This Arrayy object with the appended values.
265
   */
266 8
  public function append($value)
267
  {
268 8
    $this->array[] = $value;
269
270 8
    return $this;
271
  }
272
273
  /**
274
   * @return mixed
275
   */
276
  public function serialize()
277
  {
278
    return serialize($this->array);
279
  }
280
281
  /**
282
   * @param string $array
283
   */
284
  public function unserialize($array)
285
  {
286
    $this->array = unserialize($array);
287
  }
288
289
  /**
290
   * Assigns a value to the specified offset.
291
   *
292
   * @param mixed $offset
293
   * @param mixed $value
294
   */
295 13
  public function offsetSet($offset, $value)
296
  {
297 13
    if (null === $offset) {
298 4
      $this->array[] = $value;
299 4
    } else {
300 9
      $this->array[$offset] = $value;
301
    }
302 13
  }
303
304
  /**
305
   * alias: for "Arrayy->randomValue()"
306
   *
307
   * @return mixed get a random value or null if there wasn't a value
308
   */
309 3
  public function getRandomValue()
310
  {
311 3
    return $this->randomValue();
312
  }
313
314
  /**
315
   * Pick a random value from the values of this array.
316
   *
317
   * @return mixed get a random value or null if there wasn't a value
318
   */
319 3 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...
320
  {
321 3
    $result = $this->random(1);
322
323 3
    if (!isset($result[0])) {
324
      $result[0] = null;
325
    }
326
327 3
    return $result[0];
328
  }
329
330
  /**
331
   * alias: for "Arrayy->randomValues()"
332
   *
333
   * @param int $number
334
   *
335
   * @return Arrayy
336
   */
337 6
  public function getRandomValues($number)
338
  {
339 6
    return $this->randomValues($number);
340
  }
341
342
  /**
343
   * Pick a given number of random values out of this array.
344
   *
345
   * @param int $number
346
   *
347
   * @return Arrayy
348
   */
349 6
  public function randomValues($number)
350
  {
351 6
    $number = (int)$number;
352
353 6
    return $this->random($number);
354
  }
355
356
  /**
357
   * alias: for "Arrayy->randomKey()"
358
   *
359
   * @return mixed get a key/index or null if there wasn't a key/index
360
   */
361 3
  public function getRandomKey()
362
  {
363 3
    return $this->randomKey();
364
  }
365
366
  /**
367
   * Pick a random key/index from the keys of this array.
368
   *
369
   *
370
   * @return mixed get a key/index or null if there wasn't a key/index
371
   *
372
   * @throws \RangeException If array is empty
373
   */
374 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...
375
  {
376 3
    $result = $this->randomKeys(1);
377
378 3
    if (!isset($result[0])) {
379
      $result[0] = null;
380
    }
381
382 3
    return $result[0];
383
  }
384
385
  /**
386
   * Pick a given number of random keys/indexes out of this array.
387
   *
388
   * @param int $number The number of keys/indexes (should be <= $this->count())
389
   *
390
   * @return Arrayy
391
   *
392
   * @throws \RangeException If array is empty
393
   */
394 12
  public function randomKeys($number)
395
  {
396 12
    $number = (int)$number;
397 12
    $count = $this->count();
398
399 12
    if ($number === 0 || $number > $count) {
400 3
      throw new \RangeException(
401 3
          sprintf(
402 3
              'Number of requested keys (%s) must be equal or lower than number of elements in this array (%s)',
403 3
              $number,
404
              $count
405 3
          )
406 3
      );
407
    }
408
409 9
    $result = (array)array_rand($this->array, $number);
410
411 9
    return static::create($result);
412
  }
413
414
  /**
415
   * alias: for "Arrayy->randomKeys()"
416
   *
417
   * @param int $number
418
   *
419
   * @return Arrayy
420
   */
421 9
  public function getRandomKeys($number)
422
  {
423 9
    return $this->randomKeys($number);
424
  }
425
426
  /**
427
   * find by ...
428
   *
429
   * @param        $property
430
   * @param        $value
431
   * @param string $comparisonOp
432
   *
433
   * @return Arrayy
434
   */
435
  public function findBy($property, $value, $comparisonOp = 'eq')
436
  {
437
    $array = $this->filterBy($property, $value, $comparisonOp);
438
439
    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...
440
  }
441
442
  /**
443
   * Filters an array of objects (or a numeric array of associative arrays) based on the value of a particular property
444
   * within that.
445
   *
446
   * @param        $property
447
   * @param        $value
448
   * @param string $comparisonOp
449
   *
450
   * @return Arrayy
451
   */
452 1
  public function filterBy($property, $value, $comparisonOp = null)
453
  {
454 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...
455 1
      $comparisonOp = is_array($value) ? 'contains' : 'eq';
456 1
    }
457
458
    $ops = array(
459
        'eq'          => function ($item, $prop, $value) {
460 1
          return $item[$prop] === $value;
461 1
        },
462
        'gt'          => function ($item, $prop, $value) {
463
          return $item[$prop] > $value;
464 1
        },
465
        'gte'         => function ($item, $prop, $value) {
466
          return $item[$prop] >= $value;
467 1
        },
468
        'lt'          => function ($item, $prop, $value) {
469 1
          return $item[$prop] < $value;
470 1
        },
471
        'lte'         => function ($item, $prop, $value) {
472
          return $item[$prop] <= $value;
473 1
        },
474
        'ne'          => function ($item, $prop, $value) {
475
          return $item[$prop] !== $value;
476 1
        },
477
        'contains'    => function ($item, $prop, $value) {
478 1
          return in_array($item[$prop], (array)$value, true);
479 1
        },
480
        'notContains' => function ($item, $prop, $value) {
481
          return !in_array($item[$prop], (array)$value, true);
482 1
        },
483
        'newer'       => function ($item, $prop, $value) {
484
          return strtotime($item[$prop]) > strtotime($value);
485 1
        },
486
        'older'       => function ($item, $prop, $value) {
487
          return strtotime($item[$prop]) < strtotime($value);
488 1
        },
489 1
    );
490
491 1
    $result = array_values(
492 1
        array_filter(
493 1
            (array)$this->array,
494
            function ($item) use (
495 1
                $property,
496 1
                $value,
497 1
                $ops,
498 1
                $comparisonOp
499
            ) {
500 1
              $item = (array)$item;
501 1
              $itemArrayy = new Arrayy($item);
502 1
              $item[$property] = $itemArrayy->get($property, array());
503
504 1
              return $ops[$comparisonOp]($item, $property, $value);
505
            }
506 1
        )
507 1
    );
508
509 1
    return static::create($result);
510
  }
511
512
  /**
513
   * Get a value from an array (optional using dot-notation).
514
   *
515
   * @param string $key     The key to look for
516
   * @param mixed  $default Default value to fallback to
517
   * @param array  $array   The array to get from,
518
   *                        if it's set to "null" we use the current array from the class
519
   *
520
   * @return mixed
521
   */
522 31
  public function get($key, $default = null, $array = null)
523
  {
524 31
    if (is_array($array) === true) {
525 3
      $usedArray = $array;
526 3
    } else {
527 29
      $usedArray = $this->array;
528
    }
529
530 31
    if (null === $key) {
531 1
      return $usedArray;
532
    }
533
534 31
    if (isset($usedArray[$key])) {
535 22
      return $usedArray[$key];
536
    }
537
538
    // Crawl through array, get key according to object or not
539 16
    foreach (explode('.', $key) as $segment) {
540 16
      if (!isset($usedArray[$segment])) {
541 16
        return $default instanceof Closure ? $default() : $default;
542
      }
543
544
      $usedArray = $usedArray[$segment];
545
    }
546
547
    return $usedArray;
548
  }
549
550
  /**
551
   * WARNING: Creates a Arrayy object by reference.
552
   *
553
   * @param array $array
554
   *
555
   * @return $this
556
   */
557
  public function createByReference(&$array = array())
558
  {
559
    $array = $this->fallbackForArray($array);
560
561
    $this->array = &$array;
562
563
    return $this;
564
  }
565
566
  /**
567
   * Get all values from a array.
568
   *
569
   * @return Arrayy
570
   */
571 1
  public function values()
572
  {
573 1
    $array = array_values((array)$this->array);
574
575 1
    return static::create($array);
576
  }
577
578
  /**
579
   * Group values from a array according to the results of a closure.
580
   *
581
   * @param string $grouper a callable function name
582
   * @param bool   $saveKeys
583
   *
584
   * @return Arrayy
585
   */
586 3
  public function group($grouper, $saveKeys = false)
587
  {
588 3
    $array = (array)$this->array;
589 3
    $result = array();
590
591
    // Iterate over values, group by property/results from closure
592 3
    foreach ($array as $key => $value) {
593 3
      $groupKey = is_callable($grouper) ? $grouper($value, $key) : $this->get($grouper, null, $value);
594 3
      $newValue = $this->get($groupKey, null, $result);
595
596
      // Add to results
597 3
      if ($groupKey !== null) {
598 2
        if ($saveKeys) {
599 1
          $result[$groupKey] = $newValue;
600 1
          $result[$groupKey][$key] = $value;
601 1
        } else {
602 1
          $result[$groupKey] = $newValue;
603 1
          $result[$groupKey][] = $value;
604
        }
605 2
      }
606
607 3
    }
608
609 3
    return static::create($result);
610
  }
611
612
  /**
613
   * Given a list and an iterate-function that returns
614
   * a key for each element in the list (or a property name),
615
   * returns an object with an index of each item.
616
   *
617
   * Just like groupBy, but for when you know your keys are unique.
618
   *
619
   * @param mixed $key
620
   *
621
   * @return Arrayy
622
   */
623 3
  public function indexBy($key)
624
  {
625 3
    $results = array();
626
627 3
    foreach ($this->array as $a) {
628 3
      if (isset($a[$key])) {
629 2
        $results[$a[$key]] = $a;
630 2
      }
631 3
    }
632
633 3
    return static::create($results);
634
  }
635
636
  /**
637
   * magic to string
638
   *
639
   * @return string
640
   */
641 17
  public function __toString()
642
  {
643 17
    return $this->toString();
644
  }
645
646
  /**
647
   * Implodes array to a string with specified separator.
648
   *
649
   * @param string $separator The element's separator
650
   *
651
   * @return string The string representation of array, separated by ","
652
   */
653 17
  public function toString($separator = ',')
654
  {
655 17
    return $this->implode($separator);
656
  }
657
658
  /**
659
   * Implodes an array.
660
   *
661
   * @param string $with What to implode it with
662
   *
663
   * @return string
664
   */
665 25
  public function implode($with = '')
666
  {
667 25
    return implode($with, $this->array);
668
  }
669
670
  /**
671
   * Push one or more values onto the end of array at once.
672
   *
673
   * @return $this This Arrayy object with pushed elements to the end of array.
674
   */
675 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...
676
  {
677 4
    if (func_num_args()) {
678 4
      $args = array_merge(array(&$this->array), func_get_args());
679 4
      call_user_func_array('array_push', $args);
680 4
    }
681
682 4
    return $this;
683
  }
684
685
  /**
686
   * Shifts a specified value off the beginning of array.
687
   *
688
   * @return mixed A shifted element from the current array.
689
   */
690 4
  public function shift()
691
  {
692 4
    return array_shift($this->array);
693
  }
694
695
  /**
696
   * Prepends one or more values to the beginning of array at once.
697
   *
698
   * @return $this This Arrayy object with prepended elements to the beginning of array.
699
   */
700 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...
701
  {
702 4
    if (func_num_args()) {
703 4
      $args = array_merge(array(&$this->array), func_get_args());
704 4
      call_user_func_array('array_unshift', $args);
705 4
    }
706
707 4
    return $this;
708
  }
709
710
  /**
711
   * Get a value by key.
712
   *
713
   * @param $key
714
   *
715
   * @return mixed
716
   */
717
  public function &__get($key)
718
  {
719
    return $this->array[$key];
720
  }
721
722
  /**
723
   * Assigns a value to the specified element.
724
   *
725
   * @param $key
726
   * @param $value
727
   */
728
  public function __set($key, $value)
729
  {
730
    $this->array[$key] = $value;
731
  }
732
733
  /**
734
   * Whether or not an element exists by key.
735
   *
736
   * @param $key
737
   *
738
   * @return bool
739
   */
740
  public function __isset($key)
741
  {
742
    return isset($this->array[$key]);
743
  }
744
745
  /**
746
   * Unset element by key
747
   *
748
   * @param mixed $key
749
   */
750
  public function __unset($key)
751
  {
752
    unset($this->array[$key]);
753
  }
754
  /**
755
   * Call object as function.
756
   *
757
   * @param mixed $key
758
   *
759
   * @return mixed
760
   */
761
  public function __invoke($key = null)
762
  {
763
    if ($key !== null) {
764
      if (isset($this->array[$key])) {
765
        return $this->array[$key];
766
      } else {
767
        return false;
768
      }
769
    }
770
771
    return (array)$this->array;
772
  }/**
773
   * Whether or not an offset exists.
774
   *
775
   * @param mixed $offset
776
   *
777
   * @return bool
778
   */
779 27
  public function offsetExists($offset)
780
  {
781 27
    return isset($this->array[$offset]);
782
  }
783
784
  /**
785
   * Search for the value of the current array via $index.
786
   *
787
   * @param mixed $index
788
   *
789
   * @return Arrayy will return a empty Arrayy if the value wasn't found
790
   */
791 7
  public function searchValue($index)
792
  {
793
    // init
794 7
    $return = array();
795
796 7
    if (null !== $index) {
797 7
      $keyExists = isset($this->array[$index]);
798
799 7
      if ($keyExists !== false) {
800 5
        $return = array($this->array[$index]);
801 5
      }
802 7
    }
803
804 7
    return static::create($return);
805
  }
806
807
  /**
808
   * Check if all items in current array match a truth test.
809
   *
810
   * @param \Closure $closure
811
   *
812
   * @return bool
813
   */
814 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...
815
  {
816
    // Reduce the array to only booleans
817 9
    $array = $this->each($closure);
818
819
    // Check the results
820 9
    if (count($array) === 0) {
821 2
      return true;
822
    }
823
824 7
    $array = array_search(false, $array->toArray(), false);
825
826 7
    return is_bool($array);
827
  }
828
829
  /**
830
   * Iterate over the current array and modify the array's value.
831
   *
832
   * @param \Closure $closure
833
   *
834
   * @return Arrayy
835
   */
836 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...
837
  {
838 22
    $array = $this->array;
839
840 22
    foreach ($array as $key => &$value) {
841 18
      $value = $closure($value, $key);
842 22
    }
843
844 22
    return static::create($array);
845
  }
846
847
  /**
848
   * alias: for "Arrayy->getArray()"
849
   */
850 153
  public function toArray()
851
  {
852 153
    return $this->getArray();
853
  }
854
855
  /**
856
   * Check if any item in the current array matches a truth test.
857
   *
858
   * @param \Closure $closure
859
   *
860
   * @return bool
861
   */
862 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...
863
  {
864
    // Reduce the array to only booleans
865 9
    $array = $this->each($closure);
866
867
    // Check the results
868 9
    if (count($array) === 0) {
869 2
      return true;
870
    }
871
872 7
    $array = array_search(true, $array->toArray(), false);
873
874 7
    return is_int($array);
875
  }
876
877
  /**
878
   * Check whether array is associative or not.
879
   *
880
   * @return bool Returns true if associative, false otherwise
881
   */
882 14
  public function isAssoc()
883
  {
884 14
    if ($this->isEmpty()) {
885 2
      return false;
886
    }
887
888 12
    foreach ($this->getKeys()->getArray() as $key) {
889 12
      if (!is_string($key)) {
890 10
        return false;
891
      }
892 2
    }
893
894 2
    return true;
895
  }
896
897
  /**
898
   * Check whether the array is empty or not.
899
   *
900
   * @return bool Returns true if empty, false otherwise
901
   */
902 22
  public function isEmpty()
903
  {
904 22
    return !$this->array;
905
  }
906
907
/**
908
   * alias: for "Arrayy->keys()"
909
   *
910
   * @return Arrayy
911
   */
912 15
  public function getKeys()
913
  {
914 15
    return $this->keys();
915
  }
916
917
    /**
918
   * Get all keys from the current array.
919
   *
920
   * @return Arrayy
921
   */
922 20
  public function keys()
923
  {
924 20
    $array = array_keys((array)$this->array);
925
926 20
    return static::create($array);
927
  }
928
  /**
929
   * Check whether array is numeric or not.
930
   *
931
   * @return bool Returns true if numeric, false otherwise
932
   */
933 4
  public function isNumeric()
934
  {
935 4
    if ($this->isEmpty()) {
936 1
      return false;
937
    }
938
939 3
    foreach ($this->getKeys() as $key) {
940 3
      if (!is_int($key)) {
941 2
        return false;
942
      }
943 2
    }
944
945 1
    return true;
946
  }/**
947
   * Unset an offset.
948
   *
949
   * @param mixed $offset
950
   */
951 5
  public function offsetUnset($offset)
952
  {
953 5
    if ($this->offsetExists($offset)) {
954 3
      unset($this->array[$offset]);
955 3
    }
956 5
  }
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 5
  public function containsKey($key)
988
  {
989 5
    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 3
    }
1010
1011 8
    return round(array_sum($this->array) / $count, $decimals);
1012
  }
1013
1014
  /**
1015
   * Count the values from the current array.
1016
   *
1017
   * INFO: only a alias for "$arrayy->size()"
1018
   *
1019
   * @return int
1020
   */
1021 10
  public function length()
1022
  {
1023 10
    return $this->size();
1024
  }
1025
1026
  /**
1027
   * Get the max value from an array.
1028
   *
1029
   * @return mixed
1030
   */
1031 10
  public function max()
1032
  {
1033 10
    if ($this->count() === 0) {
1034 1
      return false;
1035
    }
1036
1037 9
    return max($this->array);
1038
  }
1039
1040
/**
1041
   * Get the min value from an array.
1042
   *
1043
   * @return mixed
1044
   */
1045 10
  public function min()
1046
  {
1047 10
    if ($this->count() === 0) {
1048 1
      return false;
1049
    }
1050
1051 9
    return min($this->array);
1052
  }
1053
1054
  /**
1055
   * Find the first item in an array that passes the truth test,
1056
   *  otherwise return false
1057
   *
1058
   * @param \Closure $closure
1059
   *
1060
   * @return mixed|false false if we did not find the value
1061
   */
1062 8
  public function find(\Closure $closure)
1063
  {
1064 8
    foreach ($this->array as $key => $value) {
1065 6
      if ($closure($value, $key)) {
1066 5
        return $value;
1067
      }
1068 5
    }
1069
1070 3
    return false;
1071
  }
1072
1073
    /**
1074
   * WARNING!!! -> Clear the current array.
1075
   *
1076
   * @return $this This will always return an empty Arrayy object.
1077
   */
1078 4
  public function clear()
1079
  {
1080 4
    $this->array = array();
1081
1082 4
    return $this;
1083
  }
1084
  /**
1085
   * Clean all falsy values from an array.
1086
   *
1087
   * @return Arrayy
1088
   */
1089 8
  public function clean()
1090
  {
1091 8
    return $this->filter(
1092
        function ($value) {
1093 7
          return (bool)$value;
1094
        }
1095 8
    );
1096
  }/**
1097
   * Returns the value at specified offset.
1098
   *
1099
   * @param mixed $offset
1100
   *
1101
   * @return mixed return null if the offset did not exists
1102
   */
1103 18
  public function offsetGet($offset)
1104
  {
1105 18
    return $this->offsetExists($offset) ? $this->array[$offset] : null;
1106
  }
1107
1108
  /**
1109
   * Find all items in an array that pass the truth test.
1110
   *
1111
   * @param \Closure|null $closure
1112
   *
1113
   * @return Arrayy
1114
   */
1115 8
  public function filter($closure = null)
1116
  {
1117 8
    if (!$closure) {
1118 1
      return $this->clean();
1119
    }
1120
1121 8
    $array = array_filter($this->array, $closure);
1122
1123 8
    return static::create($array);
1124
  }
1125
1126
  /**
1127
   * Get a random value from an array, with the ability to skew the results.
1128
   *
1129
   * Example: randomWeighted(['foo' => 1, 'bar' => 2]) has a 66% chance of returning bar.
1130
   *
1131
   * @param array    $array
1132
   * @param null|int $number how many values you will take?
1133
   *
1134
   * @return Arrayy
1135
   */
1136 9
  public function randomWeighted(array $array, $number = null)
1137
  {
1138 9
    $options = array();
1139 9
    foreach ($array as $option => $weight) {
1140 9
      if ($this->searchIndex($option) !== false) {
1141 2
        for ($i = 0; $i < $weight; ++$i) {
1142 1
          $options[] = $option;
1143 1
        }
1144 2
      }
1145 9
    }
1146
1147 9
    return $this->mergeAppendKeepIndex($options)->random($number);
1148
  }
1149
1150
  /**
1151
   * Search for the first index of the current array via $value.
1152
   *
1153
   * @param mixed $value
1154
   *
1155
   * @return mixed
1156
   */
1157 20
  public function searchIndex($value)
1158
  {
1159 20
    return array_search($value, $this->array, true);
1160
  }
1161
1162
  /**
1163
   * Merge the new $array into the current array.
1164
   *
1165
   * - keep key,value from the current array, also if the index is in the new $array
1166
   *
1167
   * @param array $array
1168
   * @param bool  $recursive
1169
   *
1170
   * @return Arrayy
1171
   */
1172 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...
1173
  {
1174 25
    if (true === $recursive) {
1175 4
      $result = array_replace_recursive($this->array, $array);
1176 4
    } else {
1177 21
      $result = array_replace($this->array, $array);
1178
    }
1179
1180 25
    return static::create($result);
1181
  }
1182
1183
  /**
1184
   * alias: for "Arrayy->searchIndex()"
1185
   *
1186
   * @param mixed $value Value to search for
1187
   *
1188
   * @return mixed
1189
   */
1190 4
  public function indexOf($value)
1191
  {
1192 4
    return $this->searchIndex($value);
1193
  }
1194
1195
/**
1196
   * Return a boolean flag which indicates whether the two input arrays have any common elements.
1197
   *
1198
   * @param array $search
1199
   *
1200
   * @return bool
1201
   */
1202 1
  public function intersects(array $search)
1203
  {
1204 1
    return count($this->intersection($search)->array) > 0;
1205
  }
1206
1207
  /**
1208
   * Return an array with all elements found in input array.
1209
   *
1210
   * @param array $search
1211
   *
1212
   * @return Arrayy
1213
   */
1214 2
  public function intersection(array $search)
1215
  {
1216 2
    $result = array_values(array_intersect($this->array, $search));
1217
1218 2
    return static::create($result);
1219
  }
1220
1221
  /**
1222
   * Get the last value from the current array.
1223
   *
1224
   * @return mixed return null if there wasn't a element.
1225
   */
1226 4
  public function last()
1227
  {
1228 4
    $result = $this->pop();
1229
1230 4
    if (null === $result) {
1231 1
      return false;
1232
    } else {
1233 3
      return $result;
1234
    }
1235
  }
1236
1237
  /**
1238
   * Get the last value(s) from the current array.
1239
   *
1240
   * @param int|null $number
1241
   *
1242
   * @return Arrayy
1243
   */
1244 11
  public function lasts($number = null)
1245
  {
1246 11
    if ($number === null) {
1247 7
      $poppedValue = (array)$this->pop();
1248 7
      $arrayy = static::create($poppedValue);
1249 7
    } else {
1250 4
      $number = (int)$number;
1251 4
      $arrayy = $this->rest(-$number);
1252
    }
1253
1254 11
    return $arrayy;
1255
  }
1256
1257
    /**
1258
   * Pop a specified value off the end of the current array.
1259
   *
1260
   * @return mixed The popped element from the current array.
1261
   */
1262 15
  public function pop()
1263
  {
1264 15
    return array_pop($this->array);
1265
  }
1266
  /**
1267
   * Get the last elements from index $from until the end of this array.
1268
   *
1269
   * @param int $from
1270
   *
1271
   * @return Arrayy
1272
   */
1273 16
  public function rest($from = 1)
1274
  {
1275 16
    $result = array_splice($this->array, $from);
1276
1277 16
    return static::create($result);
1278
  }/**
1279
   * Returns a new ArrayIterator, thus implementing the IteratorAggregate interface.
1280
   *
1281
   * @return \ArrayIterator An iterator for the values in the array.
1282
   */
1283 16
  public function getIterator()
1284
  {
1285 16
    return new \ArrayIterator($this->array);
1286
  }
1287
1288
  /**
1289
   * Get everything but the last..$to items.
1290
   *
1291
   * @param int $to
1292
   *
1293
   * @return Arrayy
1294
   */
1295 12
  public function initial($to = 1)
1296
  {
1297 12
    $slice = count($this->array) - $to;
1298
1299 12
    return $this->first($slice);
1300
  }
1301
1302
  /**
1303
   * Extract a slice of the array.
1304
   *
1305
   * @param int      $offset       Slice begin index
1306
   * @param int|null $length       Length of the slice
1307
   * @param bool     $preserveKeys Whether array keys are preserved or no
1308
   *
1309
   * @return static A slice of the original array with length $length
1310
   */
1311 4
  public function slice($offset, $length = null, $preserveKeys = false)
1312
  {
1313 4
    $result = array_slice($this->array, $offset, $length, $preserveKeys);
1314
1315 4
    return static::create($result);
1316
  }
1317
1318
  /**
1319
   * Iterate over an array and execute a callback for each loop.
1320
   *
1321
   * @param \Closure $closure
1322
   *
1323
   * @return Arrayy
1324
   */
1325 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...
1326
  {
1327 2
    $array = $this->array;
1328
1329 2
    foreach ($array as $key => $value) {
1330 2
      $closure($value, $key);
1331 2
    }
1332
1333 2
    return static::create($array);
1334
  }
1335
1336
  /**
1337
   * Merge the new $array into the current array.
1338
   *
1339
   * - replace duplicate assoc-keys from the current array with the key,values from the new $array
1340
   * - create new indexes
1341
   *
1342
   * @param array $array
1343
   * @param bool  $recursive
1344
   *
1345
   * @return Arrayy
1346
   */
1347 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...
1348
  {
1349 16
    if (true === $recursive) {
1350 4
      $result = array_merge_recursive($this->array, $array);
1351 4
    } else {
1352 12
      $result = array_merge($this->array, $array);
1353
    }
1354
1355 16
    return static::create($result);
1356
  }
1357
1358
  /**
1359
   * Merge the current array into the new $array.
1360
   *
1361
   * - replace duplicate assoc-keys from new $array with the key,values from the current array
1362
   * - create new indexes
1363
   *
1364
   * @param array $array
1365
   * @param bool  $recursive
1366
   *
1367
   * @return Arrayy
1368
   */
1369 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...
1370
  {
1371 16
    if (true === $recursive) {
1372 4
      $result = array_merge_recursive($array, $this->array);
1373 4
    } else {
1374 12
      $result = array_merge($array, $this->array);
1375
    }
1376
1377 16
    return static::create($result);
1378
  }
1379
1380
  /**
1381
   * Merge the the current array into the $array.
1382
   *
1383
   * - use key,value from the new $array, also if the index is in the current array
1384
   *
1385
   * @param array $array
1386
   * @param bool  $recursive
1387
   *
1388
   * @return Arrayy
1389
   */
1390 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...
1391
  {
1392 16
    if (true === $recursive) {
1393 4
      $result = array_replace_recursive($array, $this->array);
1394 4
    } else {
1395 12
      $result = array_replace($array, $this->array);
1396
    }
1397
1398 16
    return static::create($result);
1399
  }
1400
1401
  /**
1402
   * Return values that are only in the current array.
1403
   *
1404
   * @param array $array
1405
   *
1406
   * @return Arrayy
1407
   */
1408 12
  public function diff(array $array = array())
1409
  {
1410 12
    $result = array_diff($this->array, $array);
1411
1412 12
    return static::create($result);
1413
  }
1414
1415
  /**
1416
   * Return values that are only in the new $array.
1417
   *
1418
   * @param array $array
1419
   *
1420
   * @return Arrayy
1421
   */
1422 8
  public function diffReverse(array $array = array())
1423
  {
1424 8
    $result = array_diff($array, $this->array);
1425
1426 8
    return static::create($result);
1427
  }
1428
1429
  /**
1430
   * Replace the first matched value in an array.
1431
   *
1432
   * @param mixed $search
1433
   * @param mixed $replacement
1434
   *
1435
   * @return Arrayy
1436
   */
1437 3
  public function replaceOneValue($search, $replacement = '')
1438
  {
1439 3
    $array = $this->array;
1440 3
    $key = array_search($search, $array, true);
1441
1442 3
    if ($key !== false) {
1443 3
      $array[$key] = $replacement;
1444 3
    }
1445
1446 3
    return static::create($array);
1447
  }
1448
1449
  /**
1450
   * Replace values in the current array.
1451
   *
1452
   * @param string $search      The string to replace.
1453
   * @param string $replacement What to replace it with.
1454
   *
1455
   * @return Arrayy
1456
   */
1457 1
  public function replaceValues($search, $replacement = '')
1458
  {
1459 1
    $array = $this->each(
1460
        function ($value) use ($search, $replacement) {
1461 1
          return UTF8::str_replace($search, $replacement, $value);
1462
        }
1463 1
    );
1464
1465 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...
1466
  }
1467
1468
  /**
1469
   * Replace the keys in an array with another set.
1470
   *
1471
   * @param array $keys An array of keys matching the array's size
1472
   *
1473
   * @return Arrayy
1474
   */
1475 1
  public function replaceKeys(array $keys)
1476
  {
1477 1
    $values = array_values($this->array);
1478 1
    $result = array_combine($keys, $values);
1479
1480 1
    return static::create($result);
1481
  }
1482
1483
  /**
1484
   * Create an array using the current array as keys and the other array as values.
1485
   *
1486
   * @param array $array Values array
1487
   *
1488
   * @return Arrayy Arrayy object with values from the other array.
1489
   */
1490 1
  public function replaceAllValues(array $array)
1491
  {
1492 1
    $result = array_combine($this->array, $array);
1493
1494 1
    return static::create($result);
1495
  }
1496
1497
  /**
1498
   * Create an array using the current array as values and the other array as keys.
1499
   *
1500
   * @param array $keys Keys array
1501
   *
1502
   * @return Arrayy Arrayy object with keys from the other array.
1503
   */
1504 1
  public function replaceAllKeys(array $keys)
1505
  {
1506 1
    $result = array_combine($keys, $this->array);
1507
1508 1
    return static::create($result);
1509
  }
1510
1511
  /**
1512
   * Shuffle the current array.
1513
   *
1514
   * @return Arrayy
1515
   */
1516 1
  public function shuffle()
1517
  {
1518 1
    $array = $this->array;
1519
1520 1
    shuffle($array);
1521
1522 1
    return static::create($array);
1523
  }
1524
1525
  /**
1526
   * Split an array in the given amount of pieces.
1527
   *
1528
   * @param int  $numberOfPieces
1529
   * @param bool $keepKeys
1530
   *
1531
   * @return array
1532
   */
1533 1
  public function split($numberOfPieces = 2, $keepKeys = false)
1534
  {
1535 1
    if (count($this->array) === 0) {
1536 1
      $result = array();
1537 1
    } else {
1538 1
      $numberOfPieces = (int)$numberOfPieces;
1539 1
      $splitSize = ceil(count($this->array) / $numberOfPieces);
1540 1
      $result = array_chunk($this->array, $splitSize, $keepKeys);
1541
    }
1542
1543 1
    return static::create($result);
1544
  }
1545
1546
  /**
1547
   * Create a chunked version of this array.
1548
   *
1549
   * @param int  $size         Size of each chunk
1550
   * @param bool $preserveKeys Whether array keys are preserved or no
1551
   *
1552
   * @return static A new array of chunks from the original array
1553
   */
1554 4
  public function chunk($size, $preserveKeys = false)
1555
  {
1556 4
    $result = array_chunk($this->array, $size, $preserveKeys);
1557
1558 4
    return static::create($result);
1559
  }
1560
1561
  /**
1562
   * Returns the values from a single column of the input array, identified by
1563
   * the $columnKey, can be used to extract data-columns from multi-arrays.
1564
   *
1565
   * Info: Optionally, you may provide an $indexKey to index the values in the returned
1566
   * array by the values from the $indexKey column in the input array.
1567
   *
1568
   * @param mixed $columnKey
1569
   * @param mixed $indexKey
1570
   *
1571
   * @return Arrayy
1572
   */
1573 1
  public function getColumn($columnKey = null, $indexKey = null)
1574
  {
1575 1
    $result = array_column($this->array, $columnKey, $indexKey);
1576
1577 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 1575 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...
1578
  }
1579
1580
  /**
1581
   * Invoke a function on all of an array's values.
1582
   *
1583
   * @param mixed $callable
1584
   * @param array $arguments
1585
   *
1586
   * @return Arrayy
1587
   */
1588 1
  public function invoke($callable, $arguments = array())
1589
  {
1590
    // If one argument given for each iteration, create an array for it.
1591 1
    if (!is_array($arguments)) {
1592 1
      $arguments = StaticArrayy::repeat($arguments, count($this->array))->getArray();
1593 1
    }
1594
1595
    // If the callable has arguments, pass them.
1596 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...
1597 1
      $array = array_map($callable, $this->array, $arguments);
1598 1
    } else {
1599 1
      $array = array_map($callable, $this->array);
1600
    }
1601
1602 1
    return static::create($array);
1603
  }
1604
1605
  /**
1606
   * Apply the given function to the every element of the array,
1607
   * collecting the results.
1608
   *
1609
   * @param callable $callable
1610
   *
1611
   * @return Arrayy Arrayy object with modified elements
1612
   */
1613 4
  public function map($callable)
1614
  {
1615 4
    $result = array_map($callable, $this->array);
1616
1617 4
    return static::create($result);
1618
  }
1619
1620
  /**
1621
   * Check if a value is in the current array using a closure.
1622
   *
1623
   * @param \Closure $closure
1624
   *
1625
   * @return bool Returns true if the given value is found, false otherwise
1626
   */
1627 4
  public function exists(\Closure $closure)
1628
  {
1629 4
    $isExists = false;
1630 4
    foreach ($this->array as $key => $value) {
1631 3
      if ($closure($value, $key)) {
1632 1
        $isExists = true;
1633 1
        break;
1634
      }
1635 4
    }
1636
1637 4
    return $isExists;
1638
  }
1639
1640
  /**
1641
   * Return all items that fail the truth test.
1642
   *
1643
   * @param \Closure $closure
1644
   *
1645
   * @return Arrayy
1646
   */
1647 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...
1648
  {
1649 1
    $filtered = array();
1650
1651 1
    foreach ($this->array as $key => $value) {
1652 1
      if (!$closure($value, $key)) {
1653 1
        $filtered[$key] = $value;
1654 1
      }
1655 1
    }
1656
1657 1
    return static::create($filtered);
1658
  }
1659
1660
  /**
1661
   * Replace a key with a new key/value pair.
1662
   *
1663
   * @param $replace
1664
   * @param $key
1665
   * @param $value
1666
   *
1667
   * @return Arrayy
1668
   */
1669 1
  public function replace($replace, $key, $value)
1670
  {
1671 1
    $this->remove($replace);
1672
1673 1
    return $this->set($key, $value);
1674
  }
1675
1676
  /**
1677
   * Remove a value from the current array (optional using dot-notation).
1678
   *
1679
   * @param mixed $key
1680
   *
1681
   * @return Arrayy
1682
   */
1683 17
  public function remove($key)
1684
  {
1685
    // Recursive call
1686 17
    if (is_array($key)) {
1687
      foreach ($key as $k) {
1688
        $this->internalRemove($k);
1689
      }
1690
1691
      return static::create($this->array);
1692
    }
1693
1694 17
    $this->internalRemove($key);
1695
1696 17
    return static::create($this->array);
1697
  }
1698
1699
  /**
1700
   * Internal mechanics of remove method.
1701
   *
1702
   * @param $key
1703
   *
1704
   * @return boolean
1705
   */
1706 17
  protected function internalRemove($key)
1707
  {
1708
    // Explode keys
1709 17
    $keys = explode('.', $key);
1710
1711
    // Crawl though the keys
1712 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...
1713
      $key = array_shift($keys);
1714
1715
      if (!$this->has($key)) {
1716
        return false;
1717
      }
1718
1719
      $this->array = &$this->array[$key];
1720
    }
1721
1722 17
    $key = array_shift($keys);
1723
1724 17
    unset($this->array[$key]);
1725
1726 17
    return true;
1727
  }
1728
1729
  /**
1730
   * Check if an array has a given key.
1731
   *
1732
   * @param mixed $key
1733
   *
1734
   * @return bool
1735
   */
1736 18
  public function has($key)
1737
  {
1738
    // Generate unique string to use as marker.
1739 18
    $unFound = (string)uniqid('arrayy', true);
1740
1741 18
    return $this->get($key, $unFound) !== $unFound;
1742
  }
1743
1744
  /**
1745
   * Set a value for the current array (optional using dot-notation).
1746
   *
1747
   * @param string $key   The key to set
1748
   * @param mixed  $value Its value
1749
   *
1750
   * @return Arrayy
1751
   */
1752 14
  public function set($key, $value)
1753
  {
1754 14
    $this->internalSet($key, $value);
1755
1756 14
    return static::create($this->array);
1757
  }
1758
1759
  /**
1760
   * Internal mechanic of set method.
1761
   *
1762
   * @param mixed $key
1763
   * @param mixed $value
1764
   *
1765
   * @return bool
1766
   */
1767 14
  protected function internalSet($key, $value)
1768
  {
1769 14
    if (null === $key) {
1770
      return false;
1771
    }
1772
1773
    // Explode the keys
1774 14
    $keys = explode('.', $key);
1775
1776
    // Crawl through the keys
1777 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...
1778
      $key = array_shift($keys);
1779
1780
      $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...
1781
      $this->array = &$this->array[$key];
1782
    }
1783
1784
    // Bind final tree on the array
1785 14
    $key = array_shift($keys);
1786
1787 14
    $this->array[$key] = $value;
1788
1789 14
    return true;
1790
  }
1791
1792
  /**
1793
   * Get a value from a array and set it if it was not.
1794
   *
1795
   * WARNING: this method only set the value, if the $key is not already set
1796
   *
1797
   * @param string $key     The key
1798
   * @param mixed  $default The default value to set if it isn't
1799
   *
1800
   * @return mixed
1801
   */
1802 9
  public function setAndGet($key, $default = null)
1803
  {
1804
    // If the key doesn't exist, set it
1805 9
    if (!$this->has($key)) {
1806 4
      $this->array = $this->set($key, $default)->getArray();
1807 4
    }
1808
1809 9
    return $this->get($key);
1810
  }
1811
1812
  /**
1813
   * Remove the first value from the current array.
1814
   *
1815
   * @return Arrayy
1816
   */
1817 7
  public function removeFirst()
1818
  {
1819 7
    array_shift($this->array);
1820
1821 7
    return static::create($this->array);
1822
  }
1823
1824
  /**
1825
   * Remove the last value from the current array.
1826
   *
1827
   * @return Arrayy
1828
   */
1829 7
  public function removeLast()
1830
  {
1831 7
    array_pop($this->array);
1832
1833 7
    return static::create($this->array);
1834
  }
1835
1836
  /**
1837
   * Removes a particular value from an array (numeric or associative).
1838
   *
1839
   * @param mixed $value
1840
   *
1841
   * @return Arrayy
1842
   */
1843 7
  public function removeValue($value)
1844
  {
1845 7
    $isNumericArray = true;
1846 7
    foreach ($this->array as $key => $item) {
1847 6
      if ($item === $value) {
1848 6
        if (!is_int($key)) {
1849
          $isNumericArray = false;
1850
        }
1851 6
        unset($this->array[$key]);
1852 6
      }
1853 7
    }
1854
1855 7
    if ($isNumericArray) {
1856 7
      $this->array = array_values($this->array);
1857 7
    }
1858
1859 7
    return static::create($this->array);
1860
  }
1861
1862
  /**
1863
   * Pad array to the specified size with a given value.
1864
   *
1865
   * @param int   $size  Size of the result array
1866
   * @param mixed $value Empty value by default
1867
   *
1868
   * @return Arrayy Arrayy object padded to $size with $value
1869
   */
1870 4
  public function pad($size, $value)
1871
  {
1872 4
    $result = array_pad($this->array, $size, $value);
1873
1874 4
    return static::create($result);
1875
  }
1876
1877
  /**
1878
   * Prepend a value to an array.
1879
   *
1880
   * @param mixed $value
1881
   *
1882
   * @return $this This Arrayy object with the prepended value.
1883
   */
1884 7
  public function prepend($value)
1885
  {
1886 7
    array_unshift($this->array, $value);
1887
1888 7
    return $this;
1889
  }
1890
1891
  /**
1892
   * alias: for "Arrayy->append()"
1893
   *
1894
   * @param $value
1895
   *
1896
   * @return $this
1897
   */
1898 1
  public function add($value)
1899
  {
1900 1
    $this->array[] = $value;
1901
1902 1
    return $this;
1903
  }
1904
1905
  /**
1906
   * Create a numerically re-indexed Arrayy object.
1907
   *
1908
   * @return Arrayy The new instance with re-indexed array-elements
1909
   */
1910 8
  public function reindex()
1911
  {
1912 8
    $this->array = array_values($this->array);
1913
1914 8
    return static::create($this->array);
1915
  }
1916
1917
  /**
1918
   * Return the array in the reverse order.
1919
   *
1920
   * @return Arrayy
1921
   */
1922 7
  public function reverse()
1923
  {
1924 7
    $this->array = array_reverse($this->array);
1925
1926 7
    return static::create($this->array);
1927
  }
1928
1929
  /**
1930
   * Custom sort by value via "usort"
1931
   *
1932
   * @link http://php.net/manual/en/function.usort.php
1933
   *
1934
   * @param callable $func
1935
   *
1936
   * @return $this
1937
   */
1938 4
  public function customSortValues($func)
1939
  {
1940 4
    usort($this->array, $func);
1941
1942 4
    return $this;
1943
  }
1944
1945
  /**
1946
   * Custom sort by index via "uksort"
1947
   *
1948
   * @link http://php.net/manual/en/function.uksort.php
1949
   *
1950
   * @param callable $func
1951
   *
1952
   * @return $this
1953
   */
1954 4
  public function customSortKeys($func)
1955
  {
1956 4
    uksort($this->array, $func);
1957
1958 4
    return $this;
1959
  }
1960
1961
  /**
1962
   * Sort the current array by key.
1963
   *
1964
   * @link http://php.net/manual/en/function.ksort.php
1965
   * @link http://php.net/manual/en/function.krsort.php
1966
   *
1967
   * @param int|string $direction use SORT_ASC or SORT_DESC
1968
   * @param int        $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
1969
   *
1970
   * @return $this
1971
   */
1972 18
  public function sortKeys($direction = SORT_ASC, $strategy = SORT_REGULAR)
1973
  {
1974 18
    $this->sorterKeys($this->array, $direction, $strategy);
1975
1976 18
    return $this;
1977
  }
1978
1979
  /**
1980
   * sorting keys
1981
   *
1982
   * @param array $elements
1983
   * @param int   $direction
1984
   * @param int   $strategy
1985
   */
1986 18
  protected function sorterKeys(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR)
1987
  {
1988 18
    $direction = $this->getDirection($direction);
1989
1990
    switch ($direction) {
1991 18
      case 'desc':
1992 18
      case SORT_DESC:
1993 6
        krsort($elements, $strategy);
1994 6
        break;
1995 13
      case 'asc':
1996 13
      case SORT_ASC:
1997 13
      default:
1998 13
        ksort($elements, $strategy);
1999 13
    }
2000 18
  }
2001
2002
  /**
2003
   * Get correct PHP constant for direction.
2004
   *
2005
   * @param int|string $direction
2006
   *
2007
   * @return int
2008
   */
2009 38
  protected function getDirection($direction)
2010
  {
2011 38
    if (is_string($direction)) {
2012 10
      $direction = strtolower($direction);
2013
2014 10
      if ($direction === 'desc') {
2015 2
        $direction = SORT_DESC;
2016 2
      } else {
2017 8
        $direction = SORT_ASC;
2018
      }
2019 10
    }
2020
2021
    if (
2022
        $direction !== SORT_DESC
2023 38
        &&
2024
        $direction !== SORT_ASC
2025 38
    ) {
2026
      $direction = SORT_ASC;
2027
    }
2028
2029 38
    return $direction;
2030
  }
2031
2032
  /**
2033
   * Sort the current array by value.
2034
   *
2035
   * @param int $direction use SORT_ASC or SORT_DESC
2036
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2037
   *
2038
   * @return Arrayy
2039
   */
2040 1
  public function sortValueKeepIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2041
  {
2042 1
    return $this->sort($direction, $strategy, true);
2043
  }
2044
2045
  /**
2046
   * Sort the current array and optional you can keep the keys.
2047
   *
2048
   * @param string|int $direction use SORT_ASC or SORT_DESC
2049
   * @param int|string $strategy
2050
   * @param bool       $keepKeys
2051
   *
2052
   * @return $this
2053
   */
2054 19
  public function sort($direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2055
  {
2056 19
    $this->sorting($this->array, $direction, $strategy, $keepKeys);
2057
2058 19
    return $this;
2059
  }
2060
2061
  /**
2062
   * @param array      &$elements
2063
   * @param int|string $direction
2064
   * @param int        $strategy
2065
   * @param bool       $keepKeys
2066
   */
2067 19
  protected function sorting(array &$elements, $direction = SORT_ASC, $strategy = SORT_REGULAR, $keepKeys = false)
2068
  {
2069 19
    $direction = $this->getDirection($direction);
2070
2071 19
    if (!$strategy) {
2072 19
      $strategy = SORT_REGULAR;
2073 19
    }
2074
2075
    switch ($direction) {
2076 19
      case 'desc':
2077 19
      case SORT_DESC:
2078 9
        if ($keepKeys) {
2079 5
          arsort($elements, $strategy);
2080 5
        } else {
2081 4
          rsort($elements, $strategy);
2082
        }
2083 9
        break;
2084 10
      case 'asc':
2085 10
      case SORT_ASC:
2086 10
      default:
2087 10
        if ($keepKeys) {
2088 4
          asort($elements, $strategy);
2089 4
        } else {
2090 6
          sort($elements, $strategy);
2091
        }
2092 10
    }
2093 19
  }
2094
2095
  /**
2096
   * Sort the current array by value.
2097
   *
2098
   * @param int $direction use SORT_ASC or SORT_DESC
2099
   * @param int $strategy  use e.g.: SORT_REGULAR or SORT_NATURAL
2100
   *
2101
   * @return Arrayy
2102
   */
2103 1
  public function sortValueNewIndex($direction = SORT_ASC, $strategy = SORT_REGULAR)
2104
  {
2105 1
    return $this->sort($direction, $strategy, false);
2106
  }
2107
2108
  /**
2109
   * Sort a array by value, by a closure or by a property.
2110
   *
2111
   * - If the sorter is null, the array is sorted naturally.
2112
   * - Associative (string) keys will be maintained, but numeric keys will be re-indexed.
2113
   *
2114
   * @param null       $sorter
2115
   * @param string|int $direction
2116
   * @param int        $strategy
2117
   *
2118
   * @return Arrayy
2119
   */
2120 1
  public function sorter($sorter = null, $direction = SORT_ASC, $strategy = SORT_REGULAR)
2121
  {
2122 1
    $array = (array)$this->array;
2123 1
    $direction = $this->getDirection($direction);
2124
2125
    // Transform all values into their results.
2126 1
    if ($sorter) {
2127 1
      $arrayy = new self($array);
2128
2129 1
      $that = $this;
2130 1
      $results = $arrayy->each(
2131
          function ($value) use ($sorter, $that) {
2132 1
            return is_callable($sorter) ? $sorter($value) : $that->get($sorter, null, $value);
2133
          }
2134 1
      );
2135
2136 1
      $results = $results->getArray();
2137 1
    } else {
2138 1
      $results = $array;
2139
    }
2140
2141
    // Sort by the results and replace by original values
2142 1
    array_multisort($results, $direction, $strategy, $array);
2143
2144 1
    return static::create($array);
2145
  }
2146
2147
  /**
2148
   * Exchanges all keys with their associated values in an array.
2149
   *
2150
   * @return Arrayy
2151
   */
2152 1
  public function flip()
2153
  {
2154 1
    $this->array = array_flip($this->array);
2155
2156 1
    return static::create($this->array);
2157
  }
2158
2159
  /**
2160
   * Apply the given function to every element in the array,
2161
   * discarding the results.
2162
   *
2163
   * @param callable $callable
2164
   * @param bool     $recursive Whether array will be walked recursively or no
2165
   *
2166
   * @return $this This Arrayy object with modified elements
2167
   */
2168 8
  public function walk($callable, $recursive = false)
2169
  {
2170 8
    if (true === $recursive) {
2171 4
      array_walk_recursive($this->array, $callable);
2172 4
    } else {
2173 4
      array_walk($this->array, $callable);
2174
    }
2175
2176 8
    return $this;
2177
  }
2178
2179
  /**
2180
   * Reduce the current array via callable e.g. anonymous-function.
2181
   *
2182
   * @param mixed $callable
2183
   * @param array $init
2184
   *
2185
   * @return Arrayy
2186
   */
2187 2
  public function reduce($callable, array $init = array())
2188
  {
2189 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...
2190
2191 2
    return static::create($this->array);
2192
  }
2193
2194
  /**
2195
   * Return a duplicate free copy of the current array.
2196
   *
2197
   * @return Arrayy
2198
   */
2199 7
  public function unique()
2200
  {
2201 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...
2202 7
        $this->array,
2203 7
        function ($resultArray, $value) {
2204 6
          if (in_array($value, $resultArray, true) === false) {
2205 6
            $resultArray[] = $value;
2206 6
          }
2207
2208 6
          return $resultArray;
2209 7
        },
2210 7
        array()
2211 7
    );
2212
2213 7
    return static::create($this->array);
2214
  }
2215
2216
  /**
2217
   * Convert the current array to JSON.
2218
   *
2219
   * @param null $options e.g. JSON_PRETTY_PRINT
2220
   *
2221
   * @return string
2222
   */
2223 5
  public function toJson($options = null)
2224
  {
2225 5
    return UTF8::json_encode($this->array, $options);
2226
  }
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
}
2246