|
@@ -2,12 +2,145 @@
|
|
|
|
|
|
## ActiveQuery
|
|
|
|
|
|
-Предназначена для получения данных из БД, конструирования запросов. Под капотом преобразует цепочку вызовов (с возвратом `$this`) в SQL, который выполняется *лениво*, т. е. обычно во `view`.
|
|
|
+### 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` и дополнительные настройки к нему, например *пагинацию*.
|
|
|
|
|
|
-## PHPDoc
|
|
|
|
|
|
-Формат комментариев, предназначенный для документирования кода. Парсится IDE и генераторами документации.
|
|
|
+```php
|
|
|
+$provider = new ActiveDataProvider([
|
|
|
+ 'query' => User::find(),
|
|
|
+ 'pagination' => [
|
|
|
+ 'pageSize' => 10,
|
|
|
+ ],
|
|
|
+ 'sort' => [
|
|
|
+ 'defaultOrder' => [
|
|
|
+ 'username' => SORT_ASC,
|
|
|
+ ]
|
|
|
+ ],
|
|
|
+]);
|
|
|
+```
|
|
|
+
|
|
|
+$sortedUsers = $provider->getModels();
|
|
|
+
|
|
|
+Обычно *весь* объект `ActiveDataProvider` передается во view, где view может использоваться для настройки сортировок, пагинации и фильтрации.
|
|
|
+
|