Есть ли лучший способ сделать фасетное меню?
обзор
Я создал фасетное меню для решения электронной коммерции своих компаний. Вы можете увидеть демо этого здесь. Все это состоит из нескольких сотен строк кода, распределенных по 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 запросов (исходный плюс один для каждого ограничения). Хотя это работает, это не совсем эффективно.
Вопрос
Это единственный способ для работы с фасетным меню? Я не могу думать ни о каком другом пути, но, безусловно, есть более эффективный способ добиться этого. Я был бы очень признателен всем, кто может предложить лучший способ создания фасетного меню.