donglao7947 2017-05-10 17:29
浏览 47
已采纳

Laravel与当前用户参与的所有参与者进行所有对话

I have four tables. User, Conversations, Message and Conversation_Participants. I hope you don't find a relationship error in this image (I hope you don't find a relationship error in this image )

I tried to add a function

public function conversations(){

    return $this->belongsToMany(Conversation::class, 'conversation_participants', 'user_id', 'conversation_id');
}

to User::class but if i call User::with('conversations')->get() i only get all existing Users. What am I doing wrong? First i want to get all conversations the current user participates in and second I want to get all receivers of the conversations.

I also tried

public function participants()
{
    return $this->belongsToMany(User::class, 'conversation_participants', 'user_id', 'conversation_id');
}

in the Conversation::class but Conversation::with('participants')->get() gets me all Conversation even those the user isn't participating in.

I'm really confused atm :/

  • 写回答

2条回答 默认 最新

  • douyi4912 2017-05-10 17:42
    关注

    Add the following in your User model:

    public function conversations() {
        return $this->belongsToMany(Conversation::class, 'conversation_participants', 'users_id', 'conversations_id');
    }
    

    And this to your Conversation model:

    public function participants() {
        return $this->belongsToMany(User::class, 'conversation_participants', 'conversation_id', 'users_id');
    }
    

    If you want to link your tables easier, read up on conventions.

    To get all the conversations a user is participating in, run the following (assuming you've loaded the user): $user->conversations() to get all the conversations a user is in.

    If you want all users, with all their conversations, with all the participants connected, do the following: $users = Users::with('conversations.participants')->get(). You can now loop through this as follows:

    foreach($users as $user) {
        foreach($user->conversations as $conversation) { 
            foreach($conversations->participants as $participant) {
                // do fancy stuff here
            }
        }
    }
    

    Notice that the user from which you start is also a participant, so maybe you need to filter that one out again.

    If you want to get even more fancy (but use more resources) you could even query all the messages a conversation has too!

    User::with('conversations.participants', 'conversations.messages.user')->get()
    

    But this only works when you set up a second set of relationships along the upper table in your image (conversations <-> messages <-> users)

    Edit

    In the comments, OP asked if it was possible to limit the amount of messages retrieved from the database, which is possible to my knowledge, but I don't now if this is the best way:

    Remove the messages from the first eager loading part:

    User::with('conversations.participants')
    

    After that, when looping through the conversations, lazy load the messages:

    $conversation->load(['messages' => function($query){
        $query->take(5);
    }, 'users']);
    

    Access them after that with $conversation->messages.

    Note

    I think this could be done more easily in one go, but I don't have a setup right now to test this for you.

    Edit 2

    After Ronon added another comment, here's what I came up with:

    Add a new relationship in the Conversation model:

    public function last_messages() {
        return $this->hasMany(Message::class, 'conversation_id', 'id')->latest()->limit(2);
    }
    

    Because of that, you now can do this:

    User::with('conversations.participants', 'conversations.last_messages.users')->get()
    

    If you still want all the messages, you can use the messages relationship. If you want less, use the last_messages one.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?