PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/jelly/core/collection.php

https://github.com/leth/kohana-jelly
PHP | 250 lines | 100 code | 26 blank | 124 comment | 4 complexity | 9fa93cdc9418461eb0813e6e4bbd93df MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Jelly_Collection encapsulates a Database_Result object. It has the exact same API.
  4. *
  5. * It offers a few special features that make it useful:
  6. *
  7. * * Only one model is instantiated for the whole result set, which
  8. * is significantly faster in terms of performance.
  9. * * It is easily extensible, so things like polymorphism and
  10. * recursive result sets can be easily implemented.
  11. *
  12. * Jelly_Collection likes to know what model its result set is related to,
  13. * though it's not required. Some features may disappear, however, if
  14. * it doesn't know the model it's working with.
  15. *
  16. * @package Jelly
  17. */
  18. abstract class Jelly_Core_Collection implements Iterator, Countable, SeekableIterator, ArrayAccess {
  19. /**
  20. * @var Jelly_Meta The current meta object, based on the model we're returning
  21. */
  22. protected $_meta = NULL;
  23. /**
  24. * @var Jelly_Model The current class we're placing results into
  25. */
  26. protected $_model = NULL;
  27. /**
  28. * @var Jelly_Collection|array|mixed The current result set
  29. */
  30. protected $_result = NULL;
  31. /**
  32. * Tracks a database result
  33. *
  34. * @param mixed $model
  35. * @param mixed $result
  36. */
  37. public function __construct($result, $model = NULL)
  38. {
  39. $this->_result = $result;
  40. // Load our default model
  41. if ($model AND Jelly::meta($model))
  42. {
  43. $this->_model = ($model instanceof Jelly_Model) ? $model : new $model;
  44. $this->_meta = $this->_model->meta();
  45. }
  46. }
  47. /**
  48. * Converts MySQL Results to Cached Results, since MySQL resources are not serializable.
  49. *
  50. * @return array
  51. */
  52. public function __sleep()
  53. {
  54. if ( ! $this->_result instanceof Database_Result_Cached)
  55. {
  56. $this->_result = new Database_Result_Cached($this->_result->as_array(), '');
  57. }
  58. return array_keys(get_object_vars($this));
  59. }
  60. /**
  61. * Returns a string representation of the collection.
  62. *
  63. * @return string
  64. */
  65. public function __toString()
  66. {
  67. return get_class($this).': '.Jelly::model_name($this->_model).' ('.$this->count().')';
  68. }
  69. /**
  70. * Returns the collection's meta object, if it exists.
  71. *
  72. * @return Jelly_Meta
  73. */
  74. public function meta()
  75. {
  76. return $this->_meta;
  77. }
  78. /**
  79. * Return all of the rows in the result as an array.
  80. *
  81. * @param string $key column for associative keys
  82. * @param string $value column for values
  83. * @return array
  84. */
  85. public function as_array($key = NULL, $value = NULL)
  86. {
  87. return $this->_result->as_array($key, $value);
  88. }
  89. /**
  90. * Implementation of the Iterator interface
  91. * @return Jelly_Collection
  92. */
  93. public function rewind()
  94. {
  95. $this->_result->rewind();
  96. return $this;
  97. }
  98. /**
  99. * Implementation of the Iterator interface
  100. *
  101. * @return Jelly_Model|array
  102. */
  103. public function current()
  104. {
  105. // Database_Result causes errors if you call current()
  106. // on an object with no results, so we check first.
  107. if ($this->_result->count())
  108. {
  109. $result = $this->_result->current();
  110. }
  111. else
  112. {
  113. $result = array();
  114. }
  115. return $this->_load($result);
  116. }
  117. /**
  118. * Implementation of the Iterator interface
  119. * @return int
  120. */
  121. public function key()
  122. {
  123. return $this->_result->key();
  124. }
  125. /**
  126. * Implementation of the Iterator interface
  127. * @return Jelly_Collection
  128. */
  129. public function next()
  130. {
  131. $this->_result->next();
  132. return $this;
  133. }
  134. /**
  135. * Implementation of the Iterator interface
  136. *
  137. * @return boolean
  138. */
  139. public function valid()
  140. {
  141. return $this->_result->valid();
  142. }
  143. /**
  144. * Implementation of the Countable interface
  145. *
  146. * @return int
  147. */
  148. public function count()
  149. {
  150. return $this->_result->count();
  151. }
  152. /**
  153. * Implementation of SeekableIterator
  154. *
  155. * @param mixed $offset
  156. * @return boolean
  157. */
  158. public function seek($offset)
  159. {
  160. return $this->_result->seek($offset);
  161. }
  162. /**
  163. * ArrayAccess: offsetExists
  164. *
  165. * @param mixed $offset
  166. * @return boolean
  167. */
  168. public function offsetExists($offset)
  169. {
  170. return $this->_result->offsetExists($offset);
  171. }
  172. /**
  173. * ArrayAccess: offsetGet
  174. *
  175. * @param mixed $offset
  176. * @param bool $object
  177. * @return array|Jelly_Model
  178. */
  179. public function offsetGet($offset, $object = TRUE)
  180. {
  181. return $this->_load($this->_result->offsetGet($offset), $object);
  182. }
  183. /**
  184. * ArrayAccess: offsetSet
  185. *
  186. * @throws Kohana_Exception
  187. * @param mixed $offset
  188. * @param mixed $value
  189. * @return void
  190. */
  191. final public function offsetSet($offset, $value)
  192. {
  193. throw new Kohana_Exception('Jelly results are read-only');
  194. }
  195. /**
  196. * ArrayAccess: offsetUnset
  197. *
  198. * @throws Kohana_Exception
  199. * @param mixed $offset
  200. * @return void
  201. */
  202. final public function offsetUnset($offset)
  203. {
  204. throw new Kohana_Exception('Jelly results are read-only');
  205. }
  206. /**
  207. * Loads values into the model.
  208. *
  209. * @param array $values
  210. * @return Jelly_Model|array
  211. */
  212. protected function _load($values)
  213. {
  214. if ($this->_model)
  215. {
  216. $model = clone $this->_model;
  217. // Don't return models when we don't have one
  218. return $values
  219. ? $model->load_values($values)
  220. : $model->clear();
  221. }
  222. return $values;
  223. }
  224. } // End Jelly_Core_Collection