1: <?php namespace Illuminate\Support;
2:
3: use Closure;
4: use Countable;
5: use ArrayAccess;
6: use ArrayIterator;
7: use IteratorAggregate;
8: use Illuminate\Support\Contracts\JsonableInterface;
9: use Illuminate\Support\Contracts\ArrayableInterface;
10:
11: class Collection implements ArrayAccess, ArrayableInterface, Countable, IteratorAggregate, JsonableInterface {
12:
13: /**
14: * The items contained in the collection.
15: *
16: * @var array
17: */
18: protected $items = array();
19:
20: /**
21: * Create a new collection.
22: *
23: * @param array $items
24: * @return void
25: */
26: public function __construct(array $items = array())
27: {
28: $this->items = $items;
29: }
30:
31: /**
32: * Create a new collection instance if the value isn't one already.
33: *
34: * @param mixed $items
35: * @return \Illuminate\Support\Collection
36: */
37: public static function make($items)
38: {
39: if (is_null($items)) return new static;
40:
41: if ($items instanceof Collection) return $items;
42:
43: return new static(is_array($items) ? $items : array($items));
44: }
45:
46: /**
47: * Determine if an item exists in the collection by key.
48: *
49: * @param mixed $key
50: * @return bool
51: */
52: public function has($key)
53: {
54: return array_key_exists($key, $this->items);
55: }
56:
57: /**
58: * Get an item from the collection by key.
59: *
60: * @param mixed $key
61: * @param mixed $default
62: * @return mixed
63: */
64: public function get($key, $default = null)
65: {
66: if (array_key_exists($key, $this->items))
67: {
68: return $this->items[$key];
69: }
70:
71: return value($default);
72: }
73:
74: /**
75: * Get all of the items in the collection.
76: *
77: * @return array
78: */
79: public function all()
80: {
81: return $this->items;
82: }
83:
84: /**
85: * Put an item in the collection by key.
86: *
87: * @param mixed $key
88: * @param mixed $value
89: * @return void
90: */
91: public function put($key, $value)
92: {
93: $this->items[$key] = $value;
94: }
95:
96: /**
97: * Get the first item from the collection.
98: *
99: * @return mixed|null
100: */
101: public function first()
102: {
103: return count($this->items) > 0 ? reset($this->items) : null;
104: }
105:
106: /**
107: * Get the last item from the collection.
108: *
109: * @return mixed|null
110: */
111: public function last()
112: {
113: return count($this->items) > 0 ? end($this->items) : null;
114: }
115:
116: /**
117: * Get and remove the first item from the collection.
118: *
119: * @return mixed|null
120: */
121: public function shift()
122: {
123: return array_shift($this->items);
124: }
125:
126: /**
127: * Push an item onto the beginning of the collection.
128: *
129: * @param mixed $value
130: * @return void
131: */
132: public function push($value)
133: {
134: array_unshift($this->items, $value);
135: }
136:
137: /**
138: * Get and remove the last item from the collection.
139: *
140: * @return mixed|null
141: */
142: public function pop()
143: {
144: return array_pop($this->items);
145: }
146:
147: /**
148: * Remove an item from the collection by key.
149: *
150: * @param mixed $key
151: * @return void
152: */
153: public function forget($key)
154: {
155: unset($this->items[$key]);
156: }
157:
158: /**
159: * Execute a callback over each item.
160: *
161: * @param Closure $callback
162: * @return \Illuminate\Support\Collection
163: */
164: public function each(Closure $callback)
165: {
166: array_map($callback, $this->items);
167:
168: return $this;
169: }
170:
171: /**
172: * Run a map over each of the items.
173: *
174: * @param Closure $callback
175: * @return array
176: */
177: public function map(Closure $callback)
178: {
179: return new static(array_map($callback, $this->items));
180: }
181:
182: /**
183: * Run a filter over each of the items.
184: *
185: * @param Closure $callback
186: * @return \Illuminate\Support\Collection
187: */
188: public function filter(Closure $callback)
189: {
190: return new static(array_filter($this->items, $callback));
191: }
192:
193: /**
194: * Sort through each item with a callback.
195: *
196: * @param Closure $callback
197: * @return \Illuminate\Support\Collection
198: */
199: public function sort(Closure $callback)
200: {
201: uasort($this->items, $callback);
202:
203: return $this;
204: }
205:
206: /**
207: * Sort the collection using the given Closure.
208: *
209: * @param \Closure $callback
210: * @return \Illuminate\Support\Collection
211: */
212: public function sortBy(Closure $callback)
213: {
214: $results = array();
215:
216: // First we will loop through the items and get the comparator from a callback
217: // function which we were given. Then, we will sort the returned values and
218: // and grab the corresponding values for the sorted keys from this array.
219: foreach ($this->items as $key => $value)
220: {
221: $results[$key] = $callback($value);
222: }
223:
224: asort($results);
225:
226: // Once we have sorted all of the keys in the array, we will loop through them
227: // and grab the corresponding model so we can set the underlying items list
228: // to the sorted version. Then we'll just return the collection instance.
229: foreach (array_keys($results) as $key)
230: {
231: $results[$key] = $this->items[$key];
232: }
233:
234: $this->items = $results;
235:
236: return $this;
237: }
238:
239: /**
240: * Reverse items order.
241: *
242: * @return \Illuminate\Support\Collection
243: */
244: public function reverse()
245: {
246: return new static(array_reverse($this->items));
247: }
248:
249: /**
250: * Reset the keys on the underlying array.
251: *
252: * @return \Illuminate\Support\Collection
253: */
254: public function values()
255: {
256: $this->items = array_values($this->items);
257:
258: return $this;
259: }
260:
261: /**
262: * Fetch a nested element of the collection.
263: *
264: * @param string $key
265: * @return \Illuminate\Support\Collection
266: */
267: public function fetch($key)
268: {
269: return new static(array_fetch($this->items, $key));
270: }
271:
272: /**
273: * Get a flattened array of the items in the collection.
274: *
275: * @return array
276: */
277: public function flatten()
278: {
279: return new static(array_flatten($this->items));
280: }
281:
282: /**
283: * Collapse the collection items into a single array.
284: *
285: * @return \Illuminate\Support\Collection
286: */
287: public function collapse()
288: {
289: $results = array();
290:
291: foreach ($this->items as $values)
292: {
293: $results = array_merge($results, $values);
294: }
295:
296: return new static($results);
297: }
298:
299: /**
300: * Merge items with the collection items.
301: *
302: * @param \Illuminate\Support\Collection|\Illuminate\Support\Contracts\ArrayableInterface|array
303: * @return \Illuminate\Support\Collection
304: */
305: public function merge($items)
306: {
307: if ($items instanceof Collection)
308: {
309: $items = $items->all();
310: }
311: elseif ($items instanceof ArrayableInterface)
312: {
313: $items = $items->toArray();
314: }
315:
316: $results = array_merge($this->items, $items);
317:
318: return new static($results);
319: }
320:
321: /**
322: * Slice the underlying collection array.
323: *
324: * @param int $offset
325: * @param int $length
326: * @param bool $preserveKeys
327: * @return \Illuminate\Support\Collection
328: */
329: public function slice($offset, $length = null, $preserveKeys = false)
330: {
331: return new static(array_slice($this->items, $offset, $length, $preserveKeys));
332: }
333:
334: /**
335: * Get an array with the values of a given key.
336: *
337: * @param string $value
338: * @param string $key
339: * @return array
340: */
341: public function lists($value, $key = null)
342: {
343: $results = array();
344:
345: foreach ($this->items as $item)
346: {
347: $itemValue = is_object($item) ? $item->{$value} : $item[$value];
348:
349: // If the key is "null", we will just append the value to the array and keep
350: // looping. Otherwise we will key the array using the value of the key we
351: // received from the developer. Then we'll return the final array form.
352: if (is_null($key))
353: {
354: $results[] = $itemValue;
355: }
356: else
357: {
358: $itemKey = is_object($item) ? $item->{$key} : $item[$key];
359:
360: $results[$itemKey] = $itemValue;
361: }
362: }
363:
364: return $results;
365: }
366:
367: /**
368: * Concatenate values of a given key as a string.
369: *
370: * @param string $value
371: * @param string $glue
372: * @return string
373: */
374: public function implode($value, $glue = null)
375: {
376: if (is_null($glue)) return implode($this->lists($value));
377:
378: return implode($glue, $this->lists($value));
379: }
380:
381: /**
382: * Determine if the collection is empty or not.
383: *
384: * @return bool
385: */
386: public function isEmpty()
387: {
388: return empty($this->items);
389: }
390:
391: /**
392: * Get the collection of items as a plain array.
393: *
394: * @return array
395: */
396: public function toArray()
397: {
398: return array_map(function($value)
399: {
400: return $value instanceof ArrayableInterface ? $value->toArray() : $value;
401:
402: }, $this->items);
403: }
404:
405: /**
406: * Get the collection of items as JSON.
407: *
408: * @param int $options
409: * @return string
410: */
411: public function toJson($options = 0)
412: {
413: return json_encode($this->toArray(), $options);
414: }
415:
416: /**
417: * Get an iterator for the items.
418: *
419: * @return ArrayIterator
420: */
421: public function getIterator()
422: {
423: return new ArrayIterator($this->items);
424: }
425:
426: /**
427: * Count the number of items in the collection.
428: *
429: * @return int
430: */
431: public function count()
432: {
433: return count($this->items);
434: }
435:
436: /**
437: * Determine if an item exists at an offset.
438: *
439: * @param mixed $key
440: * @return bool
441: */
442: public function offsetExists($key)
443: {
444: return array_key_exists($key, $this->items);
445: }
446:
447: /**
448: * Get an item at a given offset.
449: *
450: * @param mixed $key
451: * @return mixed
452: */
453: public function offsetGet($key)
454: {
455: return $this->items[$key];
456: }
457:
458: /**
459: * Set the item at a given offset.
460: *
461: * @param mixed $key
462: * @param mixed $value
463: * @return void
464: */
465: public function offsetSet($key, $value)
466: {
467: if (is_null($key))
468: {
469: $this->items[] = $value;
470: }
471: else
472: {
473: $this->items[$key] = $value;
474: }
475: }
476:
477: /**
478: * Unset the item at a given offset.
479: *
480: * @param string $key
481: * @return void
482: */
483: public function offsetUnset($key)
484: {
485: unset($this->items[$key]);
486: }
487:
488: /**
489: * Convert the collection to its string representation.
490: *
491: * @return string
492: */
493: public function __toString()
494: {
495: return $this->toJson();
496: }
497:
498: }
499: