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