Как сделать фильтр по неизвестным атрибутам?

Делается фильтр товаров в категории, есть три таблицы - products(id, name), attributes(id, value), products_attributes(product_id, attribute_id, value).
Т.к я не знаю, у каких товаров какие атрибуты, я получаю их следующим способом:
// Продукты:
$products = Products::find()
            ->leftJoin('product_category', 'product_category.id=category_id')
            ->with(['productAttributeValues'])->where(['product_category.slug' => $slug, 'products.active' => 1]);
// Атрибуты:
$attrs = [];
        foreach($products->all() as $product){
            foreach($product->productAttributeValues as $item){
                $attrs[$item['attribute_id']][$item['value']] = $item['value'];
            }
        }

Массив с полученными атрибутами:
array (size=3)
  1 => 
    array (size=2)
      10 => string '10' (length=2)
      50 => string '50' (length=2)
  2 => 
    array (size=2)
      15 => string '15' (length=2)
      12 => string '12' (length=2)
  3 => 
    array (size=2)
      20 => string '20' (length=2)
      600 => string '600' (length=3)

Во view вывожу выпадающие списки циклом:
foreach($attrs as $name =>  $attr){
        echo '<label class="control-label">'.\common\models\entities\ProductAttribute::getNameById($name).'</label>';
        echo Html::dropDownList('FrontProductsSearch[ProductAttributeValues]['.$name.']', null, $attr, ['prompt' => '']);
    }

В search модели делаю запрос:
if($params['FrontProductsSearch']['ProductAttributeValues']){
            foreach($params['FrontProductsSearch']['ProductAttributeValues'] as $n => $productAttributeValue){
                if(!empty($productAttributeValue)){
                    $query->andWhere(['and',
                        ['product_attribute_value.attribute_id' => $n],
                        ['product_attribute_value.value' => $productAttributeValue]
                    ]);
                }

            }
        }

Если в фильтре выбрать значение только одного выпадающего списка - поиск работает, код запроса:
SELECT `products`.* FROM `products`
LEFT JOIN `product_category` ON `products`.`category_id` = `product_category`.`id`
LEFT JOIN `product_attribute_value` ON `products`.`id` = `product_attribute_value`.`product_id`
WHERE ((`active`=1)
       AND (`product_category`.`slug`='phones'))
       AND ((`product_attribute_value`.`attribute_id`=1)
       AND (`product_attribute_value`.`value`='10'))

Но если в фильтре выбрать значение двух выпадающих списков и больше - поиск ничего не возвращает, код запроса:
SELECT `products`.* FROM `products`
LEFT JOIN `product_category` ON `products`.`category_id` = `product_category`.`id`
LEFT JOIN `product_attribute_value` ON `products`.`id` = `product_attribute_value`.`product_id`
WHERE ((`active`=1)
		AND (`product_category`.`slug`='phones'))
		AND ((`product_attribute_value`.`attribute_id`=1)
		AND (`product_attribute_value`.`value`='10'))
		AND ((`product_attribute_value`.`attribute_id`=2)
		AND (`product_attribute_value`.`value`='15'))

В чем может быть ошибка?
  • Вопрос задан
  • 89 просмотров
Пригласить эксперта
Ответы на вопрос 1
@eyeless_watcher
В последнем запросе вы пытаетесь найти строку, у которой `attribute_id` одновременно равно и 1, и 2.
Вам же нужно найти разные строки в product_attribute_value с разными условиями, самое простое, что приходит в голову - подзапросы с exists:
select * from products where active = 1
and exists (select from product_attribute_value where product_id = products.id and attribute_id = 1 and value = 10)
and exists (select from product_attribute_value where product_id = products.id and attribute_id = 2 and value = 15)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы