PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/backwpup/sdk/OpenCloud/collection.php

https://bitbucket.org/cesarmedrano/cesarmedrano
PHP | 253 lines | 111 code | 16 blank | 126 comment | 8 complexity | 80218c903091708d62242eccab4808b9 MD5 | raw file
  1. <?php
  2. /**
  3. * An abstraction for working with ordered sets of objects
  4. *
  5. * @copyright 2012-2013 Rackspace Hosting, Inc.
  6. * See COPYING for licensing information
  7. *
  8. * @package phpOpenCloud
  9. * @version 1.1
  10. * @author Glen Campbell <glen.campbell@rackspace.com>
  11. */
  12. namespace OpenCloud;
  13. require_once(__DIR__.'/base.php');
  14. /**
  15. * Provides an abstraction for working with ordered sets of objects
  16. *
  17. * Collection objects are used whenever there are multiples; for example,
  18. * multiple objects in a container, or multiple servers in a service.
  19. *
  20. * @since 1.0
  21. * @author Glen Campbell <glen.campbell@rackspace.com>
  22. */
  23. class Collection extends Base {
  24. private
  25. $service,
  26. $itemclass,
  27. $itemlist=array(),
  28. $pointer=0,
  29. $sortkey,
  30. $next_page_class,
  31. $next_page_callback,
  32. $next_page_url;
  33. /**
  34. * A Collection is an array of objects
  35. *
  36. * @param Service $service - the service associated with the collection
  37. * @param string $itemclass - the Class of each item in the collection
  38. * (assumed to be the name of the factory method)
  39. * @param array $arr - the input array
  40. */
  41. public function __construct($service, $itemclass, $arr) {
  42. $this->service = $service;
  43. $this->debug('Collection:service=%s, class=%s, array=%s',
  44. get_class($service), $itemclass, print_r($arr,TRUE));
  45. $this->next_page_class = $itemclass;
  46. $p = strrpos($itemclass, '\\');
  47. if ($p !== FALSE)
  48. $this->itemclass = substr($itemclass, $p+1);
  49. else
  50. $this->itemclass = $itemclass;
  51. if (!is_array($arr))
  52. throw new \OpenCloud\CollectionError(
  53. _('Cannot create a Collection without an array'));
  54. // save the array of items
  55. $this->itemlist=$arr;
  56. }
  57. /**
  58. * Retrieves the service associated with the Collection
  59. *
  60. * @return Service
  61. */
  62. public function Service() {
  63. return $this->service;
  64. }
  65. /**
  66. * Resets the pointer to the beginning, but does NOT return the first item
  67. *
  68. * @api
  69. * @return void
  70. */
  71. public function Reset() {
  72. $this->pointer = 0;
  73. }
  74. /**
  75. * Resets the collection pointer back to the first item in the page
  76. * and returns it
  77. *
  78. * This is useful if you're only interested in the first item in the page.
  79. *
  80. * @api
  81. * @return Base the first item in the set
  82. */
  83. public function First() {
  84. $this->Reset();
  85. return $this->Next();
  86. }
  87. /**
  88. * Returns the next item in the page
  89. *
  90. * @api
  91. * @return Base the next item or FALSE if at the end of the page
  92. */
  93. public function Next() {
  94. if ($this->pointer >= count($this->itemlist))
  95. return FALSE;
  96. $class = $this->itemclass;
  97. return $this->Service()->$class($this->itemlist[$this->pointer++]);
  98. }
  99. /**
  100. * Returns the number of items in the page
  101. *
  102. * For most services, this is the total number of items. If the Collection
  103. * is paginated, however, this only returns the count of items in the
  104. * current page of data.
  105. *
  106. * @api
  107. * @return integer The number of items in the set
  108. */
  109. public function Size() {
  110. return count($this->itemlist);
  111. }
  112. /**
  113. * sorts the collection on a specified key
  114. *
  115. * Note: only top-level keys can be used as the sort key. Note that this
  116. * only sorts the data in the current page of the Collection (for
  117. * multi-page data).
  118. *
  119. * @api
  120. * @param string $keyname the name of the field to use as the sort key
  121. * @return void
  122. */
  123. public function Sort($keyname='id') {
  124. $this->sortkey = $keyname;
  125. usort($this->itemlist, array($this, 'sortCompare'));
  126. }
  127. /**
  128. * selects only specified items from the Collection
  129. *
  130. * This provides a simple form of filtering on Collections. For each item
  131. * in the collection, it calls the callback function, passing it the item.
  132. * If the callback returns `TRUE`, then the item is retained; if it returns
  133. * `FALSE`, then the item is deleted from the collection.
  134. *
  135. * Note that this should not supersede server-side filtering; the
  136. * `Collection::Select()` method requires that *all* of the data for the
  137. * Collection be retrieved from the server before the filtering is
  138. * performed; this can be very inefficient, especially for large data
  139. * sets. This method is mostly useful on smaller-sized sets.
  140. *
  141. * Example:
  142. * <code>
  143. * $services = $connection->ServiceList();
  144. * $services->Select(function($item){ return $item->region=='ORD';});
  145. * // now the $services Collection only has items from the ORD region
  146. * </code>
  147. *
  148. * `Select()` is *destructive*; that is, it actually removes entries from
  149. * the collection. For example, if you use `Select()` to find items with
  150. * the ID > 10, then use it again to find items that are <= 10, it will
  151. * return an empty list.
  152. *
  153. * @api
  154. * @param callable $testfunc a callback function that is passed each item
  155. * in turn. Note that `Select()` performs an explicit test for
  156. * `FALSE`, so functions like `strpos()` need to be cast into a
  157. * boolean value (and not just return the integer).
  158. * @returns void
  159. * @throws DomainError if callback doesn't return a boolean value
  160. */
  161. public function Select($testfunc) {
  162. foreach($this->itemlist as $index => $item) {
  163. $test = call_user_func($testfunc, $item);
  164. if (!is_bool($test))
  165. throw new DomainError(
  166. _('Callback function for Collection::Select() '.
  167. 'did not return boolean'));
  168. if ($test === FALSE)
  169. unset($this->itemlist[$index]);
  170. }
  171. }
  172. /**
  173. * returns the Collection object for the next page of results, or
  174. * FALSE if there are no more pages
  175. *
  176. * Generally, the structure for a multi-page collection will look like
  177. * this:
  178. *
  179. * $coll = $obj->Collection();
  180. * do {
  181. * while($item = $coll->Next()) {
  182. * // do something with the item
  183. * |
  184. * } while ($coll = $coll->NextPage());
  185. *
  186. * @api
  187. * @return Collection if there are more pages of results, otherwise FALSE
  188. */
  189. public function NextPage() {
  190. if (isset($this->next_page_url)) {
  191. return call_user_func(
  192. $this->next_page_callback,
  193. $this->next_page_class,
  194. $this->next_page_url);
  195. }
  196. return FALSE;
  197. }
  198. /**
  199. * for paginated collection, sets the callback function and URL for
  200. * the next page
  201. *
  202. * The callback function should have the signature:
  203. *
  204. * function Whatever($class, $url, $parent)
  205. *
  206. * and the `$url` should be the URL of the next page of results
  207. *
  208. * @param callable $callback the name of the function (or array of
  209. * object, function name)
  210. * @param string $url the URL of the next page of results
  211. * @return void
  212. */
  213. public function SetNextPageCallback($callback, $url) {
  214. $this->next_page_callback = $callback;
  215. $this->next_page_url = $url;
  216. }
  217. /********** PRIVATE METHODS **********/
  218. /**
  219. * Compares two values of sort keys
  220. */
  221. private function sortCompare($a, $b) {
  222. $key = $this->sortkey;
  223. // handle strings with strcmp()
  224. if (is_string($a->$key))
  225. return strcmp($a->$key, $b->$key);
  226. // handle others with logical comparisons
  227. if ($a->$key == $b->$key)
  228. return 0;
  229. if ($a->$key < $b->$key)
  230. return -1;
  231. else
  232. return 1;
  233. }
  234. } // class Collection