| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 | <?php/** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */namespace yii\data;use yii\base\InvalidConfigException;use yii\base\Model;use yii\db\ActiveQueryInterface;use yii\db\Connection;use yii\db\QueryInterface;use yii\di\Instance;/** * ActiveDataProvider implements a data provider based on [[\yii\db\Query]] and [[\yii\db\ActiveQuery]]. * * ActiveDataProvider provides data by performing DB queries using [[query]]. * * The following is an example of using ActiveDataProvider to provide ActiveRecord instances: * * ```php * $provider = new ActiveDataProvider([ *     'query' => Post::find(), *     'pagination' => [ *         'pageSize' => 20, *     ], * ]); * * // get the posts in the current page * $posts = $provider->getModels(); * ``` * * And the following example shows how to use ActiveDataProvider without ActiveRecord: * * ```php * $query = new Query(); * $provider = new ActiveDataProvider([ *     'query' => $query->from('post'), *     'pagination' => [ *         'pageSize' => 20, *     ], * ]); * * // get the posts in the current page * $posts = $provider->getModels(); * ``` * * For more details and usage information on ActiveDataProvider, see the [guide article on data providers](guide:output-data-providers). * * @author Qiang Xue <qiang.xue@gmail.com> * @since 2.0 */class ActiveDataProvider extends BaseDataProvider{    /**     * @var QueryInterface the query that is used to fetch data models and [[totalCount]]     * if it is not explicitly set.     */    public $query;    /**     * @var string|callable the column that is used as the key of the data models.     * This can be either a column name, or a callable that returns the key value of a given data model.     *     * If this is not set, the following rules will be used to determine the keys of the data models:     *     * - If [[query]] is an [[\yii\db\ActiveQuery]] instance, the primary keys of [[\yii\db\ActiveQuery::modelClass]] will be used.     * - Otherwise, the keys of the [[models]] array will be used.     *     * @see getKeys()     */    public $key;    /**     * @var Connection|array|string the DB connection object or the application component ID of the DB connection.     * If not set, the default DB connection will be used.     * Starting from version 2.0.2, this can also be a configuration array for creating the object.     */    public $db;    /**     * Initializes the DB connection component.     * This method will initialize the [[db]] property to make sure it refers to a valid DB connection.     * @throws InvalidConfigException if [[db]] is invalid.     */    public function init()    {        parent::init();        if (is_string($this->db)) {            $this->db = Instance::ensure($this->db, Connection::className());        }    }    /**     * {@inheritdoc}     */    protected function prepareModels()    {        if (!$this->query instanceof QueryInterface) {            throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.');        }        $query = clone $this->query;        if (($pagination = $this->getPagination()) !== false) {            $pagination->totalCount = $this->getTotalCount();            if ($pagination->totalCount === 0) {                return [];            }            $query->limit($pagination->getLimit())->offset($pagination->getOffset());        }        if (($sort = $this->getSort()) !== false) {            $query->addOrderBy($sort->getOrders());        }        return $query->all($this->db);    }    /**     * {@inheritdoc}     */    protected function prepareKeys($models)    {        $keys = [];        if ($this->key !== null) {            foreach ($models as $model) {                if (is_string($this->key)) {                    $keys[] = $model[$this->key];                } else {                    $keys[] = call_user_func($this->key, $model);                }            }            return $keys;        } elseif ($this->query instanceof ActiveQueryInterface) {            /* @var $class \yii\db\ActiveRecordInterface */            $class = $this->query->modelClass;            $pks = $class::primaryKey();            if (count($pks) === 1) {                $pk = $pks[0];                foreach ($models as $model) {                    $keys[] = $model[$pk];                }            } else {                foreach ($models as $model) {                    $kk = [];                    foreach ($pks as $pk) {                        $kk[$pk] = $model[$pk];                    }                    $keys[] = $kk;                }            }            return $keys;        }        return array_keys($models);    }    /**     * {@inheritdoc}     */    protected function prepareTotalCount()    {        if (!$this->query instanceof QueryInterface) {            throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.');        }        $query = clone $this->query;        return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db);    }    /**     * {@inheritdoc}     */    public function setSort($value)    {        parent::setSort($value);        if (($sort = $this->getSort()) !== false && $this->query instanceof ActiveQueryInterface) {            /* @var $modelClass Model */            $modelClass = $this->query->modelClass;            $model = $modelClass::instance();            if (empty($sort->attributes)) {                foreach ($model->attributes() as $attribute) {                    $sort->attributes[$attribute] = [                        'asc' => [$attribute => SORT_ASC],                        'desc' => [$attribute => SORT_DESC],                        'label' => $model->getAttributeLabel($attribute),                    ];                }            } else {                foreach ($sort->attributes as $attribute => $config) {                    if (!isset($config['label'])) {                        $sort->attributes[$attribute]['label'] = $model->getAttributeLabel($attribute);                    }                }            }        }    }    public function __clone()    {        if (is_object($this->query)) {            $this->query = clone $this->query;        }        parent::__clone();    }}
 |