Completed
Push — master ( 4991a4...1ef3f4 )
by Lars
06:02 queued 03:28
created

Arrayy::implode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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