Несколько операторов Where из цикла в функции обратного вызова в Laravel/Красноречиво

#php #laravel #eloquent

Вопрос:

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

 $featureSlugs = ['security', 'mobile-app', '2FA'];

$exchanges = Exchange::whereHas('features', function ($q) use ($featureSlugs) {
                    $q->where('slug', $featureSlugs);
                })->get();
 

Что чрезвычайно странно, этот запрос работает для 1 или 2 функций, но что-либо большее, чем 2, он перестает работать и больше не фильтруется.

Я хочу, чтобы фильтр становился все уже и уже, поэтому используйте несколько операторов where для каждой функции, возвращая только те обмены, в которых есть все функции, выбранные пользователем. Это код, который я пытаюсь, и он не работает, но я думаю, демонстрирует, что я пытаюсь сделать:

 $exchanges = Exchange::whereHas('features', function ($q) use ($featureSlugs) {
                    foreach($featureSlugs as $featureSlug)
                    {
                        $q->where('slug', $featureSlug);
                    }
                })->get();
 

Как я могу поместить несколько операторов where для каждой функции в массив?

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

1. Моя рекомендация состоит в том, чтобы вы этого не делали, лучше заранее проверьте пули, а затем используйте условие whereIn('slug', $array_of_slugs)

2. Проблема с Where заключается в том, что он вернет любой обмен по крайней мере с 1 функцией в списке, а не только обмены со всеми 3 функциями

Ответ №1:

Попробуйте сделать это таким образом.

 $featureSlugs = ['security', 'mobile-app', '2FA'];

$exchanges = Exchange::whereHas('features', function ($query) use ($featureSlugs) {
    $query->distinct()->whereIn('slug', $featureSlugs);
}, '=', count($featureSlugs))->get();
 

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

1. Классно! Это работает! Я считаю, что это самое чистое решение.

2. Да, это так, и мне нравится, когда люди отмечают рабочее решение.

Ответ №2:

Ты идешь в правильном направлении. Вам просто нужно использовать whereIn или orWhere

 $exchanges = Exchange::whereHas('features', function ($q) use ($featureSlugs) {
    $q->whereIn('slug', $featureSlugs);

    // This one is not optimal of course
    foreach($featureSlugs as $featureSlug) {
        $q->orWhere('slug', $featureSlug);
    }
})->get();
 

Ответ №3:

Вы можете сделать это таким образом:

 $featureSlugs = ['security', 'mobile-app', '2FA'];

$exchanges = Exchange::whereHas('features', function ($q) use ($featureSlugs) {
                foreach($featureSlugs as $featureSlug)
                {
                    $q->where('slug', $featureSlug);
                }
            })-with(['features'=> function ($q) use ($featureSlugs) {
                foreach($featureSlugs as $featureSlug)
                {
                    $q->where('slug', $featureSlug);
                }
            }])->get();