ListKey.php 4.3 KB

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