]> _ Git - physioassist-wordpress.git/blob
2e9c7128097011724b2d5d2ae83d404576f9f055
[physioassist-wordpress.git] /
1 <?php
2
3 namespace WPML\Collect\Support;
4
5 use Countable;
6 use ArrayAccess;
7 use Traversable;
8 use ArrayIterator;
9 use CachingIterator;
10 use JsonSerializable;
11 use IteratorAggregate;
12 use InvalidArgumentException;
13 use WPML\Collect\Support\Traits\Macroable;
14 use WPML\Collect\Contracts\Support\Jsonable;
15 use WPML\Collect\Contracts\Support\Arrayable;
16
17 class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable
18 {
19     use Macroable;
20
21     /**
22      * The items contained in the collection.
23      *
24      * @var array
25      */
26     protected $items = [];
27
28     /**
29      * Create a new collection.
30      *
31      * @param  mixed  $items
32      * @return void
33      */
34     public function __construct($items = [])
35     {
36         $this->items = $this->getArrayableItems($items);
37     }
38
39     /**
40      * Create a new collection instance if the value isn't one already.
41      *
42      * @param  mixed  $items
43      * @return static
44      */
45     public static function make($items = [])
46     {
47         return new static($items);
48     }
49
50     /**
51      * Get all of the items in the collection.
52      *
53      * @return array
54      */
55     public function all()
56     {
57         return $this->items;
58     }
59
60     /**
61      * Get the average value of a given key.
62      *
63      * @param  callable|string|null  $callback
64      * @return mixed
65      */
66     public function avg($callback = null)
67     {
68         if ($count = $this->count()) {
69             return $this->sum($callback) / $count;
70         }
71     }
72
73     /**
74      * Alias for the "avg" method.
75      *
76      * @param  callable|string|null  $callback
77      * @return mixed
78      */
79     public function average($callback = null)
80     {
81         return $this->avg($callback);
82     }
83
84     /**
85      * Get the median of a given key.
86      *
87      * @param  null $key
88      * @return mixed|null
89      */
90     public function median($key = null)
91     {
92         $count = $this->count();
93
94         if ($count == 0) {
95             return;
96         }
97
98         $values = with(isset($key) ? $this->pluck($key) : $this)
99                     ->sort()->values();
100
101         $middle = (int) ($count / 2);
102
103         if ($count % 2) {
104             return $values->get($middle);
105         }
106
107         return (new static([
108             $values->get($middle - 1), $values->get($middle),
109         ]))->average();
110     }
111
112     /**
113      * Get the mode of a given key.
114      *
115      * @param  null $key
116      * @return array
117      */
118     public function mode($key = null)
119     {
120         $count = $this->count();
121
122         if ($count == 0) {
123             return;
124         }
125
126         $collection = isset($key) ? $this->pluck($key) : $this;
127
128         $counts = new self;
129
130         $collection->each(function ($value) use ($counts) {
131             $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
132         });
133
134         $sorted = $counts->sort();
135
136         $highestValue = $sorted->last();
137
138         return $sorted->filter(function ($value) use ($highestValue) {
139             return $value == $highestValue;
140         })->sort()->keys()->all();
141     }
142
143     /**
144      * Collapse the collection of items into a single array.
145      *
146      * @return static
147      */
148     public function collapse()
149     {
150         return new static(Arr::collapse($this->items));
151     }
152
153     /**
154      * Determine if an item exists in the collection.
155      *
156      * @param  mixed  $key
157      * @param  mixed  $value
158      * @return bool
159      */
160     public function contains($key, $value = null)
161     {
162         if (func_num_args() == 2) {
163             return $this->contains(function ($item) use ($key, $value) {
164                 return data_get($item, $key) == $value;
165             });
166         }
167
168         if ($this->useAsCallable($key)) {
169             return ! is_null($this->first($key));
170         }
171
172         return in_array($key, $this->items);
173     }
174
175     /**
176      * Determine if an item exists in the collection using strict comparison.
177      *
178      * @param  mixed  $key
179      * @param  mixed  $value
180      * @return bool
181      */
182     public function containsStrict($key, $value = null)
183     {
184         if (func_num_args() == 2) {
185             return $this->contains(function ($item) use ($key, $value) {
186                 return data_get($item, $key) === $value;
187             });
188         }
189
190         if ($this->useAsCallable($key)) {
191             return ! is_null($this->first($key));
192         }
193
194         return in_array($key, $this->items, true);
195     }
196
197     /**
198      * Get the items in the collection that are not present in the given items.
199      *
200      * @param  mixed  $items
201      * @return static
202      */
203     public function diff($items)
204     {
205         return new static(array_diff($this->items, $this->getArrayableItems($items)));
206     }
207
208     /**
209      * Get the items in the collection whose keys are not present in the given items.
210      *
211      * @param  mixed  $items
212      * @return static
213      */
214     public function diffKeys($items)
215     {
216         return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
217     }
218
219     /**
220      * Execute a callback over each item.
221      *
222      * @param  callable  $callback
223      * @return $this
224      */
225     public function each(callable $callback)
226     {
227         foreach ($this->items as $key => $item) {
228             if ($callback($item, $key) === false) {
229                 break;
230             }
231         }
232
233         return $this;
234     }
235
236     /**
237      * Create a new collection consisting of every n-th element.
238      *
239      * @param  int  $step
240      * @param  int  $offset
241      * @return static
242      */
243     public function every($step, $offset = 0)
244     {
245         $new = [];
246
247         $position = 0;
248
249         foreach ($this->items as $item) {
250             if ($position % $step === $offset) {
251                 $new[] = $item;
252             }
253
254             $position++;
255         }
256
257         return new static($new);
258     }
259
260     /**
261      * Get all items except for those with the specified keys.
262      *
263      * @param  mixed  $keys
264      * @return static
265      */
266     public function except($keys)
267     {
268         $keys = is_array($keys) ? $keys : func_get_args();
269
270         return new static(Arr::except($this->items, $keys));
271     }
272
273     /**
274      * Run a filter over each of the items.
275      *
276      * @param  callable|null  $callback
277      * @return static
278      */
279     public function filter(callable $callback = null)
280     {
281         if ($callback) {
282             return new static(Arr::where($this->items, $callback));
283         }
284
285         return new static(array_filter($this->items));
286     }
287
288     /**
289      * Filter items by the given key value pair.
290      *
291      * @param  string  $key
292      * @param  mixed  $operator
293      * @param  mixed  $value
294      * @return static
295      */
296     public function where($key, $operator, $value = null)
297     {
298         if (func_num_args() == 2) {
299             $value = $operator;
300
301             $operator = '=';
302         }
303
304         return $this->filter($this->operatorForWhere($key, $operator, $value));
305     }
306
307     /**
308      * Get an operator checker callback.
309      *
310      * @param  string  $key
311      * @param  string  $operator
312      * @param  mixed  $value
313      * @return \Closure
314      */
315     protected function operatorForWhere($key, $operator, $value)
316     {
317         return function ($item) use ($key, $operator, $value) {
318             $retrieved = data_get($item, $key);
319
320             switch ($operator) {
321                 default:
322                 case '=':
323                 case '==':  return $retrieved == $value;
324                 case '!=':
325                 case '<>':  return $retrieved != $value;
326                 case '<':   return $retrieved < $value;
327                 case '>':   return $retrieved > $value;
328                 case '<=':  return $retrieved <= $value;
329                 case '>=':  return $retrieved >= $value;
330                 case '===': return $retrieved === $value;
331                 case '!==': return $retrieved !== $value;
332             }
333         };
334     }
335
336     /**
337      * Filter items by the given key value pair using strict comparison.
338      *
339      * @param  string  $key
340      * @param  mixed  $value
341      * @return static
342      */
343     public function whereStrict($key, $value)
344     {
345         return $this->where($key, '===', $value);
346     }
347
348     /**
349      * Filter items by the given key value pair.
350      *
351      * @param  string  $key
352      * @param  mixed  $values
353      * @param  bool  $strict
354      * @return static
355      */
356     public function whereIn($key, $values, $strict = false)
357     {
358         $values = $this->getArrayableItems($values);
359
360         return $this->filter(function ($item) use ($key, $values, $strict) {
361             return in_array(data_get($item, $key), $values, $strict);
362         });
363     }
364
365     /**
366      * Filter items by the given key value pair using strict comparison.
367      *
368      * @param  string  $key
369      * @param  mixed  $values
370      * @return static
371      */
372     public function whereInStrict($key, $values)
373     {
374         return $this->whereIn($key, $values, true);
375     }
376
377     /**
378      * Get the first item from the collection.
379      *
380      * @param  callable|null  $callback
381      * @param  mixed  $default
382      * @return mixed
383      */
384     public function first(callable $callback = null, $default = null)
385     {
386         return Arr::first($this->items, $callback, $default);
387     }
388
389     /**
390      * Get a flattened array of the items in the collection.
391      *
392      * @param  int  $depth
393      * @return static
394      */
395     public function flatten($depth = INF)
396     {
397         return new static(Arr::flatten($this->items, $depth));
398     }
399
400     /**
401      * Flip the items in the collection.
402      *
403      * @return static
404      */
405     public function flip()
406     {
407         return new static(array_flip($this->items));
408     }
409
410     /**
411      * Remove an item from the collection by key.
412      *
413      * @param  string|array  $keys
414      * @return $this
415      */
416     public function forget($keys)
417     {
418         foreach ((array) $keys as $key) {
419             $this->offsetUnset($key);
420         }
421
422         return $this;
423     }
424
425     /**
426      * Get an item from the collection by key.
427      *
428      * @param  mixed  $key
429      * @param  mixed  $default
430      * @return mixed
431      */
432     public function get($key, $default = null)
433     {
434         if ($this->offsetExists($key)) {
435             return $this->items[$key];
436         }
437
438         return value($default);
439     }
440
441     /**
442      * Group an associative array by a field or using a callback.
443      *
444      * @param  callable|string  $groupBy
445      * @param  bool  $preserveKeys
446      * @return static
447      */
448     public function groupBy($groupBy, $preserveKeys = false)
449     {
450         $groupBy = $this->valueRetriever($groupBy);
451
452         $results = [];
453
454         foreach ($this->items as $key => $value) {
455             $groupKeys = $groupBy($value, $key);
456
457             if (! is_array($groupKeys)) {
458                 $groupKeys = [$groupKeys];
459             }
460
461             foreach ($groupKeys as $groupKey) {
462                 if (! array_key_exists($groupKey, $results)) {
463                     $results[$groupKey] = new static;
464                 }
465
466                 $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
467             }
468         }
469
470         return new static($results);
471     }
472
473     /**
474      * Key an associative array by a field or using a callback.
475      *
476      * @param  callable|string  $keyBy
477      * @return static
478      */
479     public function keyBy($keyBy)
480     {
481         $keyBy = $this->valueRetriever($keyBy);
482
483         $results = [];
484
485         foreach ($this->items as $key => $item) {
486             $resolvedKey = $keyBy($item, $key);
487
488             if (is_object($resolvedKey)) {
489                 $resolvedKey = (string) $resolvedKey;
490             }
491
492             $results[$resolvedKey] = $item;
493         }
494
495         return new static($results);
496     }
497
498     /**
499      * Determine if an item exists in the collection by key.
500      *
501      * @param  mixed  $key
502      * @return bool
503      */
504     public function has($key)
505     {
506         return $this->offsetExists($key);
507     }
508
509     /**
510      * Concatenate values of a given key as a string.
511      *
512      * @param  string  $value
513      * @param  string  $glue
514      * @return string
515      */
516     public function implode($value, $glue = null)
517     {
518         $first = $this->first();
519
520         if (is_array($first) || is_object($first)) {
521             return implode($glue, $this->pluck($value)->all());
522         }
523
524         return implode($value, $this->items);
525     }
526
527     /**
528      * Intersect the collection with the given items.
529      *
530      * @param  mixed  $items
531      * @return static
532      */
533     public function intersect($items)
534     {
535         return new static(array_intersect($this->items, $this->getArrayableItems($items)));
536     }
537
538     /**
539      * Determine if the collection is empty or not.
540      *
541      * @return bool
542      */
543     public function isEmpty()
544     {
545         return empty($this->items);
546     }
547
548         /**
549      * Determine if the given value is callable, but not a string.
550      *
551      * @param  mixed  $value
552      * @return bool
553      */
554     protected function useAsCallable($value)
555     {
556         return ! is_string($value) && is_callable($value);
557     }
558
559     /**
560      * Get the keys of the collection items.
561      *
562      * @return static
563      */
564     public function keys()
565     {
566         return new static(array_keys($this->items));
567     }
568
569     /**
570      * Get the last item from the collection.
571      *
572      * @param  callable|null  $callback
573      * @param  mixed  $default
574      * @return mixed
575      */
576     public function last(callable $callback = null, $default = null)
577     {
578         return Arr::last($this->items, $callback, $default);
579     }
580
581     /**
582      * Get the values of a given key.
583      *
584      * @param  string  $value
585      * @param  string|null  $key
586      * @return static
587      */
588     public function pluck($value, $key = null)
589     {
590         return new static(Arr::pluck($this->items, $value, $key));
591     }
592
593     /**
594      * Run a map over each of the items.
595      *
596      * @param  callable  $callback
597      * @return static
598      */
599     public function map(callable $callback)
600     {
601         $keys = array_keys($this->items);
602
603         $items = array_map($callback, $this->items, $keys);
604
605         return new static(array_combine($keys, $items));
606     }
607
608     /**
609      * Run an associative map over each of the items.
610      *
611      * The callback should return an associative array with a single key/value pair.
612      *
613      * @param  callable  $callback
614      * @return static
615      */
616     public function mapWithKeys(callable $callback)
617     {
618         return $this->flatMap($callback);
619     }
620
621     /**
622      * Map a collection and flatten the result by a single level.
623      *
624      * @param  callable  $callback
625      * @return static
626      */
627     public function flatMap(callable $callback)
628     {
629         return $this->map($callback)->collapse();
630     }
631
632     /**
633      * Get the max value of a given key.
634      *
635      * @param  callable|string|null  $callback
636      * @return mixed
637      */
638     public function max($callback = null)
639     {
640         $callback = $this->valueRetriever($callback);
641
642         return $this->reduce(function ($result, $item) use ($callback) {
643             $value = $callback($item);
644
645             return is_null($result) || $value > $result ? $value : $result;
646         });
647     }
648
649     /**
650      * Merge the collection with the given items.
651      *
652      * @param  mixed  $items
653      * @return static
654      */
655     public function merge($items)
656     {
657         return new static(array_merge($this->items, $this->getArrayableItems($items)));
658     }
659
660     /**
661      * Create a collection by using this collection for keys and another for its values.
662      *
663      * @param  mixed  $values
664      * @return static
665      */
666     public function combine($values)
667     {
668         return new static(array_combine($this->all(), $this->getArrayableItems($values)));
669     }
670
671     /**
672      * Union the collection with the given items.
673      *
674      * @param  mixed  $items
675      * @return static
676      */
677     public function union($items)
678     {
679         return new static($this->items + $this->getArrayableItems($items));
680     }
681
682     /**
683      * Get the min value of a given key.
684      *
685      * @param  callable|string|null  $callback
686      * @return mixed
687      */
688     public function min($callback = null)
689     {
690         $callback = $this->valueRetriever($callback);
691
692         return $this->reduce(function ($result, $item) use ($callback) {
693             $value = $callback($item);
694
695             return is_null($result) || $value < $result ? $value : $result;
696         });
697     }
698
699     /**
700      * Get the items with the specified keys.
701      *
702      * @param  mixed  $keys
703      * @return static
704      */
705     public function only($keys)
706     {
707         if (is_null($keys)) {
708             return new static($this->items);
709         }
710
711         $keys = is_array($keys) ? $keys : func_get_args();
712
713         return new static(Arr::only($this->items, $keys));
714     }
715
716     /**
717      * "Paginate" the collection by slicing it into a smaller collection.
718      *
719      * @param  int  $page
720      * @param  int  $perPage
721      * @return static
722      */
723     public function forPage($page, $perPage)
724     {
725         return $this->slice(($page - 1) * $perPage, $perPage);
726     }
727
728         /**
729          * Partition the collection into two arrays using the given callback or key.
730          *
731          * @param  callable|string  $key
732          * @param  mixed  $operator
733          * @param  mixed  $value
734          * @return static
735          */
736         public function partition($key, $operator = null, $value = null)
737         {
738                 $partitions = [new static, new static];
739
740                 $callback = func_num_args() === 1
741                         ? $this->valueRetriever($key)
742                         : $this->operatorForWhere(...func_get_args());
743
744                 foreach ($this->items as $key => $item) {
745                         $partitions[(int) ! $callback($item, $key)][$key] = $item;
746                 }
747
748                 return new static($partitions);
749         }
750     /**
751      * Pass the collection to the given callback and return the result.
752      *
753      * @param  callable $callback
754      * @return mixed
755      */
756     public function pipe(callable $callback)
757     {
758         return $callback($this);
759     }
760
761     /**
762      * Get and remove the last item from the collection.
763      *
764      * @return mixed
765      */
766     public function pop()
767     {
768         return array_pop($this->items);
769     }
770
771     /**
772      * Push an item onto the beginning of the collection.
773      *
774      * @param  mixed  $value
775      * @param  mixed  $key
776      * @return $this
777      */
778     public function prepend($value, $key = null)
779     {
780         $this->items = Arr::prepend($this->items, $value, $key);
781
782         return $this;
783     }
784
785     /**
786      * Push an item onto the end of the collection.
787      *
788      * @param  mixed  $value
789      * @return $this
790      */
791     public function push($value)
792     {
793         $this->offsetSet(null, $value);
794
795         return $this;
796     }
797
798     /**
799      * Get and remove an item from the collection.
800      *
801      * @param  mixed  $key
802      * @param  mixed  $default
803      * @return mixed
804      */
805     public function pull($key, $default = null)
806     {
807         return Arr::pull($this->items, $key, $default);
808     }
809
810     /**
811      * Put an item in the collection by key.
812      *
813      * @param  mixed  $key
814      * @param  mixed  $value
815      * @return $this
816      */
817     public function put($key, $value)
818     {
819         $this->offsetSet($key, $value);
820
821         return $this;
822     }
823
824     /**
825      * Get one or more items randomly from the collection.
826      *
827      * @param  int  $amount
828      * @return mixed
829      *
830      * @throws \InvalidArgumentException
831      */
832     public function random($amount = 1)
833     {
834         if ($amount > ($count = $this->count())) {
835             throw new InvalidArgumentException("You requested {$amount} items, but there are only {$count} items in the collection");
836         }
837
838         $keys = array_rand($this->items, $amount);
839
840         if ($amount == 1) {
841             return $this->items[$keys];
842         }
843
844         return new static(array_intersect_key($this->items, array_flip($keys)));
845     }
846
847     /**
848      * Reduce the collection to a single value.
849      *
850      * @param  callable  $callback
851      * @param  mixed     $initial
852      * @return mixed
853      */
854     public function reduce(callable $callback, $initial = null)
855     {
856         return array_reduce($this->items, $callback, $initial);
857     }
858
859     /**
860      * Create a collection of all elements that do not pass a given truth test.
861      *
862      * @param  callable|mixed  $callback
863      * @return static
864      */
865     public function reject($callback)
866     {
867         if ($this->useAsCallable($callback)) {
868             return $this->filter(function ($value, $key) use ($callback) {
869                 return ! $callback($value, $key);
870             });
871         }
872
873         return $this->filter(function ($item) use ($callback) {
874             return $item != $callback;
875         });
876     }
877
878     /**
879      * Reverse items order.
880      *
881      * @return static
882      */
883     public function reverse()
884     {
885         return new static(array_reverse($this->items, true));
886     }
887
888     /**
889      * Search the collection for a given value and return the corresponding key if successful.
890      *
891      * @param  mixed  $value
892      * @param  bool   $strict
893      * @return mixed
894      */
895     public function search($value, $strict = false)
896     {
897         if (! $this->useAsCallable($value)) {
898             return array_search($value, $this->items, $strict);
899         }
900
901         foreach ($this->items as $key => $item) {
902             if (call_user_func($value, $item, $key)) {
903                 return $key;
904             }
905         }
906
907         return false;
908     }
909
910     /**
911      * Get and remove the first item from the collection.
912      *
913      * @return mixed
914      */
915     public function shift()
916     {
917         return array_shift($this->items);
918     }
919
920     /**
921      * Shuffle the items in the collection.
922      *
923      * @param int $seed
924      * @return static
925      */
926     public function shuffle($seed = null)
927     {
928         $items = $this->items;
929
930         if (is_null($seed)) {
931             shuffle($items);
932         } else {
933             srand($seed);
934
935             usort($items, function () {
936                 return rand(-1, 1);
937             });
938         }
939
940         return new static($items);
941     }
942
943     /**
944      * Slice the underlying collection array.
945      *
946      * @param  int   $offset
947      * @param  int   $length
948      * @return static
949      */
950     public function slice($offset, $length = null)
951     {
952         return new static(array_slice($this->items, $offset, $length, true));
953     }
954
955     /**
956      * Split a collection into a certain number of groups.
957      *
958      * @param  int  $numberOfGroups
959      * @return static
960      */
961     public function split($numberOfGroups)
962     {
963         if ($this->isEmpty()) {
964             return new static;
965         }
966
967         $groupSize = ceil($this->count() / $numberOfGroups);
968
969         return $this->chunk($groupSize);
970     }
971
972     /**
973      * Chunk the underlying collection array.
974      *
975      * @param  int   $size
976      * @return static
977      */
978     public function chunk($size)
979     {
980         $chunks = [];
981
982         foreach (array_chunk($this->items, $size, true) as $chunk) {
983             $chunks[] = new static($chunk);
984         }
985
986         return new static($chunks);
987     }
988
989     /**
990      * Sort through each item with a callback.
991      *
992      * @param  callable|null  $callback
993      * @return static
994      */
995     public function sort(callable $callback = null)
996     {
997         $items = $this->items;
998
999         $callback
1000             ? uasort($items, $callback)
1001             : asort($items);
1002
1003         return new static($items);
1004     }
1005
1006     /**
1007      * Sort the collection using the given callback.
1008      *
1009      * @param  callable|string  $callback
1010      * @param  int   $options
1011      * @param  bool  $descending
1012      * @return static
1013      */
1014     public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1015     {
1016         $results = [];
1017
1018         $callback = $this->valueRetriever($callback);
1019
1020         // First we will loop through the items and get the comparator from a callback
1021         // function which we were given. Then, we will sort the returned values and
1022         // and grab the corresponding values for the sorted keys from this array.
1023         foreach ($this->items as $key => $value) {
1024             $results[$key] = $callback($value, $key);
1025         }
1026
1027         $descending ? arsort($results, $options)
1028                     : asort($results, $options);
1029
1030         // Once we have sorted all of the keys in the array, we will loop through them
1031         // and grab the corresponding model so we can set the underlying items list
1032         // to the sorted version. Then we'll just return the collection instance.
1033         foreach (array_keys($results) as $key) {
1034             $results[$key] = $this->items[$key];
1035         }
1036
1037         return new static($results);
1038     }
1039
1040     /**
1041      * Sort the collection in descending order using the given callback.
1042      *
1043      * @param  callable|string  $callback
1044      * @param  int  $options
1045      * @return static
1046      */
1047     public function sortByDesc($callback, $options = SORT_REGULAR)
1048     {
1049         return $this->sortBy($callback, $options, true);
1050     }
1051
1052     /**
1053      * Splice a portion of the underlying collection array.
1054      *
1055      * @param  int  $offset
1056      * @param  int|null  $length
1057      * @param  mixed  $replacement
1058      * @return static
1059      */
1060     public function splice($offset, $length = null, $replacement = [])
1061     {
1062         if (func_num_args() == 1) {
1063             return new static(array_splice($this->items, $offset));
1064         }
1065
1066         return new static(array_splice($this->items, $offset, $length, $replacement));
1067     }
1068
1069     /**
1070      * Get the sum of the given values.
1071      *
1072      * @param  callable|string|null  $callback
1073      * @return mixed
1074      */
1075     public function sum($callback = null)
1076     {
1077         if (is_null($callback)) {
1078             return array_sum($this->items);
1079         }
1080
1081         $callback = $this->valueRetriever($callback);
1082
1083         return $this->reduce(function ($result, $item) use ($callback) {
1084             return $result + $callback($item);
1085         }, 0);
1086     }
1087
1088     /**
1089      * Take the first or last {$limit} items.
1090      *
1091      * @param  int  $limit
1092      * @return static
1093      */
1094     public function take($limit)
1095     {
1096         if ($limit < 0) {
1097             return $this->slice($limit, abs($limit));
1098         }
1099
1100         return $this->slice(0, $limit);
1101     }
1102
1103     /**
1104      * Transform each item in the collection using a callback.
1105      *
1106      * @param  callable  $callback
1107      * @return $this
1108      */
1109     public function transform(callable $callback)
1110     {
1111         $this->items = $this->map($callback)->all();
1112
1113         return $this;
1114     }
1115
1116     /**
1117      * Return only unique items from the collection array.
1118      *
1119      * @param  string|callable|null  $key
1120      * @param  bool  $strict
1121      *
1122      * @return static
1123      */
1124     public function unique($key = null, $strict = false)
1125     {
1126         if (is_null($key)) {
1127             return new static(array_unique($this->items, SORT_REGULAR));
1128         }
1129
1130         $key = $this->valueRetriever($key);
1131
1132         $exists = [];
1133
1134         return $this->reject(function ($item) use ($key, $strict, &$exists) {
1135             if (in_array($id = $key($item), $exists, $strict)) {
1136                 return true;
1137             }
1138
1139             $exists[] = $id;
1140         });
1141     }
1142
1143     /**
1144      * Return only unique items from the collection array using strict comparison.
1145      *
1146      * @param  string|callable|null  $key
1147      * @return static
1148      */
1149     public function uniqueStrict($key = null)
1150     {
1151         return $this->unique($key, true);
1152     }
1153
1154     /**
1155      * Reset the keys on the underlying array.
1156      *
1157      * @return static
1158      */
1159     public function values()
1160     {
1161         return new static(array_values($this->items));
1162     }
1163
1164     /**
1165      * Get a value retrieving callback.
1166      *
1167      * @param  string  $value
1168      * @return callable
1169      */
1170     protected function valueRetriever($value)
1171     {
1172         if ($this->useAsCallable($value)) {
1173             return $value;
1174         }
1175
1176         return function ($item) use ($value) {
1177             return data_get($item, $value);
1178         };
1179     }
1180
1181     /**
1182      * Zip the collection together with one or more arrays.
1183      *
1184      * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1185      *      => [[1, 4], [2, 5], [3, 6]]
1186      *
1187      * @param  mixed ...$items
1188      * @return static
1189      */
1190     public function zip($items)
1191     {
1192         $arrayableItems = array_map(function ($items) {
1193             return $this->getArrayableItems($items);
1194         }, func_get_args());
1195
1196         $params = array_merge([function () {
1197             return new static(func_get_args());
1198         }, $this->items], $arrayableItems);
1199
1200         return new static(call_user_func_array('array_map', $params));
1201     }
1202
1203     /**
1204      * Get the collection of items as a plain array.
1205      *
1206      * @return array
1207      */
1208     public function toArray()
1209     {
1210         return array_map(function ($value) {
1211             return $value instanceof Arrayable ? $value->toArray() : $value;
1212         }, $this->items);
1213     }
1214
1215     /**
1216      * Convert the object into something JSON serializable.
1217      *
1218      * @return array
1219      */
1220     public function jsonSerialize()
1221     {
1222         return array_map(function ($value) {
1223             if ($value instanceof JsonSerializable) {
1224                 return $value->jsonSerialize();
1225             } elseif ($value instanceof Jsonable) {
1226                 return json_decode($value->toJson(), true);
1227             } elseif ($value instanceof Arrayable) {
1228                 return $value->toArray();
1229             } else {
1230                 return $value;
1231             }
1232         }, $this->items);
1233     }
1234
1235     /**
1236      * Get the collection of items as JSON.
1237      *
1238      * @param  int  $options
1239      * @return string
1240      */
1241     public function toJson($options = 0)
1242     {
1243         return json_encode($this->jsonSerialize(), $options);
1244     }
1245
1246     /**
1247      * Get an iterator for the items.
1248      *
1249      * @return \ArrayIterator
1250      */
1251     public function getIterator()
1252     {
1253         return new ArrayIterator($this->items);
1254     }
1255
1256     /**
1257      * Get a CachingIterator instance.
1258      *
1259      * @param  int  $flags
1260      * @return \CachingIterator
1261      */
1262     public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1263     {
1264         return new CachingIterator($this->getIterator(), $flags);
1265     }
1266
1267     /**
1268      * Count the number of items in the collection.
1269      *
1270      * @return int
1271      */
1272     public function count()
1273     {
1274         return count($this->items);
1275     }
1276
1277     /**
1278      * Get a base Support collection instance from this collection.
1279      *
1280      * @return \WPML\Collect\Support\Collection
1281      */
1282     public function toBase()
1283     {
1284         return new self($this);
1285     }
1286
1287     /**
1288      * Determine if an item exists at an offset.
1289      *
1290      * @param  mixed  $key
1291      * @return bool
1292      */
1293     public function offsetExists($key)
1294     {
1295         return array_key_exists($key, $this->items);
1296     }
1297
1298     /**
1299      * Get an item at a given offset.
1300      *
1301      * @param  mixed  $key
1302      * @return mixed
1303      */
1304     public function offsetGet($key)
1305     {
1306         return $this->items[$key];
1307     }
1308
1309     /**
1310      * Set the item at a given offset.
1311      *
1312      * @param  mixed  $key
1313      * @param  mixed  $value
1314      * @return void
1315      */
1316     public function offsetSet($key, $value)
1317     {
1318         if (is_null($key)) {
1319             $this->items[] = $value;
1320         } else {
1321             $this->items[$key] = $value;
1322         }
1323     }
1324
1325     /**
1326      * Unset the item at a given offset.
1327      *
1328      * @param  string  $key
1329      * @return void
1330      */
1331     public function offsetUnset($key)
1332     {
1333         unset($this->items[$key]);
1334     }
1335
1336     /**
1337      * Convert the collection to its string representation.
1338      *
1339      * @return string
1340      */
1341     public function __toString()
1342     {
1343         return $this->toJson();
1344     }
1345
1346     /**
1347      * Results array of items from Collection or Arrayable.
1348      *
1349      * @param  mixed  $items
1350      * @return array
1351      */
1352     protected function getArrayableItems($items)
1353     {
1354         if (is_array($items)) {
1355             return $items;
1356         } elseif ($items instanceof self) {
1357             return $items->all();
1358         } elseif ($items instanceof Arrayable) {
1359             return $items->toArray();
1360         } elseif ($items instanceof Jsonable) {
1361             return json_decode($items->toJson(), true);
1362         } elseif ($items instanceof JsonSerializable) {
1363             return $items->jsonSerialize();
1364         } elseif ($items instanceof Traversable) {
1365             return iterator_to_array($items);
1366         }
1367
1368         return (array) $items;
1369     }
1370
1371         /** Those methods exist in the latest version of the library and have been copied here */
1372
1373         /**
1374          * Run a dictionary map over the items.
1375          *
1376          * The callback should return an associative array with a single key/value pair.
1377          *
1378          * @param  callable  $callback
1379          * @return $this
1380          */
1381         public function mapToDictionary(callable $callback)
1382         {
1383                 $dictionary = [];
1384
1385                 foreach ($this->items as $key => $item) {
1386                         $pair = $callback($item, $key);
1387
1388                         $key = key($pair);
1389
1390                         $value = reset($pair);
1391
1392                         if (! isset($dictionary[$key])) {
1393                                 $dictionary[$key] = [];
1394                         }
1395
1396                         $dictionary[$key][] = $value;
1397                 }
1398
1399                 return new static($dictionary);
1400         }
1401
1402         /**
1403          * Run a grouping map over the items.
1404          *
1405          * The callback should return an associative array with a single key/value pair.
1406          *
1407          * @param  callable  $callback
1408          * @return static
1409          */
1410         public function mapToGroups(callable $callback)
1411         {
1412                 $groups = $this->mapToDictionary($callback);
1413
1414                 return $groups->map([$this, 'make']);
1415         }
1416
1417         /**
1418          * Move the items meeting the condition to the front of the collection
1419          *
1420          * @param callable $condition
1421          *
1422          * @return Collection - A new collection
1423          */
1424         public function prioritize( callable $condition ) {
1425                 $nonPrioritized = $this->reject( $condition );
1426
1427                 return $this
1428                         ->filter( $condition )
1429                         ->toBase()
1430                         ->merge( $nonPrioritized );
1431         }
1432
1433         /**
1434          * Convert an associative array of key => value to array of pairs [ key, value ].
1435          *
1436          * @return Collection
1437          */
1438         public function assocToPair() {
1439                 return $this->map( function ( $item, $key ) {
1440                         return [ $key, $item ];
1441                 } )->values();
1442         }
1443
1444         /**
1445          * Convert an array of pairs [ key, value ] to an associative array of key => value.
1446          *
1447          * @return Collection
1448          */
1449         public function pairToAssoc() {
1450                 return $this->mapWithKeys( function ( $pair ) {
1451                         return [ $pair[0] => $pair[1] ];
1452                 } );
1453         }
1454
1455         /**
1456          * Executes the given function for each item while the total execution time is less than the time out.
1457          * Returns the unprocessed items if a timeout occurred.
1458          *
1459          * @param callable $fn Function to all for each item.
1460          * @param int $timeout Timeout in seconds.
1461          *
1462          * @return Collection
1463          */
1464         public function eachWithTimeout( callable $fn, $timeout ) {
1465                 $endTime = time() + $timeout;
1466
1467                 return $this->reduce( function ( Collection $unProcessed, $item ) use ( $endTime, $fn ) {
1468                         if ( time() > $endTime ) {
1469                                 $unProcessed->push( $item );
1470                         } else {
1471                                 $fn( $item );
1472                         }
1473
1474                         return $unProcessed;
1475                 }, wpml_collect() );
1476         }
1477
1478         /**
1479          * Determine if the collection is not empty.
1480          *
1481          * @return bool
1482          */
1483         public function isNotEmpty()
1484         {
1485                 return  ! empty($this->items);
1486         }
1487
1488         /**
1489          * Cross join with the given lists, returning all possible permutations.
1490          *
1491          * @param  mixed  ...$lists
1492          * @return static
1493          */
1494         public function crossJoin(...$lists)
1495         {
1496                 return new static(Arr::crossJoin(
1497                         $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
1498                 ));
1499         }
1500 }