Добрый день, пишу для сайта умный фильтр по аналогии Яндекс.Маркета. Собственно уже который день озадачился вопросом реализация релятивного фильтра. Что имеем: Динамическую форму: (Форма генерируется автоматически, но для наглядности вставил HTML) Код (Text): <form method="get" action=""> <div> <label>Asus</label> <input type="checkbox" name="filter[]" value="Asus"> <label>Acer</label> <input type="checkbox" name="filter[]" value="Acer"> <label>Lenovo</label> <input type="checkbox" name="filter[]" value="Lenovo"> </div> <div> <label>2015</label> <input type="checkbox" name="filter[]" value="2015"> <label>2014</label> <input type="checkbox" name="filter[]" value="2014"> <label>2013</label> <input type="checkbox" name="filter[]" value="2013"> </div> <button>Искать</button> </form> После сабмита формы имеется url следующего вида: Код (Text): site.com?filter=Asus&filter=2015 Так же имеем таблицы в базе данных: Код (Text): products (id, title) products_to_filter (id, product_id, filter_id) Сам обработчик выглядит следующим образом (P.S фреймворк Laravel) Код (Text): Выборка соответствующих фильтров. $filter[] = explode(',', $request->input('filter'); $filters = DB::table('products_to_filter')->whereIn('id', $filter) ->get() ->all(); foreach($filters as $row) {$filterArray[] = $row->product_id;} Выборка продуктов: $products = DB::table('products')->whereIn('id', $filterArray)->get()->all(); Собственно моя проблема заключается в следующем, фильтр работает, но не совсем так как мне нужно, тобишь при фильтрации, он должен результаты уменьшать, а он же наоборот ищет более углубленно, и как следствие увеличивает кол-во результатов. Как решить данную проблему?
Я тебя в пол шестого могу спросить - вот как, ты думаешь, выглядит SQL запрос? Посмотреть запрос - это первое, что надо сделать. В SQL оператор IN объединяет перечисленные значения через OR. Ясень пень, чем больше "или", тем больше вариантов. Тебе надо строить WHERE через AND. В Lavarel, по-ходу, вместо одного whereIn делать where на каждый параметр со знаком "=".
Здравствуйте, а как произвести постройку запроса WHERE если данные в нём каждый раз меняются динамически? То есть я конечно могу составить запрос единожды, но проблема заключается в том, что необходимо данный запрос сделать максимально динамическим. Код (Text): SELECT * FROM products_to_filter WHERE filter_id = 'Asus' AND filter_id = '2015' Ведь данные каждый раз могут быть абсолютно разными.
@Игонь ну у тебя же конечное число параметров в фильтре. Зафигачь if-else, или строй запрос строкой SQL а не через методы. Глянул код внимательнее, по-ходу надо так Код (Text): DB::table('products')->whereIn(...)->whereIn(...)->whereIn(...)->whereIn(...) но я о Lavarel сужу по докам. Короче итог в логике, для сужения поиска нужно объединять условия.
Очень признателен за то, что в 6 утра помогаете. В итоге пытаюсь сделать что-то вроде этого: Код (Text): foreach($filter as $key => $row) { if($key == 0) { $sqlArray[] = 'filter_id = ' . $row; } else { $sqlArray[] = 'and filter_id = ' . $row; } } $sql = implode(' ', $sqlArray); $test = DB::table('filters_to_products') ->where('category_id', $category) ->where($sql) ->get(); Но возможно где-то могу ошибиться, скажите пожалуйста, на чистом SQL правильный вид запроса как должен выглядеть?
@Игонь в общем пораскинув мозгами, я понял что всё немного сложнее, и задача решается таким запросом Код (Text): SELECT `product_id`, COUNT(DISTINCT `filter_id`) as `filters` FROM `products_to_filter` WHERE `filter_id` IN (0,1,2) GROUP BY `filter_id` HAVING `filters` = 3; Где 3 - количество используемых фильтров. Поле filters будет = 3 только у тех продуктов, которые соответствовали всем трем 0,1,2.
Решил проблему следующим образом: Модель Код (Text): public static function getProductByFilter($category, $filter) { foreach($filter as $key => $row) { $sqlArray[] = 'and filter_id = ' . $row; } $sql = implode(' ', $sqlArray); $filterProductsArray = DB::select('SELECT * FROM filters_to_products WHERE category_id = ' . $category . ' ' . $sql); if($filterProductsArray) { foreach($filterProductsArray as $product) $productsArray[] = $product->product_id; $products = Product::whereIn('id', $productsArray) ->orderBy('id', 'desc'); return $products; } } Контроллер: Код (Text): if($request->input('filter')) { foreach($request->input('filter') as $row) $filter[] = $row; $products = Product::getProductByFilter($page->id, $filter); if($products) $products = $products->paginate(10); } else { $products = Product::getProductsForCategory($page->id); if($products) $products = $products->paginate(10); } Что скажете о данной реализации?
@Игонь мне кажется, что эта идея была ошибкой и запрос, построенный таким образом, всегда будет давать пустой результат.) --- Добавлено --- Запрос с подсчетом совпавших фильтров точно сработает