# ActiveQuery && ActiveDataProvider ## ActiveQuery ### ActiveRecord Для получения объекта **ActiveQuery** по таблице обычно используется статический метод `find` класса **ActiveRecord**: ```php //получение объекта ActiveRecord для пользователя $query = User::find(); .... //код find public static function find() { return new UserQuery(get_called_class()); } ``` `UserQuery`, в свою очередь, наследуется от `\yii\db\ActiveQuery` ### Query `ActiveQuery` унаследован от `Query`, который включает в себя стандартный набор возможностей **SQL** `SELECT`: ```php $query = new Query; $query->select('id, username')->from('user') ``` `groupBy`, `having`, `innerJoin`, `leftJoin` и так далее. #### Построение запросов и фильтрация Yii любит массивы, и в этом случае тоже: - Равенство `where(['id' => 15]])` // WHERE id = 15 - AND `where(['username' => 'someUser', 'password' => 'password'])` // WHERE username = 'someUser' AND password = 'password' - OR `where(['or',['username' => 'someUser'], ['password' => 'password'])` // WHERE username = 'someUser' OR password = 'password' - сравнение `where(['>', 'registration_date', '2016-12-31')` // WHERE registration_date > 2016-12-31 - подзапрос `where(['in', 'user_id', (new Query())->select('id')->from('enabled_users')] // WHERE user_id in (SELECT id FROM enable_users) Для уточнения запросов впоследствии, существуют методы `andWhere`, `orWhere`, `andFilterWhere`, `orFilterWhere` > *FilterWhere отличается от *Where тем. что отбрасывает пустые значения в запросе #### JOIN Для тех или иных присоединений таблиц используются методы `join`, `leftJoin`, `rightJoin`, `innerJoin` с набором параметров, аналогичным синтаксису `SQL`: `leftJoin('orders', ['orders.user_id' => 'users.id'])` // LEFT JOIN orders ON (orders.user_id = users.id) #### `$params` Параметры могут быть переданы сразу, или добавлены потом: ```php $query = new Query; $query->select('id, username')->from('user')->where(["status" => ":status"]) .... $query->addParams([":status" => "active"]) ``` `Query` в целом предназначен для конструктирования `SELECT` запросов и возвращает данные в форме ассоциативных массивов. На этом уровне иерархии объектов доступа данных **Yii** между запросами и объектами `ActiveRecord` нет связи. ### ActiveQuery Наследует `Query`, однако возвращает результат в форме массива соотвествующих `ActiveRecord`. Набор "оконечных" функций (тех, которые не возвращают `$this`): - one(): одна строка (`LIMIT 1`) - all(): все записи - count(): количество записей (`count(*)`) - sum(): сумма по указанной колонке - average(): средняя по указанной колонке - min(): минимум - max(): maximum - scalar(): возвращает первую ячейку первой строки результата запроса - column(): первая колонка - exists(): проверка на наличие результата запроса (Empty Set или нет) **ActiveQuery** (как и большинство других ORM) работает с помощью **chaining**, т. е. цепочки вызовов методов. Это работает благодаря тому, что каждый метод, конструирующий запрос в СУБД, возвращает $this: ```php User::find()->where(['username' => "root"])->one(); //Объект ActiveRecord ``` #### Связи с другими таблицами Для нормальной работы связанных данных связи должны быть установлены в соответствующих `ActiveRecord` с помощью `hasMany` и `hasOne`: ```php class User extends ActiveRecord { public function getOrders(){ return $this->hasMany(Order::className(), ['users_id' => 'id']]) } } class Order extends ActiveRecord { public function getUser(){ return $this->hasOne(User::className(), ['id' => 'users_id']]) } } ``` Используя `with` вы можете указать, что нужно загружать данные, включая связи. Под капотом это превращается в `LEFT JOIN`, который экономит ресурсы, по сравнению с обращением каждый раз к полю orders в каждой записи по нескольким выборкам ```php $users = User::find()->with('orders')->all() //один запрос print_r($users[0]->orders) //уже загружено $slowpokes = User::find()->all(); //один запрос foreach ($slowpokes as $slowpoke){ print_r($slowpoke->orders) //еще стопицот запросов в цикле } ``` ## ActiveDataProvider Позволяет использовать запрос `ActiveQuery` и дополнительные настройки к нему, например *пагинацию*. ```php $provider = new ActiveDataProvider([ 'query' => User::find(), 'pagination' => [ 'pageSize' => 10, ], 'sort' => [ 'defaultOrder' => [ 'username' => SORT_ASC, ] ], ]); ``` $sortedUsers = $provider->getModels(); Обычно *весь* объект `ActiveDataProvider` передается во view, где view может использоваться для настройки сортировок, пагинации и фильтрации. ## Expression и функции mySQL TODO