1<?php 2 3namespace Illuminate\Support; 4 5use Countable; 6use ArrayAccess; 7use Traversable; 8use ArrayIterator; 9use CachingIterator; 10use JsonSerializable; 11use IteratorAggregate; 12use InvalidArgumentException; 13use Illuminate\Support\Traits\Macroable; 14use Illuminate\Contracts\Support\Jsonable; 15use Illuminate\Contracts\Support\Arrayable; 16 17class 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 string|null $key 64 * @return mixed 65 */ 66 public function avg($key = null) 67 { 68 if ($count = $this->count()) { 69 return $this->sum($key) / $count; 70 } 71 } 72 73 /** 74 * Alias for the "avg" method. 75 * 76 * @param string|null $key 77 * @return mixed 78 */ 79 public function average($key = null) 80 { 81 return $this->avg($key); 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) floor($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 ($k, $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 * Get the items in the collection that are not present in the given items. 177 * 178 * @param mixed $items 179 * @return static 180 */ 181 public function diff($items) 182 { 183 return new static(array_diff($this->items, $this->getArrayableItems($items))); 184 } 185 186 /** 187 * Get the items in the collection whose keys are not present in the given items. 188 * 189 * @param mixed $items 190 * @return static 191 */ 192 public function diffKeys($items) 193 { 194 return new static(array_diff_key($this->items, $this->getArrayableItems($items))); 195 } 196 197 /** 198 * Execute a callback over each item. 199 * 200 * @param callable $callback 201 * @return $this 202 */ 203 public function each(callable $callback) 204 { 205 foreach ($this->items as $key => $item) { 206 if ($callback($item, $key) === false) { 207 break; 208 } 209 } 210 211 return $this; 212 } 213 214 /** 215 * Create a new collection consisting of every n-th element. 216 * 217 * @param int $step 218 * @param int $offset 219 * @return static 220 */ 221 public function every($step, $offset = 0) 222 { 223 $new = []; 224 225 $position = 0; 226 227 foreach ($this->items as $item) { 228 if ($position % $step === $offset) { 229 $new[] = $item; 230 } 231 232 $position++; 233 } 234 235 return new static($new); 236 } 237 238 /** 239 * Get all items except for those with the specified keys. 240 * 241 * @param mixed $keys 242 * @return static 243 */ 244 public function except($keys) 245 { 246 $keys = is_array($keys) ? $keys : func_get_args(); 247 248 return new static(Arr::except($this->items, $keys)); 249 } 250 251 /** 252 * Run a filter over each of the items. 253 * 254 * @param callable|null $callback 255 * @return static 256 */ 257 public function filter(callable $callback = null) 258 { 259 if ($callback) { 260 $return = []; 261 262 foreach ($this->items as $key => $value) { 263 if ($callback($value, $key)) { 264 $return[$key] = $value; 265 } 266 } 267 268 return new static($return); 269 } 270 271 return new static(array_filter($this->items)); 272 } 273 274 /** 275 * Filter items by the given key value pair. 276 * 277 * @param string $key 278 * @param mixed $value 279 * @param bool $strict 280 * @return static 281 */ 282 public function where($key, $value, $strict = true) 283 { 284 return $this->filter(function ($item) use ($key, $value, $strict) { 285 return $strict ? data_get($item, $key) === $value 286 : data_get($item, $key) == $value; 287 }); 288 } 289 290 /** 291 * Filter items by the given key value pair using loose comparison. 292 * 293 * @param string $key 294 * @param mixed $value 295 * @return static 296 */ 297 public function whereLoose($key, $value) 298 { 299 return $this->where($key, $value, false); 300 } 301 302 /** 303 * Filter items by the given key value pair. 304 * 305 * @param string $key 306 * @param array $values 307 * @param bool $strict 308 * @return static 309 */ 310 public function whereIn($key, array $values, $strict = true) 311 { 312 return $this->filter(function ($item) use ($key, $values, $strict) { 313 return in_array(data_get($item, $key), $values, $strict); 314 }); 315 } 316 317 /** 318 * Filter items by the given key value pair using loose comparison. 319 * 320 * @param string $key 321 * @param array $values 322 * @return static 323 */ 324 public function whereInLoose($key, array $values) 325 { 326 return $this->whereIn($key, $values, false); 327 } 328 329 /** 330 * Get the first item from the collection. 331 * 332 * @param callable|null $callback 333 * @param mixed $default 334 * @return mixed 335 */ 336 public function first(callable $callback = null, $default = null) 337 { 338 return Arr::first($this->items, $callback, $default); 339 } 340 341 /** 342 * Get a flattened array of the items in the collection. 343 * 344 * @param int $depth 345 * @return static 346 */ 347 public function flatten($depth = INF) 348 { 349 return new static(Arr::flatten($this->items, $depth)); 350 } 351 352 /** 353 * Flip the items in the collection. 354 * 355 * @return static 356 */ 357 public function flip() 358 { 359 return new static(array_flip($this->items)); 360 } 361 362 /** 363 * Remove an item from the collection by key. 364 * 365 * @param string|array $keys 366 * @return $this 367 */ 368 public function forget($keys) 369 { 370 foreach ((array) $keys as $key) { 371 $this->offsetUnset($key); 372 } 373 374 return $this; 375 } 376 377 /** 378 * Get an item from the collection by key. 379 * 380 * @param mixed $key 381 * @param mixed $default 382 * @return mixed 383 */ 384 public function get($key, $default = null) 385 { 386 if ($this->offsetExists($key)) { 387 return $this->items[$key]; 388 } 389 390 return value($default); 391 } 392 393 /** 394 * Group an associative array by a field or using a callback. 395 * 396 * @param callable|string $groupBy 397 * @param bool $preserveKeys 398 * @return static 399 */ 400 public function groupBy($groupBy, $preserveKeys = false) 401 { 402 $groupBy = $this->valueRetriever($groupBy); 403 404 $results = []; 405 406 foreach ($this->items as $key => $value) { 407 $groupKeys = $groupBy($value, $key); 408 409 if (! is_array($groupKeys)) { 410 $groupKeys = [$groupKeys]; 411 } 412 413 foreach ($groupKeys as $groupKey) { 414 if (! array_key_exists($groupKey, $results)) { 415 $results[$groupKey] = new static; 416 } 417 418 $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value); 419 } 420 } 421 422 return new static($results); 423 } 424 425 /** 426 * Key an associative array by a field or using a callback. 427 * 428 * @param callable|string $keyBy 429 * @return static 430 */ 431 public function keyBy($keyBy) 432 { 433 $keyBy = $this->valueRetriever($keyBy); 434 435 $results = []; 436 437 foreach ($this->items as $key => $item) { 438 $results[$keyBy($item, $key)] = $item; 439 } 440 441 return new static($results); 442 } 443 444 /** 445 * Determine if an item exists in the collection by key. 446 * 447 * @param mixed $key 448 * @return bool 449 */ 450 public function has($key) 451 { 452 return $this->offsetExists($key); 453 } 454 455 /** 456 * Concatenate values of a given key as a string. 457 * 458 * @param string $value 459 * @param string $glue 460 * @return string 461 */ 462 public function implode($value, $glue = null) 463 { 464 $first = $this->first(); 465 466 if (is_array($first) || is_object($first)) { 467 return implode($glue, $this->pluck($value)->all()); 468 } 469 470 return implode($value, $this->items); 471 } 472 473 /** 474 * Intersect the collection with the given items. 475 * 476 * @param mixed $items 477 * @return static 478 */ 479 public function intersect($items) 480 { 481 return new static(array_intersect($this->items, $this->getArrayableItems($items))); 482 } 483 484 /** 485 * Determine if the collection is empty or not. 486 * 487 * @return bool 488 */ 489 public function isEmpty() 490 { 491 return empty($this->items); 492 } 493 494 /** 495 * Determine if the given value is callable, but not a string. 496 * 497 * @param mixed $value 498 * @return bool 499 */ 500 protected function useAsCallable($value) 501 { 502 return ! is_string($value) && is_callable($value); 503 } 504 505 /** 506 * Get the keys of the collection items. 507 * 508 * @return static 509 */ 510 public function keys() 511 { 512 return new static(array_keys($this->items)); 513 } 514 515 /** 516 * Get the last item from the collection. 517 * 518 * @param callable|null $callback 519 * @param mixed $default 520 * @return mixed 521 */ 522 public function last(callable $callback = null, $default = null) 523 { 524 return Arr::last($this->items, $callback, $default); 525 } 526 527 /** 528 * Get the values of a given key. 529 * 530 * @param string $value 531 * @param string|null $key 532 * @return static 533 */ 534 public function pluck($value, $key = null) 535 { 536 return new static(Arr::pluck($this->items, $value, $key)); 537 } 538 539 /** 540 * Alias for the "pluck" method. 541 * 542 * @param string $value 543 * @param string|null $key 544 * @return static 545 * 546 * @deprecated since version 5.2. Use the "pluck" method directly. 547 */ 548 public function lists($value, $key = null) 549 { 550 return $this->pluck($value, $key); 551 } 552 553 /** 554 * Run a map over each of the items. 555 * 556 * @param callable $callback 557 * @return static 558 */ 559 public function map(callable $callback) 560 { 561 $keys = array_keys($this->items); 562 563 $items = array_map($callback, $this->items, $keys); 564 565 return new static(array_combine($keys, $items)); 566 } 567 568 /** 569 * Map a collection and flatten the result by a single level. 570 * 571 * @param callable $callback 572 * @return static 573 */ 574 public function flatMap(callable $callback) 575 { 576 return $this->map($callback)->collapse(); 577 } 578 579 /** 580 * Get the max value of a given key. 581 * 582 * @param string|null $key 583 * @return mixed 584 */ 585 public function max($key = null) 586 { 587 return $this->reduce(function ($result, $item) use ($key) { 588 $value = data_get($item, $key); 589 590 return is_null($result) || $value > $result ? $value : $result; 591 }); 592 } 593 594 /** 595 * Merge the collection with the given items. 596 * 597 * @param mixed $items 598 * @return static 599 */ 600 public function merge($items) 601 { 602 return new static(array_merge($this->items, $this->getArrayableItems($items))); 603 } 604 605 /** 606 * Create a collection by using this collection for keys and another for its values. 607 * 608 * @param mixed $values 609 * @return static 610 */ 611 public function combine($values) 612 { 613 return new static(array_combine($this->all(), $this->getArrayableItems($values))); 614 } 615 616 /** 617 * Union the collection with the given items. 618 * 619 * @param mixed $items 620 * @return static 621 */ 622 public function union($items) 623 { 624 return new static($this->items + $this->getArrayableItems($items)); 625 } 626 627 /** 628 * Get the min value of a given key. 629 * 630 * @param string|null $key 631 * @return mixed 632 */ 633 public function min($key = null) 634 { 635 return $this->reduce(function ($result, $item) use ($key) { 636 $value = data_get($item, $key); 637 638 return is_null($result) || $value < $result ? $value : $result; 639 }); 640 } 641 642 /** 643 * Get the items with the specified keys. 644 * 645 * @param mixed $keys 646 * @return static 647 */ 648 public function only($keys) 649 { 650 $keys = is_array($keys) ? $keys : func_get_args(); 651 652 return new static(Arr::only($this->items, $keys)); 653 } 654 655 /** 656 * "Paginate" the collection by slicing it into a smaller collection. 657 * 658 * @param int $page 659 * @param int $perPage 660 * @return static 661 */ 662 public function forPage($page, $perPage) 663 { 664 return $this->slice(($page - 1) * $perPage, $perPage); 665 } 666 667 /** 668 * Pass the collection to the given callback and return the result. 669 * 670 * @param callable $callback 671 * @return mixed 672 */ 673 public function pipe(callable $callback) 674 { 675 return $callback($this); 676 } 677 678 /** 679 * Get and remove the last item from the collection. 680 * 681 * @return mixed 682 */ 683 public function pop() 684 { 685 return array_pop($this->items); 686 } 687 688 /** 689 * Push an item onto the beginning of the collection. 690 * 691 * @param mixed $value 692 * @param mixed $key 693 * @return $this 694 */ 695 public function prepend($value, $key = null) 696 { 697 $this->items = Arr::prepend($this->items, $value, $key); 698 699 return $this; 700 } 701 702 /** 703 * Push an item onto the end of the collection. 704 * 705 * @param mixed $value 706 * @return $this 707 */ 708 public function push($value) 709 { 710 $this->offsetSet(null, $value); 711 712 return $this; 713 } 714 715 /** 716 * Get and remove an item from the collection. 717 * 718 * @param mixed $key 719 * @param mixed $default 720 * @return mixed 721 */ 722 public function pull($key, $default = null) 723 { 724 return Arr::pull($this->items, $key, $default); 725 } 726 727 /** 728 * Put an item in the collection by key. 729 * 730 * @param mixed $key 731 * @param mixed $value 732 * @return $this 733 */ 734 public function put($key, $value) 735 { 736 $this->offsetSet($key, $value); 737 738 return $this; 739 } 740 741 /** 742 * Get one or more items randomly from the collection. 743 * 744 * @param int $amount 745 * @return mixed 746 * 747 * @throws \InvalidArgumentException 748 */ 749 public function random($amount = 1) 750 { 751 if ($amount > ($count = $this->count())) { 752 throw new InvalidArgumentException("You requested {$amount} items, but there are only {$count} items in the collection"); 753 } 754 755 $keys = array_rand($this->items, $amount); 756 757 if ($amount == 1) { 758 return $this->items[$keys]; 759 } 760 761 return new static(array_intersect_key($this->items, array_flip($keys))); 762 } 763 764 /** 765 * Reduce the collection to a single value. 766 * 767 * @param callable $callback 768 * @param mixed $initial 769 * @return mixed 770 */ 771 public function reduce(callable $callback, $initial = null) 772 { 773 return array_reduce($this->items, $callback, $initial); 774 } 775 776 /** 777 * Create a collection of all elements that do not pass a given truth test. 778 * 779 * @param callable|mixed $callback 780 * @return static 781 */ 782 public function reject($callback) 783 { 784 if ($this->useAsCallable($callback)) { 785 return $this->filter(function ($value, $key) use ($callback) { 786 return ! $callback($value, $key); 787 }); 788 } 789 790 return $this->filter(function ($item) use ($callback) { 791 return $item != $callback; 792 }); 793 } 794 795 /** 796 * Reverse items order. 797 * 798 * @return static 799 */ 800 public function reverse() 801 { 802 return new static(array_reverse($this->items, true)); 803 } 804 805 /** 806 * Search the collection for a given value and return the corresponding key if successful. 807 * 808 * @param mixed $value 809 * @param bool $strict 810 * @return mixed 811 */ 812 public function search($value, $strict = false) 813 { 814 if (! $this->useAsCallable($value)) { 815 return array_search($value, $this->items, $strict); 816 } 817 818 foreach ($this->items as $key => $item) { 819 if (call_user_func($value, $item, $key)) { 820 return $key; 821 } 822 } 823 824 return false; 825 } 826 827 /** 828 * Get and remove the first item from the collection. 829 * 830 * @return mixed 831 */ 832 public function shift() 833 { 834 return array_shift($this->items); 835 } 836 837 /** 838 * Shuffle the items in the collection. 839 * 840 * @param int $seed 841 * @return static 842 */ 843 public function shuffle($seed = null) 844 { 845 $items = $this->items; 846 847 if (is_null($seed)) { 848 shuffle($items); 849 } else { 850 srand($seed); 851 852 usort($items, function () { 853 return rand(-1, 1); 854 }); 855 } 856 857 return new static($items); 858 } 859 860 /** 861 * Slice the underlying collection array. 862 * 863 * @param int $offset 864 * @param int $length 865 * @return static 866 */ 867 public function slice($offset, $length = null) 868 { 869 return new static(array_slice($this->items, $offset, $length, true)); 870 } 871 872 /** 873 * Chunk the underlying collection array. 874 * 875 * @param int $size 876 * @return static 877 */ 878 public function chunk($size) 879 { 880 $chunks = []; 881 882 foreach (array_chunk($this->items, $size, true) as $chunk) { 883 $chunks[] = new static($chunk); 884 } 885 886 return new static($chunks); 887 } 888 889 /** 890 * Sort through each item with a callback. 891 * 892 * @param callable|null $callback 893 * @return static 894 */ 895 public function sort(callable $callback = null) 896 { 897 $items = $this->items; 898 899 $callback ? uasort($items, $callback) : uasort($items, function ($a, $b) { 900 if ($a == $b) { 901 return 0; 902 } 903 904 return ($a < $b) ? -1 : 1; 905 }); 906 907 return new static($items); 908 } 909 910 /** 911 * Sort the collection using the given callback. 912 * 913 * @param callable|string $callback 914 * @param int $options 915 * @param bool $descending 916 * @return static 917 */ 918 public function sortBy($callback, $options = SORT_REGULAR, $descending = false) 919 { 920 $results = []; 921 922 $callback = $this->valueRetriever($callback); 923 924 // First we will loop through the items and get the comparator from a callback 925 // function which we were given. Then, we will sort the returned values and 926 // and grab the corresponding values for the sorted keys from this array. 927 foreach ($this->items as $key => $value) { 928 $results[$key] = $callback($value, $key); 929 } 930 931 $descending ? arsort($results, $options) 932 : asort($results, $options); 933 934 // Once we have sorted all of the keys in the array, we will loop through them 935 // and grab the corresponding model so we can set the underlying items list 936 // to the sorted version. Then we'll just return the collection instance. 937 foreach (array_keys($results) as $key) { 938 $results[$key] = $this->items[$key]; 939 } 940 941 return new static($results); 942 } 943 944 /** 945 * Sort the collection in descending order using the given callback. 946 * 947 * @param callable|string $callback 948 * @param int $options 949 * @return static 950 */ 951 public function sortByDesc($callback, $options = SORT_REGULAR) 952 { 953 return $this->sortBy($callback, $options, true); 954 } 955 956 /** 957 * Splice a portion of the underlying collection array. 958 * 959 * @param int $offset 960 * @param int|null $length 961 * @param mixed $replacement 962 * @return static 963 */ 964 public function splice($offset, $length = null, $replacement = []) 965 { 966 if (func_num_args() == 1) { 967 return new static(array_splice($this->items, $offset)); 968 } 969 970 return new static(array_splice($this->items, $offset, $length, $replacement)); 971 } 972 973 /** 974 * Get the sum of the given values. 975 * 976 * @param callable|string|null $callback 977 * @return mixed 978 */ 979 public function sum($callback = null) 980 { 981 if (is_null($callback)) { 982 return array_sum($this->items); 983 } 984 985 $callback = $this->valueRetriever($callback); 986 987 return $this->reduce(function ($result, $item) use ($callback) { 988 return $result += $callback($item); 989 }, 0); 990 } 991 992 /** 993 * Take the first or last {$limit} items. 994 * 995 * @param int $limit 996 * @return static 997 */ 998 public function take($limit) 999 { 1000 if ($limit < 0) { 1001 return $this->slice($limit, abs($limit)); 1002 } 1003 1004 return $this->slice(0, $limit); 1005 } 1006 1007 /** 1008 * Transform each item in the collection using a callback. 1009 * 1010 * @param callable $callback 1011 * @return $this 1012 */ 1013 public function transform(callable $callback) 1014 { 1015 $this->items = $this->map($callback)->all(); 1016 1017 return $this; 1018 } 1019 1020 /** 1021 * Return only unique items from the collection array. 1022 * 1023 * @param string|callable|null $key 1024 * @return static 1025 */ 1026 public function unique($key = null) 1027 { 1028 if (is_null($key)) { 1029 return new static(array_unique($this->items, SORT_REGULAR)); 1030 } 1031 1032 $key = $this->valueRetriever($key); 1033 1034 $exists = []; 1035 1036 return $this->reject(function ($item) use ($key, &$exists) { 1037 if (in_array($id = $key($item), $exists)) { 1038 return true; 1039 } 1040 1041 $exists[] = $id; 1042 }); 1043 } 1044 1045 /** 1046 * Reset the keys on the underlying array. 1047 * 1048 * @return static 1049 */ 1050 public function values() 1051 { 1052 return new static(array_values($this->items)); 1053 } 1054 1055 /** 1056 * Get a value retrieving callback. 1057 * 1058 * @param string $value 1059 * @return callable 1060 */ 1061 protected function valueRetriever($value) 1062 { 1063 if ($this->useAsCallable($value)) { 1064 return $value; 1065 } 1066 1067 return function ($item) use ($value) { 1068 return data_get($item, $value); 1069 }; 1070 } 1071 1072 /** 1073 * Zip the collection together with one or more arrays. 1074 * 1075 * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]); 1076 * => [[1, 4], [2, 5], [3, 6]] 1077 * 1078 * @param mixed ...$items 1079 * @return static 1080 */ 1081 public function zip($items) 1082 { 1083 $arrayableItems = array_map(function ($items) { 1084 return $this->getArrayableItems($items); 1085 }, func_get_args()); 1086 1087 $params = array_merge([function () { 1088 return new static(func_get_args()); 1089 }, $this->items], $arrayableItems); 1090 1091 return new static(call_user_func_array('array_map', $params)); 1092 } 1093 1094 /** 1095 * Get the collection of items as a plain array. 1096 * 1097 * @return array 1098 */ 1099 public function toArray() 1100 { 1101 return array_map(function ($value) { 1102 return $value instanceof Arrayable ? $value->toArray() : $value; 1103 }, $this->items); 1104 } 1105 1106 /** 1107 * Convert the object into something JSON serializable. 1108 * 1109 * @return array 1110 */ 1111 public function jsonSerialize() 1112 { 1113 return array_map(function ($value) { 1114 if ($value instanceof JsonSerializable) { 1115 return $value->jsonSerialize(); 1116 } elseif ($value instanceof Jsonable) { 1117 return json_decode($value->toJson(), true); 1118 } elseif ($value instanceof Arrayable) { 1119 return $value->toArray(); 1120 } else { 1121 return $value; 1122 } 1123 }, $this->items); 1124 } 1125 1126 /** 1127 * Get the collection of items as JSON. 1128 * 1129 * @param int $options 1130 * @return string 1131 */ 1132 public function toJson($options = 0) 1133 { 1134 return json_encode($this->jsonSerialize(), $options); 1135 } 1136 1137 /** 1138 * Get an iterator for the items. 1139 * 1140 * @return \ArrayIterator 1141 */ 1142 public function getIterator() 1143 { 1144 return new ArrayIterator($this->items); 1145 } 1146 1147 /** 1148 * Get a CachingIterator instance. 1149 * 1150 * @param int $flags 1151 * @return \CachingIterator 1152 */ 1153 public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) 1154 { 1155 return new CachingIterator($this->getIterator(), $flags); 1156 } 1157 1158 /** 1159 * Count the number of items in the collection. 1160 * 1161 * @return int 1162 */ 1163 public function count() 1164 { 1165 return count($this->items); 1166 } 1167 1168 /** 1169 * Determine if an item exists at an offset. 1170 * 1171 * @param mixed $key 1172 * @return bool 1173 */ 1174 public function offsetExists($key) 1175 { 1176 return array_key_exists($key, $this->items); 1177 } 1178 1179 /** 1180 * Get an item at a given offset. 1181 * 1182 * @param mixed $key 1183 * @return mixed 1184 */ 1185 public function offsetGet($key) 1186 { 1187 return $this->items[$key]; 1188 } 1189 1190 /** 1191 * Set the item at a given offset. 1192 * 1193 * @param mixed $key 1194 * @param mixed $value 1195 * @return void 1196 */ 1197 public function offsetSet($key, $value) 1198 { 1199 if (is_null($key)) { 1200 $this->items[] = $value; 1201 } else { 1202 $this->items[$key] = $value; 1203 } 1204 } 1205 1206 /** 1207 * Unset the item at a given offset. 1208 * 1209 * @param string $key 1210 * @return void 1211 */ 1212 public function offsetUnset($key) 1213 { 1214 unset($this->items[$key]); 1215 } 1216 1217 /** 1218 * Convert the collection to its string representation. 1219 * 1220 * @return string 1221 */ 1222 public function __toString() 1223 { 1224 return $this->toJson(); 1225 } 1226 1227 /** 1228 * Results array of items from Collection or Arrayable. 1229 * 1230 * @param mixed $items 1231 * @return array 1232 */ 1233 protected function getArrayableItems($items) 1234 { 1235 if (is_array($items)) { 1236 return $items; 1237 } elseif ($items instanceof self) { 1238 return $items->all(); 1239 } elseif ($items instanceof Arrayable) { 1240 return $items->toArray(); 1241 } elseif ($items instanceof Jsonable) { 1242 return json_decode($items->toJson(), true); 1243 } elseif ($items instanceof JsonSerializable) { 1244 return $items->jsonSerialize(); 1245 } elseif ($items instanceof Traversable) { 1246 return iterator_to_array($items); 1247 } 1248 1249 return (array) $items; 1250 } 1251} 1252