Iterator.php 5.6 KB

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