Iterator.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. /**
  3. * @package Grav\Common
  4. *
  5. * @copyright Copyright (C) 2015 - 2019 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 $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 string $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. $count = \count($this->items);
  167. if ($num > $count) {
  168. $num = $count;
  169. }
  170. $this->items = array_intersect_key($this->items, array_flip((array)array_rand($this->items, $num)));
  171. return $this;
  172. }
  173. /**
  174. * Append new elements to the list.
  175. *
  176. * @param array|Iterator $items Items to be appended. Existing keys will be overridden with the new values.
  177. *
  178. * @return $this
  179. */
  180. public function append($items)
  181. {
  182. if ($items instanceof static) {
  183. $items = $items->toArray();
  184. }
  185. $this->items = array_merge($this->items, (array)$items);
  186. return $this;
  187. }
  188. /**
  189. * Filter elements from the list
  190. *
  191. * @param callable|null $callback A function the receives ($value, $key) and must return a boolean to indicate
  192. * filter status
  193. *
  194. * @return $this
  195. */
  196. public function filter(callable $callback = null)
  197. {
  198. foreach ($this->items as $key => $value) {
  199. if (
  200. (!$callback && !(bool)$value) ||
  201. ($callback && !$callback($value, $key))
  202. ) {
  203. unset($this->items[$key]);
  204. }
  205. }
  206. return $this;
  207. }
  208. /**
  209. * Sorts elements from the list and returns a copy of the list in the proper order
  210. *
  211. * @param callable|null $callback
  212. *
  213. * @param bool $desc
  214. *
  215. * @return $this|array
  216. * @internal param bool $asc
  217. *
  218. */
  219. public function sort(callable $callback = null, $desc = false)
  220. {
  221. if (!$callback || !\is_callable($callback)) {
  222. return $this;
  223. }
  224. $items = $this->items;
  225. uasort($items, $callback);
  226. return !$desc ? $items : array_reverse($items, true);
  227. }
  228. }