Iterator.php 5.6 KB

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