Yii2 按属性过滤器过滤产品
Yii2 filtering products by attributes filter
我有一个产品数据库,我想按属性对其进行过滤。我有一段产品。每个产品都应该有一个属性集合,例如颜色和重量。我有 3 个产品。第一个产品的属性:颜色 = 红色,第二个产品的颜色 = 红色,重量 = 1000kg,最后一个产品的颜色 = 黑色;当我选择红色和黑色时,一切正常,但当我选择红色和重量 1000 公斤的过滤器时,没有显示产品。
这是我的 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]
]);
}
}
}
怎么了?
如果一个产品可以有多个属性,简单连接将为每个属性生成多行(因此一个产品可能会重复多次):
| 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,
]);
}
我有一个产品数据库,我想按属性对其进行过滤。我有一段产品。每个产品都应该有一个属性集合,例如颜色和重量。我有 3 个产品。第一个产品的属性:颜色 = 红色,第二个产品的颜色 = 红色,重量 = 1000kg,最后一个产品的颜色 = 黑色;当我选择红色和黑色时,一切正常,但当我选择红色和重量 1000 公斤的过滤器时,没有显示产品。
这是我的 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]
]);
}
}
}
怎么了?
如果一个产品可以有多个属性,简单连接将为每个属性生成多行(因此一个产品可能会重复多次):
| 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,
]);
}