Reputation: 29
I am working on chat application in laravel/vue and in this app I have users where each user have several rooms each room has at least 2 user in it and several messages I am trying to make relation or query to get all the rooms for each users and the messages in them
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->enum('status',['active','busy','Do Not Disturb']);
$table->timestamp('email_verified_at')->nullable();
$table->string('image')->default('user0.jpg');
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create('rooms', function (Blueprint $table) {
$table->id();
$table->string('room_unique');
$table->foreignId('user_id')->constrained()->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
Schema::create('messages', function (Blueprint $table) {
$table->id();
$table->enum('type',['text','image','link']);
$table->string('content');
$table->foreignId('user_id')->constrained()->onDelete('cascade')->onUpdate('cascade');
$table->foreignId('room_id')->constrained()->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
Upvotes: 1
Views: 71
Reputation: 29
The best solution i have found is to make complex relation like this //relations
public function message()
{
return $this->hasMany(messages::class)->take(1);
}
public function friends()
{
return $this->belongsToMany(User::class, 'friends', 'user_id', 'friend_id');
}
public function rooms()
{
return $this->belongsToMany(Room::class,'user_room','user_id','room_id');
}
public static function getInit()
{
//get room of auth user
$rooms = DB::table('user_room')->where('user_id',Auth::id())->select('room_id')->get()->toArray();
//flatten the array
$roomArray = array_column(json_decode(json_encode($rooms), true),'room_id');
//get users friends and rooms belong to auth user with the last message
$user = User::with(array('friends.rooms' => function($query) use ($roomArray){
$query->whereIn('rooms.id',$roomArray);
},'friends.rooms.messages' => function($query) {
$query->orderBy('created_at','Desc');
}))->whereId(Auth::id())->get()->toArray();
return $user;
}
in getinit I just use this relation after each other like (friends.rooms)
laravel will use friends relation then each result will use rooms relation on it in my case i just need to pick rooms that user and friend have so i limited the relation by using where in rooms belong to the auth user like if we say the auth user has rooms 2,3,4 and his friend has 3,1,5 so the room relation will only return the union of auth user rooms and friend rooms in our case it's 3 then i return messages in each room but for design purpose i just need the last message for each room so i limit my relation message to take 1 and in getinit order them by created date desc
Upvotes: 0
Reputation: 339
What you have is good. I would just take out the foriegn key user_id
from rooms and access user's room through their messages. Hence, messages
will be like a pivot table making the relationship between users and rooms many to many.
Hence to access the rooms of a user I would
$rooms = User::find(1)->rooms()->get();
To access users in a room
$users = Room::find(1)->users()->get();
To display messages of a user per room would be like accessing pivot table. Hence
$user = User::find(1);
foreach ($user->rooms as $rooms) {
echo $rooms->pivot->content;
}
So, this is many to many relationship and message is the pivot table. I will stick with the documentation for more details.
Upvotes: 1