ListKey.php 4.2 KB

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