Многоуровневые отношения Laravel

#php #html #laravel #vue.js

Вопрос:

Я работаю над приложением чата в laravel/vue, и в этом приложении у меня есть пользователи, у каждого пользователя есть несколько комнат, в каждой комнате есть по крайней мере 2 пользователя и несколько сообщений, которые я пытаюсь связать или запросить, чтобы получить все комнаты для каждого пользователя и сообщения в них

 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();
    });
 

Ответ №1:

То, что у вас есть, хорошо. Я бы просто достал ключ foriegn user_id из комнат и получил доступ к комнате пользователя через их сообщения. Следовательно, messages это будет похоже на сводную таблицу, делающую отношения между пользователями и комнатами многими ко многим.

Следовательно, чтобы получить доступ к комнатам пользователя, я бы

$rooms = User::find(1)->rooms()->get();

Для доступа к пользователям в комнате

$users = Room::find(1)->users()->get();

Отображать сообщения пользователя в каждой комнате было бы похоже на доступ к сводной таблице. Следовательно

 $user = User::find(1);

foreach ($user->rooms as $rooms) {
    echo $rooms->pivot->content;
}

 

Итак, это отношение «многие ко многим», и сообщение является сводной таблицей. Я буду придерживаться документации для получения более подробной информации.

Комментарии:

1. Если у нас много комнат для пользователя, у нас будет для каждого пользователя $user->комнаты как $комната, а для каждого пользователя $room->>сообщения как $сообщение или групповое сообщение каждого пользователя по room_id.

2. Да, у нас может быть много комнат для каждого пользователя. Вот почему я запросил одного пользователя и получил все комнаты, в которых находится пользователь. Затем вы продолжаете цикл for, как вы предлагали. Кроме того, в каждой комнате есть несколько сообщений, но все они принадлежат пользователю, а не комнате. Следовательно, вы получаете сообщения с помощью $rooms->pivot->content или $users->pivot->content

3. Мы уже должны знать, что здесь, безусловно, речь идет о том, чтобы иметь все сообщения пользователей комнаты или только сообщения активного пользователя в комнате, и, поскольку иметь все сообщения пользователя Через комнаты-это не хазманитета, Вы уже должны знать, что здесь, безусловно, речь идет о том, чтобы иметь все сообщения пользователей комнаты, а не только сообщения рассматриваемого пользователя, и, поскольку это не Хасманитета, мы будем получать сообщения от всех пользователей. мне кажется, что мы будем получать сообщения от всех пользователей в комнате, и я думаю, что это правильный способ, или что?

Ответ №2:

Лучшее решение, которое я нашел, — это создать сложные отношения, подобные этим //отношения

 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;
}
 

в getinit я просто использую это отношение друг за другом, например (друзья.комнаты)

laravel будет использовать отношение «друзья», тогда в каждом результате будет использоваться отношение «комнаты» в моем случае мне просто нужно выбрать комнаты, которые есть у пользователя и друга, поэтому я ограничил связь, используя, где комнаты принадлежат пользователю аутентификации, например, если мы скажем, что у пользователя аутентификации есть комнаты 2,3,4, а у его друга 3,1,5, поэтому отношение «комната» вернет только объединение комнат пользователя аутентификации и комнат друзей в нашем случае 3, тогда я возвращаю сообщения в каждой комнате, но для целей дизайна мне просто нужно последнее сообщение для каждой комнаты, поэтому я ограничиваю свое сообщение отношением 1 и в getinit заказываю их по дате создания