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

如何通过定时任务按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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 17:42:45