Magento 2构造函数注入Customer Session无法获取客户的问题及优化
问题描述
我有一个VisibilityService服务,构造函数注入了以下依赖:
\Magento\Customer\Model\Session $customerSession, \Magento\Framework\App\Http\Context $httpContext,
在方法中调用:
$this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH)
可以获取客户已登录状态,但从注入的Customer Session中获取客户ID返回null。该服务用于catalog_product_collection_load_after观察者中。
在其他场景(如Magento\Catalog\Controller\Product\View的插件)中,注入的Customer Session可正常获取客户信息。
但通过以下方式创建实例时:
$customerSession = $this->objectmanager->create("Magento\Customer\Model\Session"); dd($customerSession->getCustomer());
却能获取客户ID。请问原因是什么?如何避免使用ObjectManager?
原因分析
- 事件触发时机问题:
catalog_product_collection_load_after事件触发时,Magento的客户会话初始化流程还没走完。Customer\Model\Session依赖会话存储的完整初始化,而这个事件的执行节点早于会话加载完成的时间点,导致注入的会话实例还没读取到客户登录信息。 Http\Context的特性:Http\Context是基于请求层面的上下文存储,它的登录状态会在请求早期就被设置(比如前端控制器初始化阶段),所以能提前拿到登录状态,不受会话加载顺序的限制。ObjectManager::create的差异:直接用ObjectManager创建Customer\Model\Session时,会重新触发会话的初始化逻辑,此时请求流程已经走到了会话可以正常读取的阶段,所以能获取到客户信息。但这种方式绕过了依赖注入的生命周期管理,不符合Magento开发规范。
解决方法(避免使用ObjectManager)
方法1:使用Customer\Model\SessionFactory延迟加载
这是Magento推荐的会话实例获取方式,通过工厂类延迟初始化会话,确保在需要时会话已经完成加载:
// 在VisibilityService的构造函数中注入工厂类 private \Magento\Customer\Model\SessionFactory $customerSessionFactory; private \Magento\Framework\App\Http\Context $httpContext; public function __construct( \Magento\Customer\Model\SessionFactory $customerSessionFactory, \Magento\Framework\App\Http\Context $httpContext ) { $this->customerSessionFactory = $customerSessionFactory; $this->httpContext = $httpContext; } // 在业务方法中获取会话实例 public function processProductVisibility() { if ($this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH)) { $customerSession = $this->customerSessionFactory->create(); $customerId = $customerSession->getCustomerId(); // 后续业务逻辑 } }
方法2:调整事件监听时机
如果业务场景允许,把观察者绑定到更晚触发的事件,比如controller_action_predispatch或者catalog_product_view_load_after(针对产品页场景),确保会话初始化完成后再执行逻辑。
方法3:通过客户API直接获取信息
如果已经通过Http\Context确认客户登录,可以直接从上下文中取客户ID,再通过客户API获取信息,完全不依赖会话:
// 在VisibilityService的构造函数中注入API类 private \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository; private \Magento\Framework\App\Http\Context $httpContext; public function __construct( \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, \Magento\Framework\App\Http\Context $httpContext ) { $this->customerRepository = $customerRepository; $this->httpContext = $httpContext; } // 在业务方法中获取客户信息 public function processProductVisibility() { $customerId = $this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_CUSTOMER_ID); if ($customerId) { try { $customer = $this->customerRepository->getById($customerId); // 后续业务逻辑 } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { // 处理客户不存在的异常 } } }
内容的提问来源于stack exchange,提问作者user2217288
相关产品推荐
相关产品推荐

