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

/lithium/libraries/lithium/data/collection/DocumentSet.php

https://github.com/brtriver/sukonv
PHP | 211 lines | 108 code | 24 blank | 79 comment | 23 complexity | ab4a79e88618d67c6cf2a8b3da8dc98a MD5 | raw file
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2010, 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\collection;
  9. class DocumentSet extends \lithium\data\Collection {
  10. /**
  11. * PHP magic method used when setting properties on the `Document` instance, i.e.
  12. * `$document->title = 'Lorem Ipsum'`. If `$value` is a complex data type (i.e. associative
  13. * array), it is wrapped in a sub-`Document` object before being appended.
  14. *
  15. * @param $name The name of the field/property to write to, i.e. `title` in the above example.
  16. * @param $value The value to write, i.e. `'Lorem Ipsum'`.
  17. * @return void
  18. */
  19. public function __set($name, $value = null) {
  20. if (is_array($name) && !$value) {
  21. foreach ($name as $key => $value) {
  22. $this->__set($key, $value);
  23. }
  24. return;
  25. }
  26. if (is_string($name) && strpos($name, '.')) {
  27. $current = $this;
  28. $path = explode('.', $name);
  29. $length = count($path) - 1;
  30. for ($i = 0; $i < $length; $i++) {
  31. $key = $path[$i];
  32. $next = $current->__get($key);
  33. if (!is_object($next) && ($model = $this->_model)) {
  34. $next = $model::connection()->cast($this, $next);
  35. $current->_data[$key] = $next;
  36. }
  37. $current = $next;
  38. }
  39. $current->__set(end($path), $value);
  40. }
  41. if (is_array($value)) {
  42. $value = $this->_relation('set', $name, $value);
  43. }
  44. $this->_data[$name] = $value;
  45. }
  46. /**
  47. * PHP magic method used to check the presence of a field as document properties, i.e.
  48. * `$document->_id`.
  49. *
  50. * @param $name The field name, as specified with an object property.
  51. * @return boolean True if the field specified in `$name` exists, false otherwise.
  52. */
  53. public function __isset($name) {
  54. return isset($this->_data[$name]);
  55. }
  56. /**
  57. * PHP magic method used when unset() is called on a `Document` instance.
  58. * Use case for this would be when you wish to edit a document and remove a field, ie. :
  59. * {{{ $doc = Post::find($id); unset($doc->fieldName); $doc->save(); }}}
  60. *
  61. * @param unknown_type $name
  62. * @return unknown_type
  63. */
  64. public function __unset($name) {
  65. unset($this->_data[$name]);
  66. }
  67. /**
  68. * Allows several properties to be assigned at once.
  69. *
  70. * For example:
  71. * {{{
  72. * $doc->set(array('title' => 'Lorem Ipsum', 'value' => 42));
  73. * }}}
  74. *
  75. * @param $values An associative array of fields and values to assign to the `Document`.
  76. * @return void
  77. */
  78. public function set($values) {
  79. foreach ($values as $key => $val) {
  80. $this[$key] = $val;
  81. }
  82. }
  83. /**
  84. * Allows document fields to be accessed as array keys, i.e. `$document['_id']`.
  85. *
  86. * @param mixed $offset String or integer indicating the offset or index of a document in a set,
  87. * or the name of a field in an individual document.
  88. * @return mixed Returns either a sub-object in the document, or a scalar field value.
  89. */
  90. public function offsetGet($offset) {
  91. $data = null;
  92. $null = null;
  93. $model = $this->_model;
  94. if (!isset($this->_data[$offset]) && !$data = $this->_populate(null, $offset)) {
  95. return $null;
  96. }
  97. if (is_array($data = $this->_data[$offset]) && $model) {
  98. $this->_data[$offset] = $model::connection()->cast($this, $data);
  99. }
  100. if (isset($this->_data[$offset])) {
  101. return $this->_data[$offset];
  102. }
  103. return $null;
  104. }
  105. /**
  106. * Rewinds the collection of sub-`Document`s to the beginning and returns the first one found.
  107. *
  108. * @return object Returns the first `Document` object instance in the collection.
  109. */
  110. public function rewind() {
  111. $data = parent::rewind() ?: $this->_populate();
  112. $key = key($this->_data);
  113. if (is_object($data)) {
  114. return $data;
  115. }
  116. if (isset($this->_data[$key])) {
  117. return $this->offsetGet($key);
  118. }
  119. }
  120. public function current() {
  121. return $this->offsetGet(key($this->_data));
  122. }
  123. /**
  124. * Returns the next document in the set, and advances the object's internal pointer. If the end
  125. * of the set is reached, a new document will be fetched from the data source connection handle
  126. * If no more documents can be fetched, returns `null`.
  127. *
  128. * @return object|null Returns the next document in the set, or `null`, if no more documents are
  129. * available.
  130. */
  131. public function next() {
  132. $prev = key($this->_data);
  133. $this->_valid = (next($this->_data) !== false);
  134. $cur = key($this->_data);
  135. if (!$this->_valid && $cur !== $prev && $cur !== null) {
  136. $this->_valid = true;
  137. }
  138. $this->_valid = $this->_valid ?: !is_null($this->_populate());
  139. return $this->_valid ? $this->offsetGet(key($this->_data)) : null;
  140. }
  141. public function export(array $options = array()) {
  142. $map = function($doc) use ($options) {
  143. return is_array($doc) ? $doc : $doc->export();
  144. };
  145. return array_map($map, $this->_data);
  146. }
  147. /**
  148. * Lazy-loads a document from a query using a reference to a database adapter and a query
  149. * result resource.
  150. *
  151. * @param array $data
  152. * @param mixed $key
  153. * @return array
  154. */
  155. protected function _populate($data = null, $key = null) {
  156. if ($this->closed() || !($model = $this->_model)) {
  157. return;
  158. }
  159. $conn = $model::connection();
  160. if (($data = $data ?: $this->_result->next()) === null) {
  161. return $this->close();
  162. }
  163. $options = array('exists' => true, 'first' => true, 'pathKey' => $this->_pathKey);
  164. return $this->_data[] = $conn->cast($this, array($key => $data), $options);
  165. }
  166. /**
  167. * Instantiates a new `Document` object as a descendant of the current object, and sets all
  168. * default values and internal state.
  169. *
  170. * @param string $classType The type of class to create, either `'entity'` or `'set'`.
  171. * @param string $key The key name to which the related object is assigned.
  172. * @param array $data The internal data of the related object.
  173. * @param array $options Any other options to pass when instantiating the related object.
  174. * @return object Returns a new `Document` object instance.
  175. */
  176. protected function _relation($classType, $key, $data, $options = array()) {
  177. $parent = $this;
  178. $model = $this->_model;
  179. if (is_object($data) && $data instanceof Document) {
  180. $data->assignTo($this, compact('model', 'pathKey'));
  181. return $data;
  182. }
  183. $options += compact('model', 'data', 'parent');
  184. return new $this->_classes[$classType]($options);
  185. }
  186. }
  187. ?>