动态修改Shopware商品价格时的缓存问题及方案咨询
Shopware动态商品价格缓存问题解决方案
核心问题拆解
你遇到的是Shopware多层缓存导致的价格复用问题:即使跳过HTTP缓存,实体缓存(ObjectCache)和Store API路由缓存仍会复用已缓存的商品数据,导致特殊用户的低价被普通用户看到。
问题1:如何处理二级(实体)缓存?
Shopware的实体缓存(如product.loaded对应的缓存)会根据查询条件和上下文生成缓存键,直接禁用会影响性能,最优方案是给特殊用户添加专属缓存上下文,让缓存系统区分不同用户群体:
- 订阅
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); } } }
- 在插件的
services.xml中注册该订阅者服务。
问题2:动态修改单个商品价格的最优方式
不要在product.loaded事件中修改价格(容易被缓存覆盖),应基于Shopware官方的价格计算体系扩展:
- 实现
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; } }
- 在
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
相关产品推荐
相关产品推荐

