ActiveQuery.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\mongodb;
  8. use yii\db\ActiveQueryInterface;
  9. use yii\db\ActiveQueryTrait;
  10. use yii\db\ActiveRelationTrait;
  11. /**
  12. * ActiveQuery represents a Mongo query associated with an Active Record class.
  13. *
  14. * An ActiveQuery can be a normal query or be used in a relational context.
  15. *
  16. * ActiveQuery instances are usually created by [[ActiveRecord::find()]].
  17. * Relational queries are created by [[ActiveRecord::hasOne()]] and [[ActiveRecord::hasMany()]].
  18. *
  19. * Normal Query
  20. * ------------
  21. *
  22. * ActiveQuery instances are usually created by [[ActiveRecord::find()]].
  23. *
  24. * Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]],
  25. * [[orderBy()]] to customize the query options.
  26. *
  27. * ActiveQuery also provides the following additional query options:
  28. *
  29. * - [[with()]]: list of relations that this query should be performed with.
  30. * - [[asArray()]]: whether to return each record as an array.
  31. *
  32. * These options can be configured using methods of the same name. For example:
  33. *
  34. * ```php
  35. * $customers = Customer::find()->with('orders')->asArray()->all();
  36. * ```
  37. *
  38. * Relational query
  39. * ----------------
  40. *
  41. * In relational context ActiveQuery represents a relation between two Active Record classes.
  42. *
  43. * Relational ActiveQuery instances are usually created by calling [[ActiveRecord::hasOne()]] and
  44. * [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
  45. * a getter method which calls one of the above methods and returns the created ActiveQuery object.
  46. *
  47. * A relation is specified by [[link]] which represents the association between columns
  48. * of different collections; and the multiplicity of the relation is indicated by [[multiple]].
  49. *
  50. * If a relation involves a junction collection, it may be specified by [[via()]].
  51. * This methods may only be called in a relational context. Same is true for [[inverseOf()]], which
  52. * marks a relation as inverse of another relation.
  53. *
  54. * @property Collection $collection Collection instance. This property is read-only.
  55. *
  56. * @author Paul Klimov <klimov.paul@gmail.com>
  57. * @since 2.0
  58. */
  59. class ActiveQuery extends Query implements ActiveQueryInterface
  60. {
  61. use ActiveQueryTrait;
  62. use ActiveRelationTrait;
  63. /**
  64. * @event Event an event that is triggered when the query is initialized via [[init()]].
  65. */
  66. const EVENT_INIT = 'init';
  67. /**
  68. * Constructor.
  69. * @param string $modelClass the model class associated with this query
  70. * @param array $config configurations to be applied to the newly created query object
  71. */
  72. public function __construct($modelClass, $config = [])
  73. {
  74. $this->modelClass = $modelClass;
  75. parent::__construct($config);
  76. }
  77. /**
  78. * Initializes the object.
  79. * This method is called at the end of the constructor. The default implementation will trigger
  80. * an [[EVENT_INIT]] event. If you override this method, make sure you call the parent implementation at the end
  81. * to ensure triggering of the event.
  82. */
  83. public function init()
  84. {
  85. parent::init();
  86. $this->trigger(self::EVENT_INIT);
  87. }
  88. /**
  89. * {@inheritdoc}
  90. */
  91. public function prepare()
  92. {
  93. if ($this->primaryModel !== null) {
  94. // lazy loading
  95. if ($this->via instanceof self) {
  96. // via pivot collection
  97. $viaModels = $this->via->findJunctionRows([$this->primaryModel]);
  98. $this->filterByModels($viaModels);
  99. } elseif (is_array($this->via)) {
  100. // via relation
  101. /* @var $viaQuery ActiveQuery */
  102. list($viaName, $viaQuery) = $this->via;
  103. if ($viaQuery->multiple) {
  104. $viaModels = $viaQuery->all();
  105. $this->primaryModel->populateRelation($viaName, $viaModels);
  106. } else {
  107. $model = $viaQuery->one();
  108. $this->primaryModel->populateRelation($viaName, $model);
  109. $viaModels = $model === null ? [] : [$model];
  110. }
  111. $this->filterByModels($viaModels);
  112. } else {
  113. $this->filterByModels([$this->primaryModel]);
  114. }
  115. }
  116. return parent::prepare();
  117. }
  118. /**
  119. * Executes query and returns all results as an array.
  120. * @param Connection $db the Mongo connection used to execute the query.
  121. * If null, the Mongo connection returned by [[modelClass]] will be used.
  122. * @return array|ActiveRecord the query results. If the query results in nothing, an empty array will be returned.
  123. */
  124. public function all($db = null)
  125. {
  126. return parent::all($db);
  127. }
  128. /**
  129. * Executes query and returns a single row of result.
  130. * @param Connection $db the Mongo connection used to execute the query.
  131. * If null, the Mongo connection returned by [[modelClass]] will be used.
  132. * @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
  133. * the query result may be either an array or an ActiveRecord object. Null will be returned
  134. * if the query results in nothing.
  135. */
  136. public function one($db = null)
  137. {
  138. $row = parent::one($db);
  139. if ($row !== false) {
  140. $models = $this->populate([$row]);
  141. return reset($models) ?: null;
  142. }
  143. return null;
  144. }
  145. /**
  146. * Performs 'findAndModify' query and returns a single row of result.
  147. * Warning: in case 'new' option is set to 'false' (which is by default) usage of this method may lead
  148. * to unexpected behavior at some Active Record features, because object will be populated by outdated data.
  149. * @param array $update update criteria
  150. * @param array $options list of options in format: optionName => optionValue.
  151. * @param Connection $db the Mongo connection used to execute the query.
  152. * @return ActiveRecord|array|null the original document, or the modified document when $options['new'] is set.
  153. * Depending on the setting of [[asArray]], the query result may be either an array or an ActiveRecord object.
  154. * Null will be returned if the query results in nothing.
  155. */
  156. public function modify($update, $options = [], $db = null)
  157. {
  158. $row = parent::modify($update, $options, $db);
  159. if ($row !== null) {
  160. $models = $this->populate([$row]);
  161. return reset($models) ?: null;
  162. }
  163. return null;
  164. }
  165. /**
  166. * Returns the Mongo collection for this query.
  167. * @param Connection $db Mongo connection.
  168. * @return Collection collection instance.
  169. */
  170. public function getCollection($db = null)
  171. {
  172. /* @var $modelClass ActiveRecord */
  173. $modelClass = $this->modelClass;
  174. if ($db === null) {
  175. $db = $modelClass::getDb();
  176. }
  177. if ($this->from === null) {
  178. $this->from = $modelClass::collectionName();
  179. }
  180. return $db->getCollection($this->from);
  181. }
  182. /**
  183. * Converts the raw query results into the format as specified by this query.
  184. * This method is internally used to convert the data fetched from MongoDB
  185. * into the format as required by this query.
  186. * @param array $rows the raw query result from MongoDB
  187. * @return array the converted query result
  188. */
  189. public function populate($rows)
  190. {
  191. if (empty($rows)) {
  192. return [];
  193. }
  194. $models = $this->createModels($rows);
  195. if (!empty($this->with)) {
  196. $this->findWith($this->with, $models);
  197. }
  198. if (!$this->asArray) {
  199. foreach ($models as $model) {
  200. $model->afterFind();
  201. }
  202. }
  203. return parent::populate($models);
  204. }
  205. }