Yii2按属性过滤产品

时间:2019-09-18 08:37:54

标签: php sql yii2 query-builder yii2-model

我有一个要按属性过滤的产品数据库。我有一部分产品。每个产品应具有属性集合,例如颜色和重量。我有3个产品。第一个产品的属性为:颜色=红色,第二个产品的颜色为红色,重量= 1000kg,最后一个产品的颜色为黑色。当我选择红色和黑色时,一切都很好,但是当我选择红色和重量1000kg的滤镜时,没有显示产品。 这是我的ProductSearch模型的一部分。

public function search($cat, $params=[])
{
    $query = Product::find();
    $query->joinWith(['productDesc','productCategory','productAttributes']);
    $query->andFilterWhere([
        'product.id'                => $this->id,
        'product.quantity'          => $this->quantity,
        'product.stock_status_id'   => $this->stock_status_id,
        'product.product_status_id' => $this->product_status_id
    ]); // and many more

    // Getting data from url: 
    // category?categories_path=some_category&f=6-Red;7-1000kg;&sort=price_vat
    if(isset($params['f'])) { 
        $filters_raw = explode(';', $params['f']);
        $filters_raw = array_filter($filters_raw);
        $attr_ids    = [];
        $attr_values = [];
        foreach ($filters_raw as $filter_arr) {
            $filters = explode('-', $filter_arr);
            $filter_results[$filters[0]][] = $filters[1];

        }
    }
    if(isset($filter_results)) {
        foreach ($filter_results as $attr_id => $filter_res) {
            $query->andFilterWhere([
                'and', 
                ['product_attribute.attribute_id' => $attr_id],
                ['product_attribute.value'        => $filter_res]
            ]);
        }
    }
}

怎么了?

1 个答案:

答案 0 :(得分:0)

如果一个产品可以具有多个属性,则简单联接将为每个属性产生多行(因此一个产品可能会重复多次):

| product.id | product_attribute.attribute_id | product_attribute.value |
| ---------- | ------------------------------ | ----------------------- |
| 1          | 120                            | red                     |
| 1          | 121                            | 1000kg                  |

因此,如果使用两个属性的条件创建查询,将永远无法满足它们,因为没有行会匹配“ color = red and weight = 1000kg”条件。您需要将多个属性合并为一行,以具有以下内容:

| product.id | pa1.attribute_id | pa1.value | pa2.attribute_id | pa2.value |
| ---------- | ---------------- | --------- | ---------------- | --------- |
| 1          | 120              | red       | 121              | 1000kg    |

为此,您需要删除具有属性的直接联接:

$query->joinWith(['productDesc','productCategory']);

并为每个过滤器分别加入每个属性:

foreach ($filter_results as $attr_id => $filter_res) {
    $query->joinWith("productAttributes as productAttributes{$attr_id}");
    $query->andWhere([
        "productAttributes{$attr_id}.attribute_id" => $attr_id,
        "productAttributes{$attr_id}.value" => $filter_res,
    ]);
}