概述
我为我的公司电子商务解决方案创建了一个方面菜单。你可以在这里看到一个演示。整个事情是几百行代码分布在 4 个文件中,所以我不会在这里包含整个事情,但会粘贴任何相关代码。
代码的基本流程是:
- 加载所选类别的所有产品
- 加载所有约束和方面(每个方面还同时加载链接到它的产品)。
- 检查用户选择的任何活动方面,如果有任何过滤器,则按这些方面过滤原始产品列表。
- 对每个约束运行查询以计算每个方面的活动产品数,不包括此约束中的任何活动方面。这是因为约束内的方面不应相互影响。
我对数据库运行单个查询以获取活动构面的有效产品的完整列表,然后对原始产品列表使用简单的 in_array 检查。这是目前使用的实际代码:
if(!empty($this->filters)) {
//Get a list of product IDs that match the active facets
$query = "SELECT p.pId
FROM products p
LEFT JOIN filterproducts fp
ON p.pId = fp.fpProductId
WHERE p.pDisplay <> 0
AND ( ";
$or = "";
foreach($this->filters as $constraint => $facets) {
$query .= $or . "(";
$subOr = "";
foreach($facets as $facet => $set) {
if($set) {
$query .= $subOr . "fp.fpFacetId = " . (int)$facet;
$subOr = " OR ";
}
}
$query .= ")";
$or = " OR ";
}
$query .= ")
GROUP BY p.pId
HAVING COUNT(p.pId) = " . count($this->filters);
$results = $this->dbConn->query($query);
if($this->dbConn->errno) {
trigger_error('An error occured whilst loading products matching active facets.' . PHP_EOL . 'Query: ' . $query . PHP_EOL . 'Error[' . $this->dbConn->errno . ']: ' . $this->dbConn->error, E_USER_WARNING);
} elseif($results->num_rows) {
while($row = $results->fetch_assoc()) {
$this->validProds[] = $row['pId'];
}
$results->free();
}
//Compare products with the list of valid IDs and unset any invalid products.
foreach($this->products as $product) {
if(!in_array($product->id, $this->validProds)) {
unset($this->products[$product->id]);
}
}
}
问题
然后,我对每个约束再次运行相同的查询,但从查询中忽略该约束的活动方面。我没有过滤产品,而是计算匹配的数量并使用它在菜单上的构面名称旁边显示一个数字。然而,这意味着如果我有 10 个约束,我必须运行 11 个查询(原始查询,每个约束加上一个)。虽然它有效,但它并不完全有效。
问题
这是构面菜单工作的唯一方法吗?我想不出任何其他方法,但肯定有更有效的方法来实现这一点。我将非常感谢任何可以提出更好的方法来创建方面菜单的人。