bianjunhui 1 روز پیش
والد
کامیت
9daa81d797

+ 10 - 0
packages/Webkul/BagistoApi/src/Models/AttributeOption.php

@@ -63,4 +63,14 @@ class AttributeOption extends \Webkul\Attribute\Models\AttributeOption
         return $this->translation;
     }
 
+    /**
+     * Number of visible products associated with this option within the
+     * current category context. Populated by FilterableAttributesProvider.
+     */
+    #[ApiProperty(writable: false, readable: true)]
+    public function getProductCount(): int
+    {
+        return (int) ($this->product_count ?? 0);
+    }
+
 }

+ 87 - 1
packages/Webkul/BagistoApi/src/State/FilterableAttributesProvider.php

@@ -92,10 +92,12 @@ class FilterableAttributesProvider implements ProviderInterface
             ->limit($perPage)
             ->get();
 
-        $items = $items->map(function ($item) use ($maxPrice) {
+        $items = $items->map(function ($item) use ($maxPrice, $categoryId) {
             $item->maxPrice = (float) $maxPrice;
             $item->minPrice = 0.0;
 
+            $this->attachProductCounts($item, $categoryId);
+
             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;
+    }
 }