ListKey.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. * @link http://redis.io/commands/lrange
  27. */
  28. class ListKey implements Iterator
  29. {
  30. protected $client;
  31. protected $count;
  32. protected $key;
  33. protected $valid;
  34. protected $fetchmore;
  35. protected $elements;
  36. protected $position;
  37. protected $current;
  38. /**
  39. * @param ClientInterface $client Client connected to Redis.
  40. * @param string $key Redis list key.
  41. * @param int $count Number of items retrieved on each fetch operation.
  42. */
  43. public function __construct(ClientInterface $client, $key, $count = 10)
  44. {
  45. $this->requiredCommand($client, 'LRANGE');
  46. if ((false === $count = filter_var($count, FILTER_VALIDATE_INT)) || $count < 0) {
  47. throw new InvalidArgumentException(
  48. 'The $count argument must be a positive integer.'
  49. );
  50. }
  51. $this->client = $client;
  52. $this->key = $key;
  53. $this->count = $count;
  54. $this->reset();
  55. }
  56. /**
  57. * Ensures that the client instance supports the specified Redis command
  58. * required to fetch elements from the server to perform the iteration.
  59. *
  60. * @param ClientInterface Client connected to Redis.
  61. * @param string $commandID Command ID.
  62. */
  63. protected function requiredCommand(ClientInterface $client, $commandID)
  64. {
  65. if (!$client->getProfile()->supportsCommand($commandID)) {
  66. throw new NotSupportedException(
  67. "The specified server profile does not support the `$commandID` command."
  68. );
  69. }
  70. }
  71. /**
  72. * Resets the inner state of the iterator.
  73. */
  74. protected function reset()
  75. {
  76. $this->valid = true;
  77. $this->fetchmore = true;
  78. $this->elements = array();
  79. $this->position = -1;
  80. $this->current = null;
  81. }
  82. /**
  83. * Fetches a new set of elements from the remote collection, effectively
  84. * advancing the iteration process.
  85. *
  86. * @return array
  87. */
  88. protected function executeCommand()
  89. {
  90. return $this->client->lrange($this->key, $this->position + 1, $this->position + $this->count);
  91. }
  92. /**
  93. * Populates the local buffer of elements fetched from the server during the
  94. * iteration.
  95. */
  96. protected function fetch()
  97. {
  98. $elements = $this->executeCommand();
  99. if (count($elements) < $this->count) {
  100. $this->fetchmore = false;
  101. }
  102. $this->elements = $elements;
  103. }
  104. /**
  105. * Extracts next values for key() and current().
  106. */
  107. protected function extractNext()
  108. {
  109. $this->position++;
  110. $this->current = array_shift($this->elements);
  111. }
  112. /**
  113. * {@inheritdoc}
  114. */
  115. public function rewind()
  116. {
  117. $this->reset();
  118. $this->next();
  119. }
  120. /**
  121. * {@inheritdoc}
  122. */
  123. public function current()
  124. {
  125. return $this->current;
  126. }
  127. /**
  128. * {@inheritdoc}
  129. */
  130. public function key()
  131. {
  132. return $this->position;
  133. }
  134. /**
  135. * {@inheritdoc}
  136. */
  137. public function next()
  138. {
  139. if (!$this->elements && $this->fetchmore) {
  140. $this->fetch();
  141. }
  142. if ($this->elements) {
  143. $this->extractNext();
  144. } else {
  145. $this->valid = false;
  146. }
  147. }
  148. /**
  149. * {@inheritdoc}
  150. */
  151. public function valid()
  152. {
  153. return $this->valid;
  154. }
  155. }