|
@@ -92,10 +92,12 @@ class FilterableAttributesProvider implements ProviderInterface
|
|
|
->limit($perPage)
|
|
->limit($perPage)
|
|
|
->get();
|
|
->get();
|
|
|
|
|
|
|
|
- $items = $items->map(function ($item) use ($maxPrice) {
|
|
|
|
|
|
|
+ $items = $items->map(function ($item) use ($maxPrice, $categoryId) {
|
|
|
$item->maxPrice = (float) $maxPrice;
|
|
$item->maxPrice = (float) $maxPrice;
|
|
|
$item->minPrice = 0.0;
|
|
$item->minPrice = 0.0;
|
|
|
|
|
|
|
|
|
|
+ $this->attachProductCounts($item, $categoryId);
|
|
|
|
|
+
|
|
|
return $item;
|
|
return $item;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -111,4 +113,88 @@ class FilterableAttributesProvider implements ProviderInterface
|
|
|
)
|
|
)
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Attach the number of visible products associated with each option of
|
|
|
|
|
+ * the given attribute within the requested category context.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Visibility mirrors ProductGraphQLProvider: a product is counted only when
|
|
|
|
|
+ * it has status=1 (attribute id 8) and visible_individually=1 (attribute id 7).
|
|
|
|
|
+ */
|
|
|
|
|
+ private function attachProductCounts($item, ?int $categoryId): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $options = $item->options ?? $item->options()->get();
|
|
|
|
|
+
|
|
|
|
|
+ if ($options->isEmpty()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $attributeId = $item->id;
|
|
|
|
|
+ $column = $item->type === 'select' ? 'integer_value' : 'text_value';
|
|
|
|
|
+
|
|
|
|
|
+ $countQuery = DB::table('product_attribute_values as pav')
|
|
|
|
|
+ ->join('product_attribute_values as pav_status', function ($join) {
|
|
|
|
|
+ $join->on('pav_status.product_id', '=', 'pav.product_id')
|
|
|
|
|
+ ->where('pav_status.attribute_id', 8)
|
|
|
|
|
+ ->where('pav_status.boolean_value', 1);
|
|
|
|
|
+ })
|
|
|
|
|
+ ->join('product_attribute_values as pav_visible', function ($join) {
|
|
|
|
|
+ $join->on('pav_visible.product_id', '=', 'pav.product_id')
|
|
|
|
|
+ ->where('pav_visible.attribute_id', 7)
|
|
|
|
|
+ ->where('pav_visible.boolean_value', 1);
|
|
|
|
|
+ })
|
|
|
|
|
+ ->where('pav.attribute_id', $attributeId);
|
|
|
|
|
+
|
|
|
|
|
+ if ($categoryId) {
|
|
|
|
|
+ $countQuery->whereIn('pav.product_id', function ($sub) use ($categoryId) {
|
|
|
|
|
+ $sub->select('product_id')
|
|
|
|
|
+ ->from('product_categories')
|
|
|
|
|
+ ->where('category_id', $categoryId);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $optionIds = $options->pluck('id')->map(fn ($id) => (string) $id)->all();
|
|
|
|
|
+
|
|
|
|
|
+ if ($column === 'integer_value') {
|
|
|
|
|
+ $counts = (clone $countQuery)
|
|
|
|
|
+ ->whereIn('pav.integer_value', $optionIds)
|
|
|
|
|
+ ->selectRaw('pav.integer_value as option_id, COUNT(DISTINCT pav.product_id) as total')
|
|
|
|
|
+ ->groupBy('pav.integer_value')
|
|
|
|
|
+ ->pluck('total', 'option_id')
|
|
|
|
|
+ ->toArray();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $counts = $this->countMultiSelectOptions(clone $countQuery, $optionIds);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($options as $option) {
|
|
|
|
|
+ $option->product_count = (int) ($counts[(string) $option->id] ?? 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Count products for multiselect/checkbox options whose values are stored
|
|
|
|
|
+ * as comma-separated option ids in the text_value column.
|
|
|
|
|
+ */
|
|
|
|
|
+ private function countMultiSelectOptions($query, array $optionIds): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $rows = $query
|
|
|
|
|
+ ->whereNotNull('pav.text_value')
|
|
|
|
|
+ ->selectRaw('pav.text_value, COUNT(DISTINCT pav.product_id) as total')
|
|
|
|
|
+ ->groupBy('pav.text_value')
|
|
|
|
|
+ ->get();
|
|
|
|
|
+
|
|
|
|
|
+ $counts = [];
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($rows as $row) {
|
|
|
|
|
+ $values = array_filter(array_map('trim', explode(',', (string) $row->text_value)));
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($values as $value) {
|
|
|
|
|
+ if (in_array($value, $optionIds, true)) {
|
|
|
|
|
+ $counts[$value] = ($counts[$value] ?? 0) + (int) $row->total;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $counts;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|