Получить все объекты, которые существуют в двух коллекциях - PullRequest
0 голосов
/ 31 января 2019

Я создаю страницу Laravel, на которой я хочу показать список уроков.Какие уроки должны быть на странице, отфильтрованы по трем критериям (из которых все должно быть правдой):

  1. Урок активен, т. Е. «Где ('active', true)".Достаточно просто.
  2. Урок является частью дорожки, которую выбрал пользователь.Модели настраиваются с помощью метод ownToMany () (это отношение «многие ко многим»), поэтому я могу получить эти уроки с помощью простого $ track-> уроки.
  3. Здесь все становится сложнее.Некоторые уроки должны быть видны только пользователям с определенными названиями (т. Е. Между названиями и уроками может быть много-много).Я могу получить уроки с правильным требованием к названию, используя Auth :: user () -> title-> уроки.

Вопрос в том, как собрать все это вместе.Лучшее, что я придумал, это следующее:

$title = Auth::user()->title;
$lessons = Lesson::where('active', true)
    ->whereIn('id', $track->lessons->pluck('id'))
    ->where(function ($query) use($title) {
      $query->whereIn('id', $title->lessons->pluck('id'))->orWhere('limited_by_title', false);
    })
    ->get();

... что безобразно, явно неоптимально и (по некоторым причинам я действительно не понимаю) также не будет работать(Я не получаю уроки, на которые мой титул дает мне право в моем списке).Уже несколько часов бьюсь, у меня такое ощущение, что я слишком усложняю, сначала выщипываю идентификаторы, а затем использую их в whereIn (), не может быть хорошим способом сделать это.

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

Ответы [ 3 ]

0 голосов
/ 31 января 2019

Использование whereHas() - это ответ на ваши опасения по поводу получения идентификаторов.Вместо выполнения дополнительных запросов для получения идентификаторов whereHas() будет прикреплять ограничение к исходному запросу в качестве подзапроса для связанных таблиц.

Разбиение запроса на его части:

1:Ответ

2: Предполагается, что обратное значение $ track-> уроки равно $ lesson-> track, а $ track исходит из кода, который вы не включили:

$lessons = Lesson::whereHas('tracks', function ($query) use ($track) {
            $query->where('id', $track->id);
        })

3: Предполагаяобратное значение $ title-> уроки равно $ lesson-> title:

$lessons = Lesson::where(function ($query) use ($title) {
                         $query->whereHas('titles', function ($query) use ($title) {
                             $query->where('id', $title->id);
                         })
                               ->orWhere('limited_by_title', false);
                     })

Объединено обратно в одно:

    $track = ???;
    $title = Auth::user()->title;
    $lessons = Lesson::where('active', true)
                     ->whereHas('tracks', function ($query) use ($track) {
                         $query->where('id', $track->id);
                     })
                     ->where(function ($query) use ($title) {
                         $query->whereHas('titles', function ($query) use ($title) {
                             $query->where('id', $title->id);

                         })
                               ->orWhere('limited_by_title', false);
                     })
                     ->get();

Если это все еще не дает ожидаемых результатовВы можете проверить полный запрос, заменив get() на toSql().Иногда работа с ORM в качестве отправной точки вместо SQL может привести вас по неверному пути.Для более подробной информации об отладке и понимании выполняемых запросов вы можете включить ведение журнала запросов: https://laravel.com/docs/5.7/database#listening-for-query-events

0 голосов
/ 31 января 2019

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

Однако, учитывая, что вы не хотите идти по этому пути, вы можете сделать это проще, используя join

Предполагая, что у вас следующая структура таблицы:

  • пользователи
  • заголовки (с внешним ключом user_id)
  • уроки (с внешним ключом title_id)
  • дорожек (имеет внешний ключ lesson_id)

    $trackName = $request->input('track_name');
    $title = Auth::user()->title;
    $lessons = Lesson::join('tracks', 'lessons.id', '=', 'tracks.lesson_id')
        ->join('titles', 'lessons.title_id', '=', 'titles.id')
        ->where('lessons.active', true)
        ->where('tracks.track_name', $trackName)
        ->where(function ($query) use($title) {
          $query->where('titles.id', $title->id)->orWhere('lessons.limited_by_title', false);
        });
    
    dd($lessons);
    

Это, конечно, если ваши пользовательские таблицы и заголовки имеют отношение один к одному, в противном случае соберите все title_ids и используйте вместо этого whereInwhere для запроса title.id.

Надеюсь, у вас достаточно понимания структуры Laravel, чтобы понять и реализовать это решение.

Извините, у меня нет времени на корректуру илидать больше подробностей.Удачи!

Удачи, если после этого вам понадобится нумерация страниц: p Я сомневаюсь, что простой ->paginate() сработает: D

Надеюсь, это поможет

0 голосов
/ 31 января 2019

intead, где используется whereHas в отношении "заголовков"

$title = Auth::user()->title;
$lessons = Lesson::where('active', true)
          ->whereIn('id', $track->lessons->pluck('id'))
          ->whereHas('titles',function ($query) use($title) {
                   $query->whereIn('id', $title->pluck('id')) 
                         ->orWhere('limited_by_title', false);
           })->get();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...