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

如何在Shopware 6中为未登录用户自动切换currentCustomerGroup

Shopware基于IP自动切换客户组并重新计算价格解决方案

核心实现步骤

1. 完成IP与客户组的映射逻辑

在已订阅的onPageLoaded方法中,先获取用户IP,通过自定义规则匹配对应的目标客户组ID。可根据业务需求实现IP段、地区等匹配逻辑。

2. 切换当前客户组并更新会话

不能直接修改SalesChannelContext中的客户组,需通过CustomerContextService生成新的客户上下文并存入会话,确保后续请求都使用新的客户组。

3. 强制刷新价格与购物车

清空Shopware的价格缓存,并调用购物车刷新方法,触发重新计算所有价格相关内容。

完整代码示例

use Shopware\Core\Framework\Event\GenericPageLoadedEvent;
use Shopware\Core\System\Customer\Context\CustomerContextService;
use Shopware\Core\System\Customer\CustomerEntity;
use Shopware\Core\System\Customer\CustomerGroupEntity;
use Shopware\Core\System\Customer\CustomerGroupRepository;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Checkout\Cart\CartService;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;

class IpBasedCustomerGroupSubscriber implements EventSubscriberInterface
{
    private RequestStack $requestStack;
    private CustomerGroupRepository $customerGroupRepository;
    private CustomerContextService $customerContextService;
    private CartService $cartService;

    public function __construct(
        RequestStack $requestStack,
        CustomerGroupRepository $customerGroupRepository,
        CustomerContextService $customerContextService,
        CartService $cartService
    ) {
        $this->requestStack = $requestStack;
        $this->customerGroupRepository = $customerGroupRepository;
        $this->customerContextService = $customerContextService;
        $this->cartService = $cartService;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            GenericPageLoadedEvent::class => 'onPageLoaded',
        ];
    }

    public function onPageLoaded(GenericPageLoadedEvent $event): void
    {
        $salesChannelContext = $event->getSalesChannelContext();
        $request = $this->requestStack->getCurrentRequest();
        if (!$request) {
            return;
        }

        // 获取用户IP并匹配目标客户组ID
        $userIp = $request->getClientIp();
        $targetCustomerGroupId = $this->resolveCustomerGroupByIp($userIp);
        if (!$targetCustomerGroupId) {
            return;
        }

        // 无需切换则直接返回
        $currentGroupId = $salesChannelContext->getCurrentCustomerGroup()->getId();
        if ($currentGroupId === $targetCustomerGroupId) {
            return;
        }

        // 获取目标客户组实体
        $criteria = new Criteria([$targetCustomerGroupId]);
        /** @var CustomerGroupEntity|null $targetGroup */
        $targetGroup = $this->customerGroupRepository->search($criteria, $salesChannelContext->getContext())->first();
        if (!$targetGroup) {
            return;
        }

        // 生成新的客户上下文并写入会话
        $newCustomerContext = $this->customerContextService->createCustomerContext(
            $salesChannelContext->getContext(),
            $salesChannelContext->getSalesChannel()->getId(),
            $targetGroup->getId(),
            $salesChannelContext->getCustomer()?->getId()
        );

        $session = $request->getSession();
        $session->set(CustomerContextService::CUSTOMER_CONTEXT_KEY, $newCustomerContext);

        // 可选:更新已登录用户的默认客户组
        $customer = $salesChannelContext->getCustomer();
        if ($customer instanceof CustomerEntity) {
            $this->customerGroupRepository->update(
                [['id' => $customer->getId(), 'customerGroupId' => $targetCustomerGroupId]],
                $salesChannelContext->getContext()
            );
        }

        // 清空价格缓存并刷新购物车
        $cacheKey = 'sales-channel.cached-prices.' . $salesChannelContext->getSalesChannelId();
        $salesChannelContext->getContext()->getCache()->delete($cacheKey);

        $cart = $this->cartService->getCart($salesChannelContext->getToken(), $salesChannelContext);
        $this->cartService->refresh($cart, $salesChannelContext);
    }

    private function resolveCustomerGroupByIp(string $ip): ?string
    {
        // 替换为你的实际IP匹配逻辑
        // 示例:根据IP段区分批发/零售客户组
        if (str_starts_with($ip, '192.168.')) {
            return 'your-wholesale-group-uuid'; // 替换成真实客户组ID
        }
        return 'your-retail-group-uuid'; // 默认客户组ID
    }
}

关键注意事项

  • 服务注册:确保将该订阅类注册为Shopware服务,例如在services.xml中添加配置:
    <service id="IpBasedCustomerGroupSubscriber">
        <argument type="service" id="Symfony\Component\HttpFoundation\RequestStack"/>
        <argument type="service" id="Shopware\Core\System\Customer\CustomerGroupRepository"/>
        <argument type="service" id="Shopware\Core\System\Customer\Context\CustomerContextService"/>
        <argument type="service" id="Shopware\Core\Checkout\Cart\CartService"/>
        <tag name="kernel.event_subscriber"/>
    </service>
    
  • IP获取准确性:若部署在代理/CDN后,需在Symfony配置中设置trusted_proxies,确保getClientIp()返回真实用户IP。
  • 缓存清理:测试时需清空浏览器缓存及Shopware的内核缓存,避免旧价格数据残留。
  • 访客/登录用户兼容:代码同时支持访客和已登录用户,已登录用户可选择更新其默认客户组,实现持久化切换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 15:35:28