如何通过字符串而非数组实现Yii2关系?

时间:2018-05-14 10:21:40

标签: string yii2 relation

我有一个名为ChatMessage的类。 DB中有2个主要列(from_user,to_user)。我想将这两列中的一列与User model id相关联。如何使用看起来像这样的关系查询

public function getChattedUser()
{
    return $this->hasOne(User::className(), '(case when(chat_message.from_user={Yii::$app->user->id}) then chat_message.to_user else chat_message.from_user END)=user.id');
}

2 个答案:

答案 0 :(得分:0)

简短回答:这是不可能的

ActiveRecord关系比你想象的更复杂,以可靠的方式支持这些条件真的很复杂/不可能。问题是关系可能在不同的环境中使用:

  1. 加入select * from chat_messages join users on users.id = chat_messages.from_user
  2. 延迟加载select * from users where users.id = 1
  3. 急切加载select * from users where users.id IN (1, 2, 3, 4)
  4. 您可能会发现很难将on条件转换为适合这三种类型的查询(see this issue at 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

答案 1 :(得分:-2)

只需在关系函数中添加if语句即可实现。只需在if语句中编写case逻辑,如下所示:

public function getChattedUser()
{
    if ($this->from_user == Yii::$app->user->id) {
        return $this->hasOne(User::className(), ['id' => 'to_user']);
    }
    return $this->hasOne(User::className(), ['id' => 'from_user']);
}