Применение области по умолчанию со ссылкой на отношение в yii
Я не могу найти слишком много документации по применению области действия по умолчанию к модели в yii, мне было интересно, может ли кто-нибудь объяснить или указать мне правильное направление.
Быстрая версия моего вопроса:
Можно ли добавить отношение к области действия по умолчанию или добавить критерии "с" по умолчанию к каждому поиску AR в модели?
Длинная версия моего вопроса:
Краткий обзор моего приложения:
У меня есть две модели, provider
а также item
, Которые имеют отношение am: 1, где у поставщика может быть много элементов, но у каждого элемента может быть только один поставщик.
Пока у меня есть эти отношения:
class Provider extends CActiveRecord
{
...
public function relations()
{
return array(
'items' => array(self::HAS_MANY, 'Item', 'id_provider', 'order'=>'rank DESC'),
);
}
...
}
class Item extends CActiveRecord
{
...
public function relations()
{
return array(
'provider' => array(self::BELONGS_TO, 'Provider', 'id_provider'),
);
}
...
}
В моей модели элементов у меня уже есть defaultScope, который отфильтровывает все автономные элементы (т.е. отображает только элементы, для которых установлено значение offline = false
):
public function defaultScope()
{
$alias = $this->getTableAlias(false,false);
return array(
'condition'=>"`$alias`.`offline` = false",
);
}
То, что я хочу сделать сейчас, это также отфильтровать элементы, когда их провайдер отключен (т.е. показывать только элементы, где provider.offline = false
наряду с течением item.offline = false
).
Я попытался присоединиться к таблице провайдеров в defaultScope:
public function defaultScope()
{
$alias = $this->getTableAlias(false,false);
return array(
'join'=>"JOIN `provider` AS `provider` ON `provider`.`id` = `$alias`.`id_provider`",
'condition'=>"`$alias`.`offline` = false AND `provider`.`offline` = false",
);
}
Однако JOIN применяется после оператора ON и вызывает ошибку (CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'provider.offline' in 'on clause'
).
Я также попытался добавить с критериями в defaultScope:
public function defaultScope()
{
$alias = $this->getTableAlias(false,false);
return array(
'with'=>"provider",
'condition'=>"`$alias`.`offline` = false AND `provider`.`offline` = false",
);
}
Но я получаю ту же ошибку: SQLSTATE[42S22]: Столбец не найден: 1054 Неизвестный столбец 'provider.offline' в 'предложении').
Какие-либо предложения?
2 ответа
Есть пара вещей, которые я бы попробовал:
Во-первых, измените ваше условие, чтобы оно распространялось на все это (и не забывайте, что если для провайдера нет товаров, он не вернет провайдера)
public function defaultScope()
{
return array(
'with'=> array("provider" => array(
'condition'=> "t.offline = false AND provider.offline = false",
)
);
}
Во-вторых, попробуйте добавить области к вашим моделям, а затем сослаться на них в области по умолчанию следующим образом:
public function defaultScope()
{
return array(
'scopes'=> array('default'),
);
}
class Provider extends CActiveRecord
{
...
public function scopes()
{
...
}
...
}
class Item extends CActiveRecord
{
...
public function scopes()
{
...
}
...
}
Просто была похожая проблема. В то время как первое предложение Бенджамина указало мне правильное направление (высоко ценится!), Я столкнулся с неожиданной проблемой, используя "условие" и "с", о которых может быть полезно знать.
Если таблица, к которой вы присоединяетесь (в данном случае "поставщик"), имеет свой собственный defaultScope, кажется, что он применяется как часть предложения SQL ON при использовании "с", ограничивая возвращаемые строки.
Поскольку используется внешнее соединение, вы по-прежнему получаете запись назад для каждой строки в первичной таблице ('item'), но поля 'provider' могут быть нулевыми для некоторых строк, если defaultScope провайдера предотвращает возврат этих строк.
Это не вызывает проблемы, пока вы не попытаетесь применить "условие", включающее одно из этих полей провайдера. Это делается как часть предложения WHERE, которое обрабатывается после объединения, но поскольку это поле имеет значение null, условие не будет выполнено и запись не будет возвращена.
В некоторых случаях это может быть желаемое вами поведение, но в других случаях вы можете захотеть переместить тесты в полях "провайдера" в объединение, используя опцию on:
public function defaultScope()
{
return array(
'with'=> array("provider" => array(
'condition'=> "t.offline = false",
'on'=>"provider.offline = false",
)
);
}