BufferedIterator.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Collection\Iterator;
  16. use Cake\Collection\Collection;
  17. use Countable;
  18. use Serializable;
  19. use SplDoublyLinkedList;
  20. /**
  21. * Creates an iterator from another iterator that will keep the results of the inner
  22. * iterator in memory, so that results don't have to be re-calculated.
  23. */
  24. class BufferedIterator extends Collection implements Countable, Serializable
  25. {
  26. /**
  27. * The in-memory cache containing results from previous iterators
  28. *
  29. * @var \SplDoublyLinkedList
  30. */
  31. protected $_buffer;
  32. /**
  33. * Points to the next record number that should be fetched
  34. *
  35. * @var int
  36. */
  37. protected $_index = 0;
  38. /**
  39. * Last record fetched from the inner iterator
  40. *
  41. * @var mixed
  42. */
  43. protected $_current;
  44. /**
  45. * Last key obtained from the inner iterator
  46. *
  47. * @var mixed
  48. */
  49. protected $_key;
  50. /**
  51. * Whether or not the internal iterator's rewind method was already
  52. * called
  53. *
  54. * @var bool
  55. */
  56. protected $_started = false;
  57. /**
  58. * Whether or not the internal iterator has reached its end.
  59. *
  60. * @var bool
  61. */
  62. protected $_finished = false;
  63. /**
  64. * Maintains an in-memory cache of the results yielded by the internal
  65. * iterator.
  66. *
  67. * @param array|\Traversable $items The items to be filtered.
  68. */
  69. public function __construct($items)
  70. {
  71. $this->_buffer = new SplDoublyLinkedList();
  72. parent::__construct($items);
  73. }
  74. /**
  75. * Returns the current key in the iterator
  76. *
  77. * @return mixed
  78. */
  79. public function key()
  80. {
  81. return $this->_key;
  82. }
  83. /**
  84. * Returns the current record in the iterator
  85. *
  86. * @return mixed
  87. */
  88. public function current()
  89. {
  90. return $this->_current;
  91. }
  92. /**
  93. * Rewinds the collection
  94. *
  95. * @return void
  96. */
  97. public function rewind()
  98. {
  99. if ($this->_index === 0 && !$this->_started) {
  100. $this->_started = true;
  101. parent::rewind();
  102. return;
  103. }
  104. $this->_index = 0;
  105. }
  106. /**
  107. * Returns whether or not the iterator has more elements
  108. *
  109. * @return bool
  110. */
  111. public function valid()
  112. {
  113. if ($this->_buffer->offsetExists($this->_index)) {
  114. $current = $this->_buffer->offsetGet($this->_index);
  115. $this->_current = $current['value'];
  116. $this->_key = $current['key'];
  117. return true;
  118. }
  119. $valid = parent::valid();
  120. if ($valid) {
  121. $this->_current = parent::current();
  122. $this->_key = parent::key();
  123. $this->_buffer->push([
  124. 'key' => $this->_key,
  125. 'value' => $this->_current
  126. ]);
  127. }
  128. $this->_finished = !$valid;
  129. return $valid;
  130. }
  131. /**
  132. * Advances the iterator pointer to the next element
  133. *
  134. * @return void
  135. */
  136. public function next()
  137. {
  138. $this->_index++;
  139. if (!$this->_finished) {
  140. parent::next();
  141. }
  142. }
  143. /**
  144. * Returns the number or items in this collection
  145. *
  146. * @return int
  147. */
  148. public function count()
  149. {
  150. if (!$this->_started) {
  151. $this->rewind();
  152. }
  153. while ($this->valid()) {
  154. $this->next();
  155. }
  156. return $this->_buffer->count();
  157. }
  158. /**
  159. * Returns a string representation of this object that can be used
  160. * to reconstruct it
  161. *
  162. * @return string
  163. */
  164. public function serialize()
  165. {
  166. if (!$this->_finished) {
  167. $this->count();
  168. }
  169. return serialize($this->_buffer);
  170. }
  171. /**
  172. * Unserializes the passed string and rebuilds the BufferedIterator instance
  173. *
  174. * @param string $buffer The serialized buffer iterator
  175. * @return void
  176. */
  177. public function unserialize($buffer)
  178. {
  179. $this->__construct([]);
  180. $this->_buffer = unserialize($buffer);
  181. $this->_started = true;
  182. $this->_finished = true;
  183. }
  184. }