Вывод товаров по выбранным фильтрам

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Вывод товаров по выбранным фильтрам

Сообщение webplus »

Здравствуйте!
Есть фильтры с товарами:
Изображение
на изображения выбрано два фильтра из одной группы, вывело один товар который привязан к этим двум фильтрам. А всего у этих фильтров два товара, один привязан только к фильтру XL , а другой товар привязан к двум фильтрам к XL и XXL. Должно вывестись два товара.
Но это неправильно совпадения должны работать при выборе разных групп фильтров, т.е. если мы выбрали в группе Цвет -> Красный и выбрали Размер -> XL и XXL то должны вывестись товары у которых цвет "красный" и размер "XL" ИЛИ "XXL", а у меня все совпадения связанные. Т.е. в каждой группе фильтров связей не должно быть, а только связи между группами фильтров.
Вот код:

Код: Выделить всё

        $productsQuery = Product::find();
        if ($id !== null) {
             $productsQuery->where([Product::tableName() .'.category_id' => $id]);
        }

        if (count($filter_ids) > 0) {
            $productsQuery->select([Product::tableName() . '.*', 'Count(*) as total']);
            $productsQuery->joinWith(['filter']);
            $productsQuery->andWhere([ProductFilter::tableName() . '.filter_id' => $filter_ids]);
            $productsQuery->groupBy(ProductFilter::tableName() . '.product_id');
            $productsQuery->having('total = ' . count($filter_ids));
        }
Если убрать having то тогда нет точных совпадений фильтров в товаре, а нужно чтобы было например такое совпадение цвет "Красны" и размер "XL" - т.е. с этими фильтрами должны вывестись товары. Но а вот как в группе например РАЗМЕР между собой убрать совпадения и добавить совпадения к группе ЦВЕТ я не знаю как построить запрос.

Вот скрин таблицы фильтров Изображение
Вот скрин таблицы связей фильтров с товарами: Изображение
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

Искал в интернете что то подобное с фильтрами, чтобы запрос подсмотреть.
Нашел https://github.com/nurbeknurjanov/yii2ecommerce вот пример их демо сайта: https://demo.sakuracommerce.com/electro ... archForm=1
и вижу что у них фильтра также неправильно работают.
вот скрин Изображение
а должно было выбрать только Apple с i7. а выбрало Apple или i7
Или я не прав, должно быть как в скрине демо сайта?
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Вывод товаров по выбранным фильтрам

Сообщение unknownby »

webplus писал(а): 2019.12.20, 13:36 а должно было выбрать только Apple с i7. а выбрало Apple или i7
Или я не прав, должно быть как в скрине демо сайта?
Тут как логику построить, так и будет верно для вашего сайта :D
Почему у вас не выводит id = 6 и id =7, а потому что условие поставили

Код: Выделить всё

$productsQuery->andWhere([ProductFilter::tableName() . '.filter_id' => $filter_ids]);
Можно заменить на "ИЛИ"

Код: Выделить всё

$productsQuery->orWhere([ProductFilter::tableName() . '.filter_id' => $filter_ids]);
А для того, чтобы из разных фильтров оно считало как вам нужно, ["Красный" и ( "XL" или "XXL" )] или [("Красный" или "Синий") и ("XL" или "XXL")]
Нужно проверку сделать на parent_id и если они совпадают, тогда условие "ИЛИ" прописывать, если не совпадают "И"
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

unknownby писал(а): 2019.12.20, 14:18 А для того, чтобы из разных фильтров оно считало как вам нужно, ["Красный" и ( "XL" или "XXL" )] или [("Красный" или "Синий") и ("XL" или "XXL")]
Нужно проверку сделать на parent_id и если они совпадают, тогда условие "ИЛИ" прописывать, если не совпадают "И"
Я догадывался что нужно parent_id использовать, но у меня не получается построить запрос где я parent_id буду сравнивать.
Т.е. я так понимаю leftjoin -ом подключаю таблицу фильтров и как в них parent_id сравнить, а потом сами фильтры сравнить. Уже все возможные варианты запросов перепробовал, но с parent_id не выходит. Можете привести наводящий пример?
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Вывод товаров по выбранным фильтрам

Сообщение unknownby »

webplus писал(а): 2019.12.20, 15:33 Я догадывался что нужно parent_id использовать, но у меня не получается построить запрос где я parent_id буду сравнивать.
Т.е. я так понимаю leftjoin -ом подключаю таблицу фильтров и как в них parent_id сравнить, а потом сами фильтры сравнить. Уже все возможные варианты запросов перепробовал, но с parent_id не выходит. Можете привести наводящий пример?
А что приходит в переменную $filter_ids ? Нужно примерно понимать, что с этой переменной можно сделать
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

unknownby писал(а): 2019.12.20, 15:59 А что приходит в переменную $filter_ids ? Нужно примерно понимать, что с этой переменной можно сделать

Код: Выделить всё

	// например url: http://domen.loc/shop/catalog/knigi?filters=xl-5;xxl-6;krasnyj-3
        $get['filters'] = \Yii::$app->request->get('filters');
        $params['filters_array'] = explode(';', $get['filters']);
        $filter_ids = [];
        foreach ($params['filters_array'] as $str) {
            $filter_id = (int) substr(strrchr($str, '-'), 1);
            if ($filter_id) {
                $filter_ids[] = $filter_id;
            }
        }
т.е. $filter_ids = [5, 6, 3];
вот так можно получить parent_id

Код: Выделить всё

        if (count($filter_ids) > 0) {
            $_filters = [];
            foreach (Filter::find()->where(['id' => $filter_ids])->all() as $model) {
                $_filters[$model->parent_id][] = $model->id;
            }
        }    
и далее в запрос для выборки товаров как то добавить $_filters - в ней уже parent_id есть и id есть
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Вывод товаров по выбранным фильтрам

Сообщение unknownby »

Если правильно понимаю, то внутри $_filters = [2 => [3] , 4 => [5,6]]
А значит можно попробовать как-то так :D
Совершенству нет предела и можно переделать, но смысл понятен

Код: Выделить всё

if (count($filter_ids) > 0) {
            $productsQuery->select([Product::tableName() . '.*', 'Count(*) as total']);
            $productsQuery->joinWith(['filter']);
            $productsQuery->andWhere(['or',
            	foreach($_filters as $key => $value){
            		['in', ProductFilter::tableName() . '.filter_id', [$value]],
            	}
            ]);
            $productsQuery->groupBy(ProductFilter::tableName() . '.product_id');
            $productsQuery->having('total = ' . count($filter_ids));
        }
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

unknownby писал(а): 2019.12.20, 16:29 А значит можно попробовать как-то так :D
Тут я запутался и не выходит это - оно неверное, а как построить верно не пойму:

Код: Выделить всё

            $productsQuery->andWhere(['or',
            	foreach($_filters as $key => $value){
            		['in', ProductFilter::tableName() . '.filter_id', [$value]],
            	}
            ]);
. т.е. foreach вставленный в andWhere не работает.
и еще $productsQuery->having('total = ' . count($filter_ids)); - наверно в нем как то между parent_id значениями нужно условие делать, а у нас для всех фильтров условие. В вашем запросе мы по perent связи не сделали, а делаем связь для всех фильтров
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Вывод товаров по выбранным фильтрам

Сообщение yiiliveext »

Это первый тревожный звоночек, согласно текущей схемы хранения фильтров)
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

yiiliveext писал(а): 2019.12.20, 16:52 Это первый тревожный звоночек, согласно текущей схемы хранения фильтров)
но ведь если сделать как вы писали добавления в товаре фильтров динамически, то они все равно будут хранится так: Изображение
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Вывод товаров по выбранным фильтрам

Сообщение yiiliveext »

Не так, вернее filter_id будет указывать на то, что у вас называется группа фильтров.
А вообще фильтрацию по такого рода фильтрах уже разбирали недавно viewtopic.php?f=19&t=53622
там даже два варианта есть.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Вывод товаров по выбранным фильтрам

Сообщение unknownby »

Я намудрил немного :D
А если так? Переменные объявил текстовые, чтобы передать строку в запрос.
Насчёт запятой в конце должно прокатить :D строка ведь.
По итогу что-то да выйдет

Код: Выделить всё

$where = '';
$condition = '';
foreach($_filters as $value){
 foreach($value as $v){
 $condition .= [ProductFilter::tableName() . '.filter_id' =>$v],;
 } 
 $where .= ['or', $condition],;
}

$productsQuery->andWhere($where);
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

unknownby писал(а): 2019.12.20, 17:33 Я намудрил немного :D
А если так? Переменные объявил текстовые, чтобы передать строку в запрос.
Насчёт запятой в конце должно прокатить :D строка ведь.
По итогу что-то да выйдет
Ваш вариант не работает
ка может быть чтобы к переменное как строку добавляли массив:
$condition .= [];

Код: Выделить всё

$condition .= [ProductFilter::tableName() . '.filter_id' =>$v] . ',';
Пробовал так и ошибка запроса:

Код: Выделить всё

            $where = [];
            $condition = [];
            foreach ($_filters as $value) {
                foreach ($value as $v) {
                    $condition[] = [ProductFilter::tableName() . '.filter_id' => $v];
                }
                $where[] = ['or', $condition];
            }
            $productsQuery->andWhere($where);
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Вывод товаров по выбранным фильтрам

Сообщение yiiliveext »

И все это безобразие нынче происходит из-за того, что у нынешних программистов нет базовых теоретических знаний и получается не программирование, а гадание на кофейной гуще:)
Держите, играйтесь http://sqlfiddle.com/#!9/aecf57/3
Надеюсь, перевести в Yii QueryBuilder вы осилите.
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

yiiliveext писал(а): 2019.12.20, 17:11 А вообще фильтрацию по такого рода фильтрах уже разбирали недавно viewtopic.php?f=19&t=53622
там даже два варианта есть.
Прочитал, спасибо! Я изначально так делал:
вот запрос из дебагера:

Код: Выделить всё

SELECT `product`.*, Count(*) AS `total` FROM `product` 
LEFT JOIN `product_filter` ON product.id = product_filter.product_id 
WHERE (`product`.`category_id`=16) AND (`product_filter`.`filter_id` IN (6, 5, 3)) 
GROUP BY `product`.`id`
 HAVING total = 3
Но ту ссылку что вы дали, там автор не использует parent_id. У меня parent_id это группа.
Сейчас запрос ищет товары если у них только IN (6, 5, 3) . А у меня фильтр 3 это первая группа, а 6, 5 - вторая группа. Надо сделать так чтобы искало 3 и (6 или 5). как то в HAVING нужно добавить условия если parent_id = 2 тогда он ищет фильтр 3 и если parent_id = 4 тогда ищет фильтры (6 или 5).
Т.е. в рамках группы(parent_id) использует ИЛИ - в запросе можно IN, а между группами должно использовать И
вот скрин фильтров таблицы Изображение
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Вывод товаров по выбранным фильтрам

Сообщение yiiliveext »

webplus писал(а): 2019.12.20, 18:31 Прочитал, спасибо! Я изначально так делал:
вот запрос из дебагера:
Плохо читали, выше дал ссылку на фидл.
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: Вывод товаров по выбранным фильтрам

Сообщение webplus »

yiiliveext писал(а): 2019.12.20, 18:35 Плохо читали, выше дал ссылку на фидл.
Пока писал, не увидел примера.
Работает! Спасибо большое!
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Вывод товаров по выбранным фильтрам

Сообщение yiiliveext »

Есть еще один красивый способ с группами и без циклов http://sqlfiddle.com/#!9/970526/1
Но в нем есть ряд недостатков. Он боится дублей и при значении фильтра, которого нет в базе игнорирует его.
Если будете играться, то между значениями фильтров и запятыми в SET @filter = ('Красный,XXL,XL,Ситец,Хлопок') не должно быть пробелов. Ну и переменную можно выбросить и вместо FIND_IN_SET() использовать обычный IN, это я просто для удобства тестирования делал, чтобы два раза не вводить.
Ответить