DocumentSet.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <?php
  2. /**
  3. * @category Thinkopen
  4. * @package Mooses_Mongodb_Mongo
  5. * @license New BSD License
  6. */
  7. class Mooses_Mongodb_Mongo_DocumentSet extends Mooses_Mongodb_Mongo_Document
  8. {
  9. const DYNAMIC_INDEX = '$';
  10. protected static $_requirements = array(
  11. self::DYNAMIC_INDEX => 'Document'
  12. );
  13. /**
  14. * Get the property keys for this Document Set
  15. *
  16. * @return array
  17. */
  18. public function getPropertyKeys()
  19. {
  20. $keys = parent::getPropertyKeys();
  21. sort($keys, SORT_NUMERIC);
  22. return $keys;
  23. }
  24. /**
  25. * Get a property
  26. *
  27. * @param mixed $property
  28. */
  29. public function getProperty($index = null)
  30. {
  31. $new = is_null($index);
  32. // If property exists and initialised then return it
  33. if (!$new && array_key_exists($index, $this->_data)) {
  34. return $this->_data[$index];
  35. }
  36. // Make sure we are not trying to create a document that is supposed to be saved as a reference
  37. if ($new && $this->hasRequirement(static::DYNAMIC_INDEX, 'AsReference')) {
  38. require_once 'Thinkopen/Mongodb/Mongo/Exception.php';
  39. throw new Mooses_Mongodb_Mongo_Exception("Can not create a new document from documentset where document must be saved as a reference");
  40. }
  41. if (!$new) {
  42. // Fetch clean data for this property if it exists
  43. if (array_key_exists($index, $this->_cleanData)) $data = $this->_cleanData[$index];
  44. else return null;
  45. }
  46. else $data = array();
  47. // If property is a reference to another document then fetch the reference document
  48. if (MongoDBRef::isRef($data)) {
  49. $collection = $data['$ref'];
  50. $data = MongoDBRef::get($this->_getMongoDB(false), $data);
  51. // If this is a broken reference then no point keeping it for later
  52. if (!$data) {
  53. $this->_data[$index] = null;
  54. return $this->_data[$index];
  55. }
  56. $reference = true;
  57. }
  58. else {
  59. $reference = false;
  60. $collection = $this->getConfigAttribute('collection');
  61. }
  62. $config = array ();
  63. $config['new'] = $new;
  64. $config['requirementModifiers'] = $this->getRequirements(self::DYNAMIC_INDEX.'.');
  65. $config['parentIsDocumentSet'] = true;
  66. $config['connectionGroup'] = $this->getConfigAttribute('connectionGroup');
  67. $config['db'] = $this->getConfigAttribute('db');
  68. $config['collection'] = $collection;
  69. if (!$reference) {
  70. // If this is a new array element. We will $push to the array when saving
  71. if ($new) $path = $this->getPathToDocument();
  72. else $path = $this->getPathToProperty($index);
  73. $config['pathToDocument'] = $path;
  74. $config['criteria'] = $this->getCriteria();
  75. $config['hasId'] = $this->hasRequirement(self::DYNAMIC_INDEX, 'hasId');
  76. }
  77. // get the document class
  78. $documentClass = $this->hasRequirement(self::DYNAMIC_INDEX, 'Document');
  79. if (isset($data['_type']) && !empty($data['_type'][0])) {
  80. $documentClass = $data['_type'][0];
  81. }
  82. $document = new $documentClass($data, $config);
  83. // if this document was a reference then remember that
  84. if ($reference) {
  85. $this->_references->attach($document);
  86. }
  87. // If this is not a new document cache it
  88. if (!$new) {
  89. $this->_data[$index] = $document;
  90. }
  91. return $document;
  92. }
  93. /**
  94. * Set property
  95. *
  96. * @param $index
  97. * @param $document
  98. */
  99. public function setProperty($index, $document)
  100. {
  101. $new = is_null($index);
  102. // Make sure index is numeric
  103. if (!$new && !is_numeric($index)) {
  104. require_once 'Thinkopen/Mongodb/Mongo/Exception.php';
  105. throw new Mooses_Mongodb_Mongo_Exception("Index must be numeric '{$index}' given");
  106. }
  107. // Unset element
  108. if (!$new && is_null($document)) {
  109. $this->_data[$index] = null;
  110. return;
  111. }
  112. // Make sure we are not keeping a copy of the old document in reference memory
  113. if (!$new && isset($this->_data[$index]) && !is_null($this->_data[$index])) {
  114. $this->_references->detach($this->_data[$index]);
  115. }
  116. // Throw exception if value is not valid
  117. $validators = $this->getValidators(self::DYNAMIC_INDEX);
  118. if (!$validators->isValid($document)) {
  119. require_once 'Thinkopen/Mongodb/Mongo/Exception.php';
  120. throw new Mooses_Mongodb_Mongo_Exception(implode($validators->getMessages(), "\n"));
  121. }
  122. if ($new) {
  123. $keys = $this->getPropertyKeys();
  124. $index = empty($keys) ? 0 : max($keys)+1;
  125. }
  126. // Filter value
  127. // $value = $this->getFilters(self::DYNAMIC_INDEX)->filter($document);
  128. if (!$this->hasRequirement(self::DYNAMIC_INDEX, 'AsReference')) {
  129. // Make a new document if it has been saved somewhere else
  130. if (!$document->isNewDocument()) {
  131. $documentClass = get_class($document);
  132. $document = new $documentClass($document->export(), array('new' => false, 'pathToDocument' => $this->getPathToProperty($index)));
  133. }
  134. else {
  135. $document->setPathToDocument($this->getPathToProperty($index));
  136. }
  137. // Inform the document of it's surroundings
  138. $document->setConfigAttribute('connectionGroup', $this->getConfigAttribute('connectionGroup'));
  139. $document->setConfigAttribute('db', $this->getConfigAttribute('db'));
  140. $document->setConfigAttribute('collection', $this->getConfigAttribute('collection'));
  141. $document->setConfigAttribute('criteria', $this->getCriteria());
  142. $document->applyRequirements($this->getRequirements(self::DYNAMIC_INDEX.'.'));
  143. }
  144. $this->_data[$index] = $document;
  145. }
  146. /**
  147. * Export all data
  148. *
  149. * @return array
  150. */
  151. public function export($skipRequired = false)
  152. {
  153. // Since this is an array, fill in empty index's with null
  154. $exportData = parent::export($skipRequired);
  155. // Fix PHP "max(): Array must contain at least one element" bug
  156. // if DocumentSet has no data
  157. if (count($exportData) > 0) {
  158. $maxKey = max(array_keys($exportData));
  159. for ($i = 0; $i<$maxKey; $i++) {
  160. if (array_key_exists($i, $exportData)) {
  161. continue;
  162. }
  163. $exportData[$i] = null;
  164. }
  165. ksort($exportData);
  166. }
  167. return $exportData;
  168. }
  169. /**
  170. * Add a document to this set
  171. *
  172. * @param Mooses_Mongodb_Mongo_Document $document
  173. */
  174. public function addDocument(Mooses_Mongodb_Mongo_Document $document)
  175. {
  176. return $this->setProperty(null, $document);
  177. }
  178. /**
  179. * Add a document to the push queue
  180. *
  181. * @param Mooses_Mongodb_Mongo_Document $document
  182. */
  183. public function pushDocument(Mooses_Mongodb_Mongo_Document $document)
  184. {
  185. $this->push(null, $document);
  186. }
  187. /**
  188. * Get all operations
  189. *
  190. * @param Boolean $includingChildren Get operations from children as well
  191. */
  192. public function getOperations($includingChildren = false)
  193. {
  194. if ($this->hasRequirement(self::DYNAMIC_INDEX, 'AsReference')) $includingChildren = false;
  195. return parent::getOperations($includingChildren);
  196. }
  197. /**
  198. * Remove all operations
  199. *
  200. * @param Boolean $includingChildren Remove operations from children as wells
  201. */
  202. public function purgeOperations($includingChildren = false)
  203. {
  204. if ($this->hasRequirement(self::DYNAMIC_INDEX, 'AsReference')) $includingChildren = false;
  205. return parent::purgeOperations($includingChildren);
  206. }
  207. public function __call($name, $arguments = array())
  208. {
  209. switch ($name) {
  210. case 'new':
  211. return $this->getProperty();
  212. }
  213. require_once 'Thinkopen/Mongodb/Mongo/Exception.php';
  214. throw new Mooses_Mongodb_Mongo_Exception("Captured in __call. Method $name does not exist.");
  215. }
  216. }