ActiveQuery.php 6.41 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

Qiang Xue committed
67 68 69 70 71 72 73 74 75 76 77 78

    /**
     * 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);
    }

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    /**
     * @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
                /** @var ActiveQuery $viaQuery */
                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]);
            }
        }
107

108 109
        return parent::buildCursor($db);
    }
110

111 112
    /**
     * Executes query and returns all results as an array.
113 114 115
     * @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.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
     */
    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();
                }
            }
131

132 133 134 135 136 137 138 139
            return $models;
        } else {
            return [];
        }
    }

    /**
     * Executes query and returns a single row of result.
140 141
     * @param Connection $db the Mongo connection used to execute the query.
     * If null, the Mongo connection returned by [[modelClass]] will be used.
142
     * @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
143 144
     * the query result may be either an array or an ActiveRecord object. Null will be returned
     * if the query results in nothing.
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
     */
    public function one($db = null)
    {
        $row = parent::one($db);
        if ($row !== false) {
            if ($this->asArray) {
                $model = $row;
            } else {
                /** @var ActiveRecord $class */
                $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.
175
     * @param Connection $db Mongo connection.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
     * @return Collection collection instance.
     */
    public function getCollection($db = null)
    {
        /** @var ActiveRecord $modelClass */
        $modelClass = $this->modelClass;
        if ($db === null) {
            $db = $modelClass::getDb();
        }
        if ($this->from === null) {
            $this->from = $modelClass::collectionName();
        }

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