Completed
Push — master ( 0f3a61...213fa3 )
by Lars
02:57
created

Arrayy::set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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