ListKey.php 4.3 KB

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