Краткий ответ: это невозможно .
Отношения ActiveRecord сложнее, чем вы думаете, и надежное поддержание таких условий действительно сложно / невозможно.Проблема в том, что отношение может использоваться в разных контекстах:
- Присоединиться :
select * from chat_messages join users on users.id = chat_messages.from_user
. - Ленивая загрузка :
select * from users where users.id = 1
. - Стремительная загрузка :
select * from users where users.id IN (1, 2, 3, 4)
.
Как вы видите, трудно преобразовать ваше on
условие, чтобы соответствовать каждому из этих трехтипы запросов ( см. эту проблему на GitHub ).
Вы можете попытаться переопределить ActiveQuery
для поддержки вашего состояния, но гораздо проще (и, вероятно, достаточно хорошо) использовать два отношения и создать несколько помощников, чтобы сделать доступ к этим отношениям более удобным:
public function getUserFrom() {
return $this->hasOne(User::className(), ['id' => 'user_from']);
}
public function getUserTo() {
return $this->hasOne(User::className(), ['id' => 'user_to']);
}
public function getUser() {
return Yii::$app->user->id == $this->user_from ? $this->userFrom : $this->userTo;
}
Триггерная загрузка:
ChatMessage::find()->with(['userFrom', 'userTo'])->all();
Этого должно быть достаточно для простых случаев.Для более сложных сценариев вам нужно будет писать запросы вручную.
Обратите внимание, что использование Yii::$app->user->id
в вашей модели считается плохой практикой:
В итоге, модели /... /
- НЕ ДОЛЖЕН иметь прямой доступ к запросу, сеансу или любым другим данным о среде.Эти данные должны вводиться контроллерами в модели;
https://www.yiiframework.com/doc/guide/2.0/en/structure-models#best-practices