ListKey.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. /*
  3. * This file is part of the Predis package.
  4. *
  5. * (c) Daniele Alessandri <suppakilla@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Predis\Collection\Iterator;
  11. use Predis\ClientInterface;
  12. use Predis\NotSupportedException;
  13. /**
  14. * Abstracts the iteration of items stored in a list by leveraging the LRANGE
  15. * command wrapped in a fully-rewindable PHP iterator.
  16. *
  17. * This iterator tries to emulate the behaviour of cursor-based iterators based
  18. * on the SCAN-family of commands introduced in Redis <= 2.8, meaning that due
  19. * to its incremental nature with multiple fetches it can only offer limited
  20. * guarantees on the returned elements because the collection can change several
  21. * times (trimmed, deleted, overwritten) during the iteration process.
  22. *
  23. * @author Daniele Alessandri <suppakilla@gmail.com>
  24. *
  25. * @link http://redis.io/commands/lrange
  26. */
  27. class ListKey implements \Iterator
  28. {
  29. protected $client;
  30. protected $count;
  31. protected $key;
  32. protected $valid;
  33. protected $fetchmore;
  34. protected $elements;
  35. protected $position;
  36. protected $current;
  37. /**
  38. * @param ClientInterface $client Client connected to Redis.
  39. * @param string $key Redis list key.
  40. * @param int $count Number of items retrieved on each fetch operation.
  41. *
  42. * @throws \InvalidArgumentException
  43. */
  44. public function __construct(ClientInterface $client, $key, $count = 10)
  45. {
  46. $this->requiredCommand($client, 'LRANGE');
  47. if ((false === $count = filter_var($count, FILTER_VALIDATE_INT)) || $count < 0) {
  48. throw new \InvalidArgumentException('The $count argument must be a positive integer.');
  49. }
  50. $this->client = $client;
  51. $this->key = $key;
  52. $this->count = $count;
  53. $this->reset();
  54. }
  55. /**
  56. * Ensures that the client instance supports the specified Redis command
  57. * required to fetch elements from the server to perform the iteration.
  58. *
  59. * @param ClientInterface $client Client connected to Redis.
  60. * @param string $commandID Command ID.
  61. *
  62. * @throws NotSupportedException
  63. */
  64. protected function requiredCommand(ClientInterface $client, $commandID)
  65. {
  66. if (!$client->getProfile()->supportsCommand($commandID)) {
  67. throw new NotSupportedException("The current profile does not support '$commandID'.");
  68. }
  69. }
  70. /**
  71. * Resets the inner state of the iterator.
  72. */
  73. protected function reset()
  74. {
  75. $this->valid = true;
  76. $this->fetchmore = true;
  77. $this->elements = array();
  78. $this->position = -1;
  79. $this->current = null;
  80. }
  81. /**
  82. * Fetches a new set of elements from the remote collection, effectively
  83. * advancing the iteration process.
  84. *
  85. * @return array
  86. */
  87. protected function executeCommand()
  88. {
  89. return $this->client->lrange($this->key, $this->position + 1, $this->position + $this->count);
  90. }
  91. /**
  92. * Populates the local buffer of elements fetched from the server during the
  93. * iteration.
  94. */
  95. protected function fetch()
  96. {
  97. $elements = $this->executeCommand();
  98. if (count($elements) < $this->count) {
  99. $this->fetchmore = false;
  100. }
  101. $this->elements = $elements;
  102. }
  103. /**
  104. * Extracts next values for key() and current().
  105. */
  106. protected function extractNext()
  107. {
  108. ++$this->position;
  109. $this->current = array_shift($this->elements);
  110. }
  111. /**
  112. * {@inheritdoc}
  113. */
  114. public function rewind()
  115. {
  116. $this->reset();
  117. $this->next();
  118. }
  119. /**
  120. * {@inheritdoc}
  121. */
  122. public function current()
  123. {
  124. return $this->current;
  125. }
  126. /**
  127. * {@inheritdoc}
  128. */
  129. public function key()
  130. {
  131. return $this->position;
  132. }
  133. /**
  134. * {@inheritdoc}
  135. */
  136. public function next()
  137. {
  138. if (!$this->elements && $this->fetchmore) {
  139. $this->fetch();
  140. }
  141. if ($this->elements) {
  142. $this->extractNext();
  143. } else {
  144. $this->valid = false;
  145. }
  146. }
  147. /**
  148. * {@inheritdoc}
  149. */
  150. public function valid()
  151. {
  152. return $this->valid;
  153. }
  154. }