Как выполнить вложенный запрос Laravel

#php #laravel #laravel-7

#php #laravel #laravel-7

Вопрос:

У меня есть следующие 3 таблицы

Классы

id subject

Зарегистрированные студенты

id user_id class_id

Публикации

id class_id type attachment

Модели

Classroom.php

 public function posts()
{
   return $this->hasMany(Post::class);
}
 

RegisteredStudents.php

 public function classroom()
{
  return $this->belongsTo(Classroom::class);
}
 

Post.php

 public function classroom()
{
  return $this->belongsTo(Classroom::class);
}
 

Теперь мне нужно получить все записи определенного класса, под которым зарегистрирован студент.

например, студент зарегистрирован для класса, идентификатор которого равен 1 в таблице classroom. таким образом, в таблице registered_students будет отмечено, что этот конкретный пользователь зарегистрирован в этом конкретном классе. Каждый класс может иметь несколько записей в таблице post. И пользователю необходимо получить все сообщения своего класса.

Я пытаюсь сделать что-то вроде этого:

  $registered_classes = RegisteredStudent::where('user_id',$user->id)
            ->where(function ($q) use ($class_id){
                Post::where('class_id',$class_id);
            })->get();
 

что определенно неверно. каким будет правильный запрос для этого.

Ответ №1:

Вы создали RegisteredStudent модель с classroom отношением. Проблема в том, что если ваше foreign_key поведение отличается от поведения Laravel, вы должны включить его в отношение. Вот так:

Classroom.php

 public function posts(): HasMany
{
    return $this->hasMany(Post::class, 'class_id');
}
 

* Поведение Laravel требует, чтобы вы использовали classroom_id вместо class_id

RegisteredStudent.php

 public function classroom(): BelongsTo
{
    return $this->belongsTo(Classroom::class, 'class_id');
}

public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}
 

Post.php

 public function classroom(): BelongsTo
{
    return $this->belongsTo(Classroom::class, 'class_id');
}
 

Более подробно о поведении Laravel с полными примерами здесь

* Отредактировано

Затем, если вы хотите получить все записи определенного класса, в котором зарегистрирован учащийся, вы можете использовать with метод:

 public function getAllPostsClassroom()
{
    $registeredUser = RegisteredStudent::where('user_id', $user->id)->with(['classroom.posts' => function($query) use ($class_id) {
        $query->where('class_id', $class_id);
    }])->first();
}
 

И вы получите все Posts внутри Classroom зарегистрированного пользователя

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

1. это не дает ПОЛНОГО ответа на вопрос. Он в первую очередь запрашивает правильный запрос

2. каким будет запрос?

3. Отредактировано @OsmanRafi. Пожалуйста, дайте мне знать, работает ли это.

4. этот запрос не возвращает Posts, а возвращает экземпляр RegiateredStudent

5. У них должна быть установлена hasManyThrough связь от User до Classroom . RegisteredStudent это просто сводная модель, и она не должна напрямую участвовать в запросе.

Ответ №2:

Сначала вам нужно исправить отношения, как TheArKa указано в его ответе (поскольку имена таблиц и классов неправильно соответствуют соглашению laravel eloquent).

Classroom.php

 public function posts()
{
    return $this->hasMany(Post::class, 'class_id');
}
 

RegisteredStudent.php

 public function classroom()
{
    return $this->belongsTo(Classroom::class, 'class_id');
}
 

Тогда правильный запрос должен быть:

 $posts_of_class_of_user =
RegisteredStudent::where('user_id',$user->id)->first()->classroom->posts;
 

Сначала это приведет к получению зарегистрированного пользователя из RegisteredStudent, а затем он получит экземпляр Classroom из relatationsto relatation, а затем получит все связанные posts с hasMany отношения.

Обратите внимание, что, используя отношение, вы можете избежать сложных запросов, особенно в вашем случае. Вам не нужен какой-либо сложный запрос. Просто используйте красноречивый реляционный подход.

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

1. Он выдает сообщение «Свойство [класс] не существует в экземпляре Eloquent builder».

2. opps, просто ->first() отсутствует перед классом. обновляю свой ответ сейчас

3. RegisteredStudent не имеет прямого отношения к Post. поэтому ->posts предполагается, что он выдает ошибку. Это может сработать, если вы создадите отношение ‘hasManyThrough` в модели. @Psycho

4. то, о чем вы говорите, — это прямой доступ к сообщениям без классной RegisteredStudent::where('user_id',$user->id)->first()->posts комнаты, который выполняется с помощью hasManyThrough, но я получаю доступ, как classroom->posts