EMongoPartialDocument.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. /**
  3. * EMongoPartialDocument.php
  4. *
  5. * PHP version 5.2+
  6. *
  7. * @author Nagy Attila Gabor
  8. * @author Dariusz Górecki <darek.krk@gmail.com>
  9. * @copyright 2011 CleverIT http://www.cleverit.com.pl
  10. * @license http://www.yiiframework.com/license/ BSD license
  11. * @version 1.3
  12. * @category ext
  13. * @package ext.YiiMongoDbSuite
  14. * @since v1.3.6
  15. */
  16. /**
  17. * EMongoPartialDocument
  18. *
  19. * @property-read array $loadedFields
  20. * @property-read array $unloadedFields
  21. * @since v1.3.6
  22. */
  23. abstract class EMongoPartialDocument extends EMongoDocument
  24. {
  25. protected $_loadedFields = array(); // Fields that have not been loaded from DB
  26. protected $_partial = false; // Whatever the document has been partially loaded
  27. /**
  28. * Returns if this document is only partially loaded
  29. * @return boolean true if the document is partially loaded
  30. */
  31. public function isPartial()
  32. {
  33. return $this->_partial;
  34. }
  35. /**
  36. * Returns list of fields that have been loaded from DB by
  37. * {@link EMongoDocument::instantiate} method.
  38. * @return array
  39. */
  40. public function getLoadedFields()
  41. {
  42. return $this->_partial ? $this->_loadedFields : array();
  43. }
  44. /**
  45. * Returns list of fields that have not been loaded from DB by
  46. * {@link EMongoDocument::instantiate} method.
  47. * @return array
  48. */
  49. public function getUnloadedFields()
  50. {
  51. return $this->_partial ? array_diff(
  52. $this->_loadedFields,
  53. $this->attributeNames()
  54. ) : array();
  55. }
  56. /**
  57. * Check if this attribute is loaded, and if not, then return null
  58. */
  59. public function __get($name)
  60. {
  61. if(
  62. $this->_partial &&
  63. $this->hasEmbeddedDocuments() &&
  64. isset(self::$_embeddedConfig[get_class($this)][$name]) &&
  65. !in_array($name, $this->_loadedFields)
  66. ){
  67. return null;
  68. }
  69. else
  70. return parent::__get($name);
  71. }
  72. /**
  73. * If user explicitly sets the unloaded embedded field, consider it as an loaded one, if model is partially loaded
  74. * @see EMongoEmbeddedDocument::__set()
  75. */
  76. public function __set($name, $value)
  77. {
  78. $return = parent::__set($name, $value);
  79. if($this->_partial && !in_array($name, $this->_loadedFields))
  80. {
  81. $this->_loadedFields[] = $name;
  82. if(count($this->_loadedFields) === count($this->attributeNames()))
  83. {
  84. $this->_partial = false;
  85. $this->loadedFields = null;
  86. }
  87. }
  88. return $return;
  89. }
  90. /**
  91. * Loads additional, previously unloaded attributes
  92. * to this document.
  93. * @param array $attributes attributes to be loaded
  94. * @return boolean wether the load was successfull
  95. */
  96. public function loadAttributes($attributes = array())
  97. {
  98. $document = $this->getCollection()->findOne(
  99. array('_id' => $this->_id),
  100. $attributes
  101. );
  102. unset($document['_id']);
  103. $attributesSum = array_merge($this->_loadedFields, array_keys($document));
  104. if(count($attributesSum) === count($this->attributeNames()))
  105. {
  106. $this->_partial = false;
  107. $this->_loadedFields = null;
  108. }
  109. else
  110. {
  111. $this->_loadedFields = $attributesSum;
  112. }
  113. $this->setAttributes($document, false);
  114. return true;
  115. }
  116. /**
  117. * Updates the row represented by this active record.
  118. * All loaded attributes will be saved to the database.
  119. * Note, validation is not performed in this method. You may call {@link validate} to perform the validation.
  120. * @param array $attributes list of attributes that need to be saved. Defaults to null,
  121. * meaning all attributes that are loaded from DB will be saved.
  122. * @param boolean modify if set true only selected attributes will be replaced, and not
  123. * the whole document
  124. * @return boolean whether the update is successful
  125. * @throws CException if the record is new
  126. * @throws EMongoException on fail of update
  127. * @throws MongoCursorException on fail of update, when safe flag is set to true
  128. * @throws MongoCursorTimeoutException on timeout of db operation , when safe flag is set to true
  129. * @since v1.0
  130. */
  131. public function update(array $attributes=null, $modify = false)
  132. {
  133. if($this->_partial)
  134. {
  135. $attributes = count($attributes) > 0 ? array_intersect($attributes, $this->_loadedFields) : array_diff($this->_loadedFields, array('_id'));
  136. return parent::update($attributes, true);
  137. }
  138. return parent::update($attributes, $modify);
  139. }
  140. protected function instantiate($attributes)
  141. {
  142. $model = parent::instantiate($attributes);
  143. $loadedFields = array_keys($attributes);
  144. if(count($loadedFields) < count($model->attributeNames()))
  145. {
  146. $model->_partial = true;
  147. $model->_loadedFields = $loadedFields;
  148. }
  149. return $model;
  150. }
  151. }