Я использую конструктор красноречивых запросов для создания поискового запроса, условно зависящего от параметров, предоставленных поисковым запросом пользователей.

Кажется, это работает для атрибутов, которые напрямую принадлежат модели, которую я ищу. Однако у меня возникают проблемы при попытке вернуть дополнительные результаты, которые связаны с моделью, но не относятся непосредственно к модели.

Что именно я пытаюсь сделать:

Я пытаюсь разрешить пользователям искать школы по имени учителя, где имя / ключевое слово появляется в отношении школы через промежуточную таблицу.

Вот мои модели и отношения:

Школа:

class School extends Authenticatable
{
    protected $fillable = [
        'school_name', 'head_teacher', 'address'
    ];

    public function teachers()
    {
        return $this->belongsToMany(Teacher::class, 'teacher_links', 'school_id', 'teacher_id');
    }
}

Учитель:

class Teacher extends Authenticatable
{
    use Notifiable;

    protected $table = 'teacher';

    protected $fillable = [
        'name'
    ];

}

TeacherLink:

class TeacherLink extends Authenticatable
{
    protected $table = 'teacher_links';
    protected $fillable = [
        'teacher_id', 'school_id'
    ];

Я могу успешно запросить учителей через школу в контроллере, используя $school->teachers, так что я знаю, что связь работает нормально.

Вот мой код для контроллера, в котором параметры поиска пользователей условно построены:

public function index(Request $request)
{
    $schools = School::query();

    // User Search Term
    $search = $request->get('search');
    $headTeacher = $request->get('head_teacher');

    $questions
        ->when($search, function ($q) use ($search) {
            $q->where('school_name', 'like', '%' . $search . '%')
                ->orWhere('head_teacher', 'like', '%' . $search . '%')
                
                // This is the query i'm having an issue with
                ->whereHas('teachers', function($q) use ($search) {
                    $q->where('teacher_name', 'like', '%' . $search . '%');
                });

        })

}

Два начальных предложения where возвращают правильные результаты при поиске по названию школы или head_teacher, поскольку эти два свойства напрямую принадлежат школе. Однако я хотел бы вернуть дополнительные школы, в которых имя учителя указано в отношениях.

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

Первоначально я пытался использовать функцию объединения и объединения, которые работали, но нарушили последующие предложения where, поскольку, похоже, не разрешено следовать предложениям where после запросов на объединение.

Было бы здорово, если бы кто-нибудь мог сказать мне, что я делаю не так и как я могу исправить рассматриваемый запрос:

            // This is the query i'm having an issue with
            ->whereHas('teachers', function($q) use ($search) {
                $q->where('teacher_name', 'like', '%' . $search . '%');
            });

ИЗМЕНИТЬ

Я пробовал следующее, которое, похоже, работает, но работает медленно:

$schools
        ->when($search, function ($q) use ($search) {
            $q->join("teacher_links", function ($join) {
                    $join->on("teacher_links.school_id", "=", "schools.id");
                })
                ->join("teachers", function ($join) {
                    $join->on("teachers.id", "=", "teacher_links.teacher_id");
                })
                ->select("schools.*")
                ->where("teachers.teacher_name", 'like', '%' . $search . '%')
                ->orWhere('school_name', 'like', '%' . $search . '%')
                ->orWhere('school_address', 'like', '%' . $search . '%')
                ->orWhere('school_focus', 'like', '%' . $search . '%');
        });
1
Bob Deli 14 Окт 2021 в 17:44

2 ответа

Лучший ответ

Вместо этого попробуйте использовать в этом запросе orWhereHas.

->when($search, function ($q) use ($search) {
    $q->where('school_name', 'like', '%' . $search . '%')
        ->orWhere('head_teacher', 'like', '%' . $search . '%')
        ->orWhereHas('teachers', function ($sub) use ($search) {
            $sub->where('teacher_name', 'like', '%' . $search . '%');
        });
    });
1
IGP 14 Окт 2021 в 18:48

Попробуйте использовать красноречивые отношения

School::where('school_name', 'like', '%' . $search . '%')
  ->orWhere('head_teacher', 'like', '%' . $search . '%')
  ->with(['teachers'=>function($query) use ($search) {
      return $query->orwhere('teacher_name', 'like', '%' . $search . '%');
    }]
  )->get();
0
Shahzad Manzoor 14 Окт 2021 в 19:46