如何通过定时任务按categoryId查询店铺前台显示的商品总数?
问题描述
我希望用定时任务检查特定分类下是否存在商品。尝试通过product.repository按categoryId获取商品,但方法无效——比如店铺前台显示“Clothes”分类有2个商品,但调用该方法返回null。
我想使用product_listing,但定时任务里没法用SalesChannelContext。请问怎么获取店铺前台特定分类显示的商品总数?
当前代码如下:
#[AsMessageHandler(handles: CategoriesTask::class)] class CategoriesTaskHandler extends ScheduledTaskHandler { private EntityRepository $productRepository; private EntityRepository $categoryRepository; public function __construct( EntityRepository $productRepository, EntityRepository $categoryRepository, ) { $this->productRepository = $productRepository; $this->categoryRepository = $categoryRepository; } public function run(): void { $data = []; $productsTotal = 0; $context = Context::createDefaultContext(); $categories = $this->categoryRepository->search(new Criteria(), $context); foreach ($categories as $category) { $criteria = new Criteria(); $criteria->addAssociation('categories'); $criteria->addFilter(new EqualsFilter('categories.id', $category->getId())); $products = $this->productRepository->search($criteria, $context); $data[] = [ 'categoryName' => $category->getName(), 'products' => $products->getTotal(), ]; } dump($data); } }
解决方案
问题根源在于你使用了Context::createDefaultContext(),这个上下文不会加载店铺前台的销售渠道规则(比如商品是否激活、是否关联对应销售渠道、库存状态、可见性设置等),所以查询结果和前台展示不一致。
要匹配前台的商品展示逻辑,你需要手动构建包含销售渠道信息的上下文,或者使用专门处理商品列表的ProductListingGateway。具体实现步骤如下:
修改后的代码示例
use Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingGateway; use Shopware\Core\System\SalesChannel\SalesChannelContextFactory; use Shopware\Core\System\SalesChannel\SalesChannelRepository; use Shopware\Core\System\SalesChannel\SalesChannelEntity; use Shopware\Core\System\SalesChannel\Type\DefaultSalesChannelType; use Symfony\Component\Uid\Uuid; #[AsMessageHandler(handles: CategoriesTask::class)] class CategoriesTaskHandler extends ScheduledTaskHandler { private EntityRepository $categoryRepository; private SalesChannelRepository $productSalesChannelRepository; private SalesChannelContextFactory $salesChannelContextFactory; private EntityRepository $salesChannelRepository; private ProductListingGateway $productListingGateway; public function __construct( EntityRepository $categoryRepository, SalesChannelRepository $productSalesChannelRepository, SalesChannelContextFactory $salesChannelContextFactory, EntityRepository $salesChannelRepository, ProductListingGateway $productListingGateway ) { $this->categoryRepository = $categoryRepository; $this->productSalesChannelRepository = $productSalesChannelRepository; $this->salesChannelContextFactory = $salesChannelContextFactory; $this->salesChannelRepository = $salesChannelRepository; $this->productListingGateway = $productListingGateway; } public function run(): void { $data = []; $defaultContext = Context::createDefaultContext(); // 获取默认销售渠道(可根据需求替换为指定销售渠道ID) $salesChannelCriteria = new Criteria(); $salesChannelCriteria->addFilter(new EqualsFilter('typeId', DefaultSalesChannelType::TYPE_ID)); /** @var SalesChannelEntity|null $salesChannel */ $salesChannel = $this->salesChannelRepository->search($salesChannelCriteria, $defaultContext)->first(); if (!$salesChannel) { return; } // 构建销售渠道上下文,自动应用前台的商品过滤规则 $salesChannelContext = $this->salesChannelContextFactory->create( Uuid::randomHex(), $salesChannel->getId(), [ 'currencyId' => $salesChannel->getCurrencyId(), 'languageId' => $salesChannel->getLanguageId(), ] ); $categories = $this->categoryRepository->search(new Criteria(), $defaultContext); foreach ($categories as $category) { // 方式一:用SalesChannelRepository查询,自动适配销售渠道规则 $productCriteria = new Criteria(); $productCriteria->addFilter(new EqualsFilter('categories.id', $category->getId())); $products = $this->productSalesChannelRepository->search($productCriteria, $salesChannelContext); // 方式二:用ProductListingGateway查询,完全匹配前台商品列表逻辑(推荐) // $listingResult = $this->productListingGateway->search( // new Criteria(), // $salesChannelContext, // $category->getId() // ); // $productCount = $listingResult->getTotal(); $data[] = [ 'categoryName' => $category->getName(), 'products' => $products->getTotal(), ]; } dump($data); } }
关键说明
- 销售渠道上下文:通过
SalesChannelContextFactory创建的上下文,会自动加载对应销售渠道的所有规则,包括商品激活状态、销售渠道关联、库存可见性、价格过滤等,确保查询结果和前台一致。 - ProductListingGateway:这是Shopware专门用于商品列表查询的服务,会自动处理分类关联、排序、前台过滤逻辑,是保证数据和前台完全同步的最优选择。
- 多销售渠道适配:如果店铺有多个销售渠道,只需修改
salesChannelCriteria中的过滤条件,指定目标销售渠道的ID即可获取对应渠道下的商品数。
内容的提问来源于stack exchange,提问作者SMS
相关产品推荐
相关产品推荐

