Completed
Push — master ( f12aa8...87c9d5 )
by Lars
02:31
created

Arrayy::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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