PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Guzzle/Service/Resource/ResourceIterator.php

http://github.com/guzzle/guzzle
PHP | 321 lines | 134 code | 42 blank | 145 comment | 15 complexity | e4618c1b4d841f52d2c5f4f27e727c04 MD5 | raw file
  1. <?php
  2. namespace Guzzle\Service\Resource;
  3. use Guzzle\Common\AbstractHasDispatcher;
  4. use Guzzle\Service\Command\CommandInterface;
  5. /**
  6. * {@inheritdoc}
  7. */
  8. abstract class ResourceIterator extends AbstractHasDispatcher implements ResourceIteratorInterface
  9. {
  10. /**
  11. * @var CommandInterface Command used to send requests
  12. */
  13. protected $command;
  14. /**
  15. * @var CommandInterface First sent command
  16. */
  17. protected $originalCommand;
  18. /**
  19. * @var array Currently loaded resources
  20. */
  21. protected $resources;
  22. /**
  23. * @var int Total number of resources that have been retrieved
  24. */
  25. protected $retrievedCount = 0;
  26. /**
  27. * @var int Total number of resources that have been iterated
  28. */
  29. protected $iteratedCount = 0;
  30. /**
  31. * @var string NextToken/Marker for a subsequent request
  32. */
  33. protected $nextToken = false;
  34. /**
  35. * @var int Maximum number of resources to fetch per request
  36. */
  37. protected $pageSize;
  38. /**
  39. * @var int Maximum number of resources to retrieve in total
  40. */
  41. protected $limit;
  42. /**
  43. * @var int Number of requests sent
  44. */
  45. protected $requestCount = 0;
  46. /**
  47. * @var array Initial data passed to the constructor
  48. */
  49. protected $data = array();
  50. /**
  51. * @var bool Whether or not the current value is known to be invalid. This
  52. * is set for example when a senRequest() method returns 0 resources.
  53. */
  54. protected $invalid;
  55. /**
  56. * {@inheritdoc}
  57. */
  58. public static function getAllEvents()
  59. {
  60. return array(
  61. // About to issue another command to get more results
  62. 'resource_iterator.before_send',
  63. // Issued another command to get more results
  64. 'resource_iterator.after_send'
  65. );
  66. }
  67. /**
  68. * This should only be invoked by a {@see ClientInterface} object.
  69. *
  70. * @param CommandInterface $command Initial command used for iteration
  71. *
  72. * @param array $data Associative array of additional parameters.
  73. * You may specify any number of custom options for an iterator. Among
  74. * these options, you may also specify the following values:
  75. *
  76. * limit: Attempt to limit the maximum number of resources to this amount
  77. * page_size: Attempt to retrieve this number of resources per request
  78. */
  79. public function __construct(CommandInterface $command, array $data = array())
  80. {
  81. // Clone the command to keep track of the originating command for rewind
  82. $this->originalCommand = $command;
  83. // Parse options from the array of options
  84. $this->data = $data;
  85. $this->limit = array_key_exists('limit', $data) ? $data['limit'] : 0;
  86. $this->pageSize = array_key_exists('page_size', $data) ? $data['page_size'] : false;
  87. }
  88. /**
  89. * Get all of the resources as an array (be careful as this could issue a
  90. * large number of requests if no limit is specified)
  91. *
  92. * @return array
  93. */
  94. public function toArray()
  95. {
  96. return iterator_to_array($this, false);
  97. }
  98. /**
  99. * {@inheritdoc}
  100. */
  101. public function setLimit($limit)
  102. {
  103. $this->limit = $limit;
  104. $this->resetState();
  105. return $this;
  106. }
  107. /**
  108. * {@inheritdoc}
  109. */
  110. public function setPageSize($pageSize)
  111. {
  112. $this->pageSize = $pageSize;
  113. $this->resetState();
  114. return $this;
  115. }
  116. /**
  117. * Get an option from the iterator
  118. *
  119. * @param string $key Key of the option to retrieve
  120. *
  121. * @return mixed|null Returns NULL if not set or the value if set
  122. */
  123. public function get($key)
  124. {
  125. return array_key_exists($key, $this->data) ? $this->data[$key] : null;
  126. }
  127. /**
  128. * Set an option on the iterator
  129. *
  130. * @param string $key Key of the option to set
  131. * @param mixed $value Value to set for the option
  132. *
  133. * @return ResourceIterator
  134. */
  135. public function set($key, $value)
  136. {
  137. $this->data[$key] = $value;
  138. return $this;
  139. }
  140. /**
  141. * Return the current element.
  142. *
  143. * @return mixed Returns the current element.
  144. */
  145. public function current()
  146. {
  147. return $this->resources ? current($this->resources) : false;
  148. }
  149. /**
  150. * Return the key of the current element.
  151. *
  152. * @return mixed
  153. */
  154. public function key()
  155. {
  156. return max(0, $this->iteratedCount - 1);
  157. }
  158. /**
  159. * Return the total number of items that have been retrieved thus far.
  160. *
  161. * @return int
  162. */
  163. public function count()
  164. {
  165. return $this->retrievedCount;
  166. }
  167. /**
  168. * Get the total number of requests sent
  169. *
  170. * @return int
  171. */
  172. public function getRequestCount()
  173. {
  174. return $this->requestCount;
  175. }
  176. /**
  177. * Rewind the Iterator to the first element and send the original command
  178. */
  179. public function rewind()
  180. {
  181. // Use the original command
  182. $this->command = clone $this->originalCommand;
  183. $this->resetState();
  184. $this->next();
  185. }
  186. /**
  187. * Check if there is a current element after calls to rewind() or next().
  188. *
  189. * @return bool Returns TRUE if the current element is valid or FALSE
  190. */
  191. public function valid()
  192. {
  193. return !$this->invalid && (!$this->resources || $this->current() || $this->nextToken)
  194. && (!$this->limit || $this->iteratedCount < $this->limit + 1);
  195. }
  196. /**
  197. * Move forward to next element and may trigger subsequent requests
  198. */
  199. public function next()
  200. {
  201. $this->iteratedCount++;
  202. // Check if a new set of resources needs to be retrieved
  203. $sendRequest = false;
  204. if (!$this->resources) {
  205. $sendRequest = true;
  206. } else {
  207. // iterate over the internal array
  208. $current = next($this->resources);
  209. $sendRequest = $current === false && $this->nextToken && (!$this->limit || $this->iteratedCount < $this->limit + 1);
  210. }
  211. if ($sendRequest) {
  212. $this->dispatch('resource_iterator.before_send', array(
  213. 'iterator' => $this,
  214. 'resources' => $this->resources
  215. ));
  216. // Get a new command object from the original command
  217. $this->command = clone $this->originalCommand;
  218. // Send a request and retrieve the newly loaded resources
  219. $this->resources = $this->sendRequest();
  220. $this->requestCount++;
  221. // If no resources were found, then the last request was not needed
  222. // and iteration must stop
  223. if (empty($this->resources)) {
  224. $this->invalid = true;
  225. } else {
  226. // Add to the number of retrieved resources
  227. $this->retrievedCount += count($this->resources);
  228. // Ensure that we rewind to the beginning of the array
  229. reset($this->resources);
  230. }
  231. $this->dispatch('resource_iterator.after_send', array(
  232. 'iterator' => $this,
  233. 'resources' => $this->resources
  234. ));
  235. }
  236. }
  237. /**
  238. * Retrieve the NextToken that can be used in other iterators.
  239. *
  240. * @return string Returns a NextToken
  241. */
  242. public function getNextToken()
  243. {
  244. return $this->nextToken;
  245. }
  246. /**
  247. * Returns the value that should be specified for the page size for
  248. * a request that will maintain any hard limits, but still honor the
  249. * specified pageSize if the number of items retrieved + pageSize < hard
  250. * limit
  251. *
  252. * @return int Returns the page size of the next request.
  253. */
  254. protected function calculatePageSize()
  255. {
  256. if ($this->limit && $this->iteratedCount + $this->pageSize > $this->limit) {
  257. return 1 + ($this->limit - $this->iteratedCount);
  258. }
  259. return (int) $this->pageSize;
  260. }
  261. /**
  262. * Reset the internal state of the iterator without triggering a rewind()
  263. */
  264. protected function resetState()
  265. {
  266. $this->iteratedCount = 0;
  267. $this->retrievedCount = 0;
  268. $this->nextToken = false;
  269. $this->resources = null;
  270. $this->invalid = false;
  271. }
  272. /**
  273. * Send a request to retrieve the next page of results.
  274. * Hook for subclasses to implement.
  275. *
  276. * @return array Returns the newly loaded resources
  277. */
  278. abstract protected function sendRequest();
  279. }