Collection.php 9.6 KB

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