ActiveQuery.php 6.94 KB
Newer Older
1 2 3 4 5 6 7
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

8
namespace yii\mongodb;
9 10 11

use yii\db\ActiveQueryInterface;
use yii\db\ActiveQueryTrait;
12
use yii\db\ActiveRelationTrait;
13 14

/**
15 16
 * ActiveQuery represents a Mongo query associated with an Active Record class.
 *
17 18 19 20 21 22 23 24
 * An ActiveQuery can be a normal query or be used in a relational context.
 *
 * ActiveQuery instances are usually created by [[ActiveRecord::find()]].
 * Relational queries are created by [[ActiveRecord::hasOne()]] and [[ActiveRecord::hasMany()]].
 *
 * Normal Query
 * ------------
 *
25 26 27 28 29 30 31 32 33 34 35 36
 * ActiveQuery instances are usually created by [[ActiveRecord::find()]].
 *
 * Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]],
 * [[orderBy()]] to customize the query options.
 *
 * ActiveQuery also provides the following additional query options:
 *
 * - [[with()]]: list of relations that this query should be performed with.
 * - [[asArray()]]: whether to return each record as an array.
 *
 * These options can be configured using methods of the same name. For example:
 *
37
 * ```php
38
 * $customers = Customer::find()->with('orders')->asArray()->all();
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
 * ```
 *
 * Relational query
 * ----------------
 *
 * In relational context ActiveQuery represents a relation between two Active Record classes.
 *
 * Relational ActiveQuery instances are usually created by calling [[ActiveRecord::hasOne()]] and
 * [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
 * a getter method which calls one of the above methods and returns the created ActiveQuery object.
 *
 * A relation is specified by [[link]] which represents the association between columns
 * of different tables; and the multiplicity of the relation is indicated by [[multiple]].
 *
 * If a relation involves a pivot table, it may be specified by [[via()]].
 * This methods may only be called in a relational context. Same is true for [[inverseOf()]], which
 * marks a relation as inverse of another relation.
56
 *
Qiang Xue committed
57 58
 * @property Collection $collection Collection instance. This property is read-only.
 *
59 60 61
 * @author Paul Klimov <klimov.paul@gmail.com>
 * @since 2.0
 */
62
class ActiveQuery extends Query implements ActiveQueryInterface
63
{
64 65
    use ActiveQueryTrait;
    use ActiveRelationTrait;
66

67 68 69 70 71
    /**
     * @event Event an event that is triggered when the query is initialized via [[init()]].
     */
    const EVENT_INIT = 'init';

Qiang Xue committed
72 73 74 75 76 77 78 79 80 81 82 83

    /**
     * Constructor.
     * @param array $modelClass the model class associated with this query
     * @param array $config configurations to be applied to the newly created query object
     */
    public function __construct($modelClass, $config = [])
    {
        $this->modelClass = $modelClass;
        parent::__construct($config);
    }

84 85 86 87 88 89 90 91 92 93 94 95
    /**
     * Initializes the object.
     * This method is called at the end of the constructor. The default implementation will trigger
     * an [[EVENT_INIT]] event. If you override this method, make sure you call the parent implementation at the end
     * to ensure triggering of the event.
     */
    public function init()
    {
        parent::init();
        $this->trigger(self::EVENT_INIT);
    }

96 97 98 99 100 101 102 103 104 105 106 107 108
    /**
     * @inheritdoc
     */
    protected function buildCursor($db = null)
    {
        if ($this->primaryModel !== null) {
            // lazy loading
            if ($this->via instanceof self) {
                // via pivot collection
                $viaModels = $this->via->findPivotRows([$this->primaryModel]);
                $this->filterByModels($viaModels);
            } elseif (is_array($this->via)) {
                // via relation
109
                /* @var $viaQuery ActiveQuery */
110 111 112 113 114 115 116 117 118 119 120 121 122 123
                list($viaName, $viaQuery) = $this->via;
                if ($viaQuery->multiple) {
                    $viaModels = $viaQuery->all();
                    $this->primaryModel->populateRelation($viaName, $viaModels);
                } else {
                    $model = $viaQuery->one();
                    $this->primaryModel->populateRelation($viaName, $model);
                    $viaModels = $model === null ? [] : [$model];
                }
                $this->filterByModels($viaModels);
            } else {
                $this->filterByModels([$this->primaryModel]);
            }
        }
124

125 126
        return parent::buildCursor($db);
    }
127

128 129
    /**
     * Executes query and returns all results as an array.
130 131 132
     * @param Connection $db the Mongo connection used to execute the query.
     * If null, the Mongo connection returned by [[modelClass]] will be used.
     * @return array the query results. If the query results in nothing, an empty array will be returned.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
     */
    public function all($db = null)
    {
        $cursor = $this->buildCursor($db);
        $rows = $this->fetchRows($cursor);
        if (!empty($rows)) {
            $models = $this->createModels($rows);
            if (!empty($this->with)) {
                $this->findWith($this->with, $models);
            }
            if (!$this->asArray) {
                foreach ($models as $model) {
                    $model->afterFind();
                }
            }
148

149 150 151 152 153 154 155 156
            return $models;
        } else {
            return [];
        }
    }

    /**
     * Executes query and returns a single row of result.
157 158
     * @param Connection $db the Mongo connection used to execute the query.
     * If null, the Mongo connection returned by [[modelClass]] will be used.
159
     * @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
160 161
     * the query result may be either an array or an ActiveRecord object. Null will be returned
     * if the query results in nothing.
162 163 164 165 166 167 168 169
     */
    public function one($db = null)
    {
        $row = parent::one($db);
        if ($row !== false) {
            if ($this->asArray) {
                $model = $row;
            } else {
170
                /* @var $class ActiveRecord */
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
                $class = $this->modelClass;
                $model = $class::instantiate($row);
                $class::populateRecord($model, $row);
            }
            if (!empty($this->with)) {
                $models = [$model];
                $this->findWith($this->with, $models);
                $model = $models[0];
            }
            if (!$this->asArray) {
                $model->afterFind();
            }

            return $model;
        } else {
            return null;
        }
    }

    /**
     * Returns the Mongo collection for this query.
192
     * @param Connection $db Mongo connection.
193 194 195 196
     * @return Collection collection instance.
     */
    public function getCollection($db = null)
    {
197
        /* @var $modelClass ActiveRecord */
198 199 200 201 202 203 204 205 206 207
        $modelClass = $this->modelClass;
        if ($db === null) {
            $db = $modelClass::getDb();
        }
        if ($this->from === null) {
            $this->from = $modelClass::collectionName();
        }

        return $db->getCollection($this->from);
    }
AlexGx committed
208
}