|
|
@@ -8,6 +8,8 @@ use ApiPlatform\Metadata\Get;
|
|
|
use ApiPlatform\Metadata\GetCollection;
|
|
|
use ApiPlatform\OpenApi\Model;
|
|
|
use Illuminate\Database\Eloquent\Model as EloquentModel;
|
|
|
+use Symfony\Component\TypeInfo\Type\BuiltinType;
|
|
|
+use Symfony\Component\TypeInfo\TypeIdentifier;
|
|
|
|
|
|
#[ApiResource(
|
|
|
shortName: 'AttributeOption',
|
|
|
@@ -42,23 +44,50 @@ use Illuminate\Database\Eloquent\Model as EloquentModel;
|
|
|
),
|
|
|
],
|
|
|
)]
|
|
|
+#[ApiProperty(property: 'product_count', writable: false, readable: true, nativeType: new BuiltinType(TypeIdentifier::INT))]
|
|
|
class AttributeOption extends \Webkul\Attribute\Models\AttributeOption
|
|
|
{
|
|
|
/**
|
|
|
- * Number of visible products associated with this option within the
|
|
|
- * current category context. Populated by FilterableAttributesProvider.
|
|
|
+ * Static cache of product counts resolved by FilterableAttributesProvider.
|
|
|
+ *
|
|
|
+ * Keyed by attribute id, then option id. The provider computes the counts
|
|
|
+ * once per request and stores them here so the GraphQL "options" relation
|
|
|
+ * (which re-queries options through a separate cursor-connection provider
|
|
|
+ * and therefore produces fresh model instances) can still surface the
|
|
|
+ * correct product count.
|
|
|
+ *
|
|
|
+ * @var array<int, array<int, int>>
|
|
|
*/
|
|
|
- #[ApiProperty(writable: false, readable: true)]
|
|
|
- public int $product_count = 0;
|
|
|
+ private static array $resolvedProductCounts = [];
|
|
|
|
|
|
/**
|
|
|
- * Laravel accessor for the product_count virtual attribute. The accessor
|
|
|
- * naming convention makes API Platform discover it as a virtual attribute,
|
|
|
- * while the public property above lets PropertyInfo infer the int type.
|
|
|
+ * Store the resolved product counts for the given attribute's options.
|
|
|
+ *
|
|
|
+ * @param array<int, int> $counts option id => count
|
|
|
+ */
|
|
|
+ public static function setResolvedProductCounts(int $attributeId, array $counts): void
|
|
|
+ {
|
|
|
+ static::$resolvedProductCounts[$attributeId] = $counts;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Number of visible products associated with this option within the
|
|
|
+ * current category context.
|
|
|
+ *
|
|
|
+ * Prefer the value computed and cached by FilterableAttributesProvider;
|
|
|
+ * this keeps the count correct even when the option is fetched through
|
|
|
+ * the GraphQL cursor-connection relation instead of the eager-loaded
|
|
|
+ * collection.
|
|
|
*/
|
|
|
public function getProductCountAttribute(): int
|
|
|
{
|
|
|
- return (int) ($this->product_count ?? 0);
|
|
|
+ $attributeId = (int) ($this->attribute_id ?? 0);
|
|
|
+
|
|
|
+ if (isset(static::$resolvedProductCounts[$attributeId][(int) $this->id])) {
|
|
|
+ return (int) static::$resolvedProductCounts[$attributeId][(int) $this->id];
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#[ApiProperty(identifier: true, writable: false)]
|