PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/lithium/data/Collection.php

https://bitbucket.org/thesyncim/front-biarq
PHP | 338 lines | 125 code | 36 blank | 177 comment | 16 complexity | a060502211f0c43d4f14db45e40825b2 MD5 | raw file
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2011, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\data;
  9. /**
  10. * The `Collection` class extends the generic `lithium\util\Collection` class to provide
  11. * context-specific features for working with sets of data persisted by a backend data store. This
  12. * is a general abstraction that operates on arbitrary sets of data from either relational or
  13. * non-relational data stores.
  14. */
  15. abstract class Collection extends \lithium\util\Collection {
  16. /**
  17. * A reference to this object's parent `Document` object.
  18. *
  19. * @var object
  20. */
  21. protected $_parent = null;
  22. /**
  23. * If this `Collection` instance has a parent document (see `$_parent`), this value indicates
  24. * the key name of the parent document that contains it.
  25. *
  26. * @see lithium\data\Collection::$_parent
  27. * @var string
  28. */
  29. protected $_pathKey = null;
  30. /**
  31. * The fully-namespaced class name of the model object to which this entity set is bound. This
  32. * is usually the model that executed the query which created this object.
  33. *
  34. * @var string
  35. */
  36. protected $_model = null;
  37. /**
  38. * A reference to the query object that originated this entity set; usually an instance of
  39. * `lithium\data\model\Query`.
  40. *
  41. * @see lithium\data\model\Query
  42. * @var object
  43. */
  44. protected $_query = null;
  45. /**
  46. * A pointer or resource that is used to load entities from the backend data source that
  47. * originated this collection.
  48. *
  49. * @var resource
  50. */
  51. protected $_result = null;
  52. /**
  53. * Indicates whether the current position is valid or not. This overrides the default value of
  54. * the parent class.
  55. *
  56. * @var boolean
  57. * @see lithium\util\Collection::valid()
  58. */
  59. protected $_valid = true;
  60. /**
  61. * Contains an array of backend-specific statistics generated by the query that produced this
  62. * `Collection` object. These stats are accessible via the `stats()` method.
  63. *
  64. * @see lithium\data\Collection::stats()
  65. * @var array
  66. */
  67. protected $_stats = array();
  68. /**
  69. * By default, query results are not fetched until the collection is iterated. Set to `true`
  70. * when the collection has begun iterating and fetching entities.
  71. *
  72. * @see lithium\data\Collection::rewind()
  73. * @see lithium\data\Collection::_populate()
  74. * @var boolean
  75. */
  76. protected $_hasInitialized = false;
  77. protected $_schema = array();
  78. /**
  79. * Holds an array of values that should be processed on initialization.
  80. *
  81. * @var array
  82. */
  83. protected $_autoConfig = array(
  84. 'data', 'model', 'result', 'query', 'parent', 'stats', 'pathKey'
  85. );
  86. /**
  87. * Class constructor
  88. * @param array $config
  89. */
  90. public function __construct(array $config = array()) {
  91. $defaults = array('data' => array(), 'model' => null);
  92. parent::__construct($config + $defaults);
  93. }
  94. protected function _init() {
  95. parent::_init();
  96. foreach (array('data', 'classes', 'model', 'result', 'query') as $key) {
  97. unset($this->_config[$key]);
  98. }
  99. if ($model = $this->_model) {
  100. $options = array(
  101. 'pathKey' => $this->_pathKey,
  102. 'schema' => $model::schema(),
  103. 'exists' => isset($this->_config['exists']) ? $this->_config['exists'] : null
  104. );
  105. $this->_data = $model::connection()->cast($this, $this->_data, $options);
  106. }
  107. }
  108. /**
  109. * Configures protected properties of a `Collection` so that it is parented to `$parent`.
  110. *
  111. * @param object $parent
  112. * @param array $config
  113. * @return void
  114. */
  115. public function assignTo($parent, array $config = array()) {
  116. foreach ($config as $key => $val) {
  117. $this->{'_' . $key} = $val;
  118. }
  119. $this->_parent =& $parent;
  120. }
  121. /**
  122. * Returns the model which this particular collection is based off of.
  123. *
  124. * @return string The fully qualified model class name.
  125. */
  126. public function model() {
  127. return $this->_model;
  128. }
  129. public function schema($field = null) {
  130. $schema = array();
  131. switch (true) {
  132. case ($this->_schema):
  133. $schema = $this->_schema;
  134. break;
  135. case ($model = $this->_model):
  136. $schema = $model::schema();
  137. break;
  138. }
  139. if ($field) {
  140. return isset($self->_schema[$field]) ? $self->_schema[$field] : null;
  141. }
  142. return $schema;
  143. }
  144. /**
  145. * Returns a boolean indicating whether an offset exists for the
  146. * current `Collection`.
  147. *
  148. * @param string $offset String or integer indicating the offset or
  149. * index of an entity in the set.
  150. * @return boolean Result.
  151. */
  152. public function offsetExists($offset) {
  153. return ($this->offsetGet($offset) !== null);
  154. }
  155. /**
  156. * Reset the set's iterator and return the first entity in the set.
  157. * The next call of `current()` will get the first entity in the set.
  158. *
  159. * @return object Returns the first `Entity` instance in the set.
  160. */
  161. public function rewind() {
  162. $this->_valid = (reset($this->_data) || count($this->_data));
  163. if (!$this->_valid && !$this->_hasInitialized) {
  164. $this->_hasInitialized = true;
  165. if ($entity = $this->_populate()) {
  166. $this->_valid = true;
  167. return $entity;
  168. }
  169. }
  170. return current($this->_data);
  171. }
  172. /**
  173. * Returns meta information for this `Collection`.
  174. *
  175. * @return array
  176. */
  177. public function meta() {
  178. return array('model' => $this->_model);
  179. }
  180. /**
  181. * Applies a callback to all data in the collection.
  182. *
  183. * Overridden to load any data that has not yet been loaded.
  184. *
  185. * @param callback $filter The filter to apply.
  186. * @return object This collection instance.
  187. */
  188. public function each($filter) {
  189. if (!$this->closed()) {
  190. while ($this->next()) {}
  191. }
  192. return parent::each($filter);
  193. }
  194. /**
  195. * Applies a callback to a copy of all data in the collection
  196. * and returns the result.
  197. *
  198. * Overriden to load any data that has not yet been loaded.
  199. *
  200. * @param callback $filter The filter to apply.
  201. * @param array $options The available options are:
  202. * - `'collect'`: If `true`, the results will be returned wrapped
  203. * in a new `Collection` object or subclass.
  204. * @return object The filtered data.
  205. */
  206. public function map($filter, array $options = array()) {
  207. $defaults = array('collect' => true);
  208. $options += $defaults;
  209. if (!$this->closed()) {
  210. while ($this->next()) {}
  211. }
  212. $data = parent::map($filter, $options);
  213. if ($options['collect']) {
  214. foreach (array('_model', '_schema', '_pathKey') as $key) {
  215. $data->{$key} = $this->{$key};
  216. }
  217. }
  218. return $data;
  219. }
  220. /**
  221. * Converts the current state of the data structure to an array.
  222. *
  223. * @return array Returns the array value of the data in this `Collection`.
  224. */
  225. public function data() {
  226. return $this->to('array');
  227. }
  228. /**
  229. * Adds the specified object to the `Collection` instance, and assigns associated metadata to
  230. * the added object.
  231. *
  232. * @param string $offset The offset to assign the value to.
  233. * @param mixed $data The entity object to add.
  234. * @return mixed Returns the set `Entity` object.
  235. */
  236. public function offsetSet($offset, $data) {
  237. if (is_array($data) && ($model = $this->_model)) {
  238. $data = $model::connection()->cast($this, $data);
  239. } elseif (is_object($data)) {
  240. $data->assignTo($this);
  241. }
  242. return $this->_data[] = $data;
  243. }
  244. /**
  245. * Gets the stat or stats associated with this `Collection`.
  246. *
  247. * @param string $name Stat name.
  248. * @return mixed Single stat if `$name` supplied, else all stats for this
  249. * `Collection`.
  250. */
  251. public function stats($name = null) {
  252. if ($name) {
  253. return isset($this->_stats[$name]) ? $this->_stats[$name] : null;
  254. }
  255. return $this->_stats;
  256. }
  257. /**
  258. * Executes when the associated result resource pointer reaches the end of its data set. The
  259. * resource is freed by the connection, and the reference to the connection is unlinked.
  260. *
  261. * @return void
  262. */
  263. public function close() {
  264. if (!empty($this->_result)) {
  265. $this->_result = null;
  266. }
  267. }
  268. /**
  269. * Checks to see if this entity has already fetched all available entities and freed the
  270. * associated result resource.
  271. *
  272. * @return boolean Returns true if all entities are loaded and the database resources have been
  273. * freed, otherwise returns false.
  274. */
  275. public function closed() {
  276. return empty($this->_result);
  277. }
  278. /**
  279. * Ensures that the data set's connection is closed when the object is destroyed.
  280. *
  281. * @return void
  282. */
  283. public function __destruct() {
  284. $this->close();
  285. }
  286. /**
  287. * A method to be implemented by concrete `Collection` classes which, provided a reference to a
  288. * backend data source, and a resource representing a query result cursor, fetches new result
  289. * data and wraps it in the appropriate object type, which is added into the `Collection` and
  290. * returned.
  291. *
  292. * @param mixed $data Data (in an array or object) that is manually added to the data
  293. * collection. If `null`, data is automatically fetched from the associated backend
  294. * data source, if available.
  295. * @param mixed $key String, integer or array key representing the unique key of the data
  296. * object. If `null`, the key will be extracted from the data passed or fetched,
  297. * using the associated `Model` class.
  298. * @return object Returns a `Record` or `Document` object, or other `Entity` object.
  299. */
  300. abstract protected function _populate($data = null, $key = null);
  301. }
  302. ?>