Reputation: 140
I try to build simple conversation system for my app, but I have some troubles with planning that structure. When user go to 'conversation' page it should list all conversation where the user was sender or receiver with order by the newest messages. Then, when user open specific conversation it should list all messages from that conversation. I planned something like that:
Create Conversation table
$table->increments('id');
$table->integer('sender_id');
$table->integer('receiver_id');
$table->timestamps();
Create Messages table
$table->increments('id');
$table->text('message');
$table->integer('conversation_id');
$table->integer('user_id');
$table->timestamps();
Create Conversation and Message Model
User Model - ?
public function conversations()
{
return $this->hasMany('App\Conversation', 'sender_id');
}
Here I have troubles - I want to make relation with conversations where foreign key will be 'sender_id' or 'receiver_id' and return conversation order by the newest messages. How can I accomplish that? Can you give me some tips how solve relations between users, conversations and messages to return all information when I return user?
I really appreciate any help.
Upvotes: 1
Views: 734
Reputation: 2636
First of all, you should define the Conversation relationship with messages like this:
Conversation Model
public function messages()
{
return $this->hasMany('App\Message');
}
You should define the inverse relationship as well:
Message Model
public function conversation()
{
return $this->belongsTo('App\Conversation');
}
You could show all conversations by a user with the code below:
public function getConversations($userId)
{
$conversations = Conversation::where('sender_id',$userId)->orWhere('receiver_id',$userId);
return view('yourview', compact('conversations'));
}
In your view you could loop and find every message from every conversation:
@foreach($conversations as $conversation)
@foreach($conversation->messages as $message)
{{$message->message}}
@endforeach
@endforeach
In your conversations
table you could have a user_id
FK, also your relation should look like this:
User Model
public function conversations()
{
return $this->hasMany('App\Conversation', 'user_id');
}
Note: you could use the receiver_id
or sender_id
as a foreign key as well.
With this relation you could get all conversations from a user with this:
$user = User::find($id);
$user->conversations; // This will return all conversations from that user
You could also get all the messages from a user using the Has Many Through relationship:
public function messages()
{
return $this->hasManyThrough('App\Message', 'App\Conversation');
}
Another Approach
Another way to do it is creating a pivot table between users
and conversations
The conversation_user
table
id
user_id
conversation_id
This way a user could have many conversations (Many to many relationship).
You could change your messages
table to:
id
conversation_id
receiver_id
sender_id
content
...
Your Message Model
public function conversation()
{
return $this->belongsTo('App\Conversation', 'conversation_id');
}
The User model
public function conversations()
{
return $this->belongsToMany('App\Conversation');
}
The Conversation Model
public function users()
{
return $this->belongsToMany('App\User');
}
public function messages()
{
return $this->hasMany('App\Message');
}
I think this is the best way to do it
If you wanna get the conversation and the messages:
$user = User::find($id);
foreach($user->conversations as $conversation)
{
foreach($conversation->messages as $message)
{
echo $message->content;
}
}
Another simple way to do it is using the Message Model:
$userMessages = Message::where('receiver_id', $userId)->orWhere('sender_id',$userId)->get();
But this way you will only get the messages, you can find the conversation with this:
foreach($userMessages->conversation as $conversation)
{
echo $conversation;
}
Upvotes: 3
Reputation: 1494
My approach would be: I have conversations that have a subject. Every message has a conversation_id and a user_id that sends the message. and finally, in participants table, I would add the users that are part of the thread but not necessarily send a message in it.
So you must have a conversations table with just one subject, You must have participants table so that you must add users that part of a conversation. and finally, a messages table that you must save every message that user sends to a conversation.
for threads table:
Schema::create('conversations', function (Blueprint $table) {
$table->increments('id');
$table->string('subject');
$table->timestamps();
});
for messages table:
Schema::create('messages', function (Blueprint $table) {
$table->increments('id');
$table->integer('conversation_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->text('body');
$table->timestamps();
});
for any user that participates in the message:
Schema::create('participants', function (Blueprint $table) {
$table->increments('id');
$table->integer('conversation_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamp('last_read')->nullable();
$table->timestamps();
});
User Model:
public function conversations()
{
return $this->belongsToMany('App\Conversation', 'user_id');
}
Conversation Model:
public function messages()
{
return $this->belongsToMany('App\User', 'conversation_id');
}
Upvotes: 0