You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态修改Shopware商品价格时的缓存问题及方案咨询

Shopware动态商品价格缓存问题解决方案

核心问题拆解

你遇到的是Shopware多层缓存导致的价格复用问题:即使跳过HTTP缓存,实体缓存(ObjectCache)和Store API路由缓存仍会复用已缓存的商品数据,导致特殊用户的低价被普通用户看到。


问题1:如何处理二级(实体)缓存?

Shopware的实体缓存(如product.loaded对应的缓存)会根据查询条件和上下文生成缓存键,直接禁用会影响性能,最优方案是给特殊用户添加专属缓存上下文,让缓存系统区分不同用户群体:

  1. 订阅ProductCriteriaEvent,实时检查会话状态并修改查询上下文:
use Shopware\Core\Content\Product\Event\ProductCriteriaEvent;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

class ProductCacheContextSubscriber implements EventSubscriberInterface
{
    private SessionInterface $session;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            ProductCriteriaEvent::class => 'onProductCriteria'
        ];
    }

    public function onProductCriteria(ProductCriteriaEvent $event): void
    {
        $context = $event->getContext();
        if ($this->session->has('your_special_session_key')) {
            // 添加自定义缓存上下文,让缓存区分普通/特殊用户
            $context->addExtension('special_price_context', new ArrayEntity(['active' => true]));
            // 若需完全禁用当前查询的实体缓存,可使用:
            // $event->getCriteria()->setUseCache(false);
        }
    }
}
  1. 在插件的services.xml中注册该订阅者服务。

问题2:动态修改单个商品价格的最优方式

不要在product.loaded事件中修改价格(容易被缓存覆盖),应基于Shopware官方的价格计算体系扩展:

  1. 实现AbstractProductPriceCalculator的装饰器,在价格计算环节调整价格:
use Shopware\Core\Content\Product\SalesChannel\Price\AbstractProductPriceCalculator;
use Shopware\Core\Content\Product\SalesChannel\Price\ProductPriceCollection;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

class SpecialProductPriceCalculator extends AbstractProductPriceCalculator
{
    private AbstractProductPriceCalculator $inner;
    private SessionInterface $session;

    public function __construct(AbstractProductPriceCalculator $inner, SessionInterface $session)
    {
        $this->inner = $inner;
        $this->session = $session;
    }

    public function calculate(array $products, SalesChannelContext $context): ProductPriceCollection
    {
        $priceCollection = $this->inner->calculate($products, $context);
        
        // 仅当会话键存在时修改价格
        if (!$this->session->has('your_special_session_key')) {
            return $priceCollection;
        }

        foreach ($priceCollection as $productId => $price) {
            // 示例:将价格调整为原价的80%,可根据需求自定义逻辑
            $adjustedPrice = $price->getPrice() * 0.8;
            $priceCollection->set($productId, $price->withPrice($adjustedPrice));
        }

        return $priceCollection;
    }
}
  1. 在services.xml中注册装饰器:
<service id="YourPlugin\Service\SpecialProductPriceCalculator" decorates="Shopware\Core\Content\Product\SalesChannel\Price\AbstractProductPriceCalculator">
    <argument type="service" id="YourPlugin\Service\SpecialProductPriceCalculator.inner"/>
    <argument type="service" id="session"/>
</service>

修复你的Store API缓存问题

你当前的代码存在会话判断时机错误的问题——不要在服务初始化时判断sessionKeyExists,应在请求时实时检查会话:

public function onCacheKeyEvent(StoreApiRouteCacheKeyEvent $event): void
{
    $session = $event->getSalesChannelContext()->getContext()->getSession();
    
    if ($session->has('your_special_session_key')) {
        // 推荐:添加缓存键后缀,生成特殊用户专属缓存,而非完全禁用
        $event->addCacheKeyPart('special_price_active');
        // 若需完全禁用该路由缓存,保留以下代码:
        // $event->disableCaching();
    }
}

该修改会让特殊用户的Store API请求生成独立缓存键,避免和普通用户的缓存冲突。


内容的提问来源于stack exchange,提问作者Dennis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 03:07:11