Iterator.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. /**
  3. * @package Grav.Common
  4. *
  5. * @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Common;
  9. use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
  10. use RocketTheme\Toolbox\ArrayTraits\Iterator as ArrayIterator;
  11. use RocketTheme\Toolbox\ArrayTraits\Constructor;
  12. use RocketTheme\Toolbox\ArrayTraits\Countable;
  13. use RocketTheme\Toolbox\ArrayTraits\Export;
  14. use RocketTheme\Toolbox\ArrayTraits\Serializable;
  15. class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
  16. {
  17. use Constructor, ArrayAccessWithGetters, ArrayIterator, Countable, Serializable, Export;
  18. /**
  19. * @var array
  20. */
  21. protected $items = [];
  22. /**
  23. * Convert function calls for the existing keys into their values.
  24. *
  25. * @param string $key
  26. * @param mixed $args
  27. *
  28. * @return mixed
  29. */
  30. public function __call($key, $args)
  31. {
  32. return (isset($this->items[$key])) ? $this->items[$key] : null;
  33. }
  34. /**
  35. * Clone the iterator.
  36. */
  37. public function __clone()
  38. {
  39. foreach ($this as $key => $value) {
  40. if (is_object($value)) {
  41. $this->$key = clone $this->$key;
  42. }
  43. }
  44. }
  45. /**
  46. * Convents iterator to a comma separated list.
  47. *
  48. * @return string
  49. */
  50. public function __toString()
  51. {
  52. return implode(',', $this->items);
  53. }
  54. /**
  55. * Remove item from the list.
  56. *
  57. * @param $key
  58. */
  59. public function remove($key)
  60. {
  61. $this->offsetUnset($key);
  62. }
  63. /**
  64. * Return previous item.
  65. *
  66. * @return mixed
  67. */
  68. public function prev()
  69. {
  70. return prev($this->items);
  71. }
  72. /**
  73. * Return nth item.
  74. *
  75. * @param int $key
  76. *
  77. * @return mixed|bool
  78. */
  79. public function nth($key)
  80. {
  81. $items = array_keys($this->items);
  82. return (isset($items[$key])) ? $this->offsetGet($items[$key]) : false;
  83. }
  84. /**
  85. * Get the first item
  86. *
  87. * @return mixed
  88. */
  89. public function first()
  90. {
  91. $items = array_keys($this->items);
  92. return $this->offsetGet(array_shift($items));
  93. }
  94. /**
  95. * Get the last item
  96. *
  97. * @return mixed
  98. */
  99. public function last()
  100. {
  101. $items = array_keys($this->items);
  102. return $this->offsetGet(array_pop($items));
  103. }
  104. /**
  105. * Reverse the Iterator
  106. *
  107. * @return $this
  108. */
  109. public function reverse()
  110. {
  111. $this->items = array_reverse($this->items);
  112. return $this;
  113. }
  114. /**
  115. * @param mixed $needle Searched value.
  116. *
  117. * @return string|bool Key if found, otherwise false.
  118. */
  119. public function indexOf($needle)
  120. {
  121. foreach (array_values($this->items) as $key => $value) {
  122. if ($value === $needle) {
  123. return $key;
  124. }
  125. }
  126. return false;
  127. }
  128. /**
  129. * Shuffle items.
  130. *
  131. * @return $this
  132. */
  133. public function shuffle()
  134. {
  135. $keys = array_keys($this->items);
  136. shuffle($keys);
  137. $new = [];
  138. foreach ($keys as $key) {
  139. $new[$key] = $this->items[$key];
  140. }
  141. $this->items = $new;
  142. return $this;
  143. }
  144. /**
  145. * Slice the list.
  146. *
  147. * @param int $offset
  148. * @param int $length
  149. *
  150. * @return $this
  151. */
  152. public function slice($offset, $length = null)
  153. {
  154. $this->items = array_slice($this->items, $offset, $length);
  155. return $this;
  156. }
  157. /**
  158. * Pick one or more random entries.
  159. *
  160. * @param int $num Specifies how many entries should be picked.
  161. *
  162. * @return $this
  163. */
  164. public function random($num = 1)
  165. {
  166. if ($num > count($this->items)) {
  167. $num = count($this->items);
  168. }
  169. $this->items = array_intersect_key($this->items, array_flip((array)array_rand($this->items, $num)));
  170. return $this;
  171. }
  172. /**
  173. * Append new elements to the list.
  174. *
  175. * @param array|Iterator $items Items to be appended. Existing keys will be overridden with the new values.
  176. *
  177. * @return $this
  178. */
  179. public function append($items)
  180. {
  181. if ($items instanceof static) {
  182. $items = $items->toArray();
  183. }
  184. $this->items = array_merge($this->items, (array)$items);
  185. return $this;
  186. }
  187. /**
  188. * Filter elements from the list
  189. *
  190. * @param callable|null $callback A function the receives ($value, $key) and must return a boolean to indicate
  191. * filter status
  192. *
  193. * @return $this
  194. */
  195. public function filter(callable $callback = null)
  196. {
  197. foreach ($this->items as $key => $value) {
  198. if (
  199. ($callback && !call_user_func($callback, $value, $key)) ||
  200. (!$callback && !(bool)$value)
  201. ) {
  202. unset($this->items[$key]);
  203. }
  204. }
  205. return $this;
  206. }
  207. /**
  208. * Sorts elements from the list and returns a copy of the list in the proper order
  209. *
  210. * @param callable|null $callback
  211. *
  212. * @param bool $desc
  213. *
  214. * @return $this|array
  215. * @internal param bool $asc
  216. *
  217. */
  218. public function sort(callable $callback = null, $desc = false)
  219. {
  220. if (!$callback || !is_callable($callback)) {
  221. return $this;
  222. }
  223. $items = $this->items;
  224. uasort($items, $callback);
  225. return !$desc ? $items : array_reverse($items, true);
  226. }
  227. }