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

Shopware 6自定义CMS元素:如何从两个仓库获取数据到CMS区块

推荐方案:为每个CMS元素配置独立DataResolver(解决覆盖问题)

1. 每个Resolver需返回唯一元素标识

多个Resolver互相覆盖的核心原因是getType()返回了重复的类型字符串,每个CMS元素的Resolver必须返回唯一的元素类型标识(与你定义CMS元素时的type一致)。

第一个元素的Resolver实现

// ExampleOneCmsElementResolver.php
namespace YourPlugin\Cms\Resolver;

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\Element\CmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use YourPlugin\Entity\Entity1Definition;
use YourPlugin\Repository\Entity1Repository;
use YourPlugin\Struct\ExampleOneElementStruct;

class ExampleOneCmsElementResolver extends CmsElementResolver
{
    public function __construct(
        private readonly Entity1Repository $entity1Repository
    ) {}

    // 返回第一个CMS元素的唯一类型标识
    public function getType(): string
    {
        return 'example-one-element';
    }

    public function getStruct(): \Shopware\Core\Framework\Struct\Struct
    {
        return new ExampleOneElementStruct();
    }

    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        $config = $slot->getFieldConfig();
        // 从元素配置中获取需要查询的实体ID(根据你的配置字段调整)
        $entityId = $config->get('entity1Id')?->getValue();

        if (!$entityId) {
            return null; // 无配置则无需查询
        }

        $criteria = new Criteria([$entityId]);
        // 可添加关联、过滤等条件,例如:$criteria->addAssociation('relatedEntity');

        $criteriaCollection = new CriteriaCollection();
        // 用唯一键区分查询结果(元素类型+实体名)
        $criteriaCollection->add(
            sprintf('%s-%s', $this->getType(), Entity1Definition::ENTITY_NAME),
            Entity1Definition::class,
            $criteria
        );

        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        // 通过collect阶段的唯一键获取查询结果
        $entityData = $result->get(sprintf('%s-%s', $this->getType(), Entity1Definition::ENTITY_NAME));
        if (!$entityData) {
            return;
        }

        $struct = $this->getStruct();
        // 将数据赋值到Struct(需在Struct类中定义对应的setter)
        $struct->setEntity1($entityData->first());

        // 将Struct绑定到CMS Slot的data属性
        $slot->setData($struct);
    }
}

第二个元素的Resolver实现

只需替换类型标识、仓库、实体定义和Struct即可:

// ExampleTwoCmsElementResolver.php
namespace YourPlugin\Cms\Resolver;

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\Element\CmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use YourPlugin\Entity\Entity2Definition;
use YourPlugin\Repository\Entity2Repository;
use YourPlugin\Struct\ExampleTwoElementStruct;

class ExampleTwoCmsElementResolver extends CmsElementResolver
{
    public function __construct(
        private readonly Entity2Repository $entity2Repository
    ) {}

    public function getType(): string
    {
        return 'example-two-element';
    }

    public function getStruct(): \Shopware\Core\Framework\Struct\Struct
    {
        return new ExampleTwoElementStruct();
    }

    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        $config = $slot->getFieldConfig();
        $entityId = $config->get('entity2Id')?->getValue();

        if (!$entityId) {
            return null;
        }

        $criteria = new Criteria([$entityId]);
        $criteriaCollection = new CriteriaCollection();
        $criteriaCollection->add(
            sprintf('%s-%s', $this->getType(), Entity2Definition::ENTITY_NAME),
            Entity2Definition::class,
            $criteria
        );

        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $entityData = $result->get(sprintf('%s-%s', $this->getType(), Entity2Definition::ENTITY_NAME));
        if (!$entityData) {
            return;
        }

        $struct = $this->getStruct();
        $struct->setEntity2($entityData->first());
        $slot->setData($struct);
    }
}

2. 正确注册Resolver服务

在插件的src/Resources/config/services.xml中注册两个Resolver,必须指定type属性对应各自的元素类型,Shopware会自动匹配:

<services>
    <!-- 第一个元素的Resolver -->
    <service id="YourPlugin\Cms\Resolver\ExampleOneCmsElementResolver">
        <argument type="service" id="Entity1.repository"/>
        <tag name="shopware.cms.data_resolver" type="example-one-element"/>
    </service>

    <!-- 第二个元素的Resolver -->
    <service id="YourPlugin\Cms\Resolver\ExampleTwoCmsElementResolver">
        <argument type="service" id="Entity2.repository"/>
        <tag name="shopware.cms.data_resolver" type="example-two-element"/>
    </service>
</services>

备选方案:整合到单个DataResolver(不推荐)

如果一定要将逻辑整合到一个Resolver,需在方法中判断当前Slot的类型,分别处理:

// CombinedCmsElementResolver.php
namespace YourPlugin\Cms\Resolver;

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\Element\CmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use YourPlugin\Entity\Entity1Definition;
use YourPlugin\Entity\Entity2Definition;
use YourPlugin\Repository\Entity1Repository;
use YourPlugin\Repository\Entity2Repository;
use YourPlugin\Struct\ExampleOneElementStruct;
use YourPlugin\Struct\ExampleTwoElementStruct;

class CombinedCmsElementResolver extends CmsElementResolver
{
    public function __construct(
        private readonly Entity1Repository $entity1Repository,
        private readonly Entity2Repository $entity2Repository
    ) {}

    public function getType(): string
    {
        return 'combined-resolver';
    }

    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        $criteriaCollection = new CriteriaCollection();
        $slotType = $slot->getType();

        // 处理第一个元素
        if ($slotType === 'example-one-element') {
            $config = $slot->getFieldConfig();
            $entityId = $config->get('entity1Id')?->getValue();
            if ($entityId) {
                $criteria = new Criteria([$entityId]);
                $criteriaCollection->add(
                    sprintf('%s-%s', $slotType, Entity1Definition::ENTITY_NAME),
                    Entity1Definition::class,
                    $criteria
                );
            }
        }

        // 处理第二个元素
        if ($slotType === 'example-two-element') {
            $config = $slot->getFieldConfig();
            $entityId = $config->get('entity2Id')?->getValue();
            if ($entityId) {
                $criteria = new Criteria([$entityId]);
                $criteriaCollection->add(
                    sprintf('%s-%s', $slotType, Entity2Definition::ENTITY_NAME),
                    Entity2Definition::class,
                    $criteria
                );
            }
        }

        return $criteriaCollection->all() ? $criteriaCollection : null;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $slotType = $slot->getType();
        $struct = null;

        if ($slotType === 'example-one-element') {
            $struct = new ExampleOneElementStruct();
            $entityData = $result->get(sprintf('%s-%s', $slotType, Entity1Definition::ENTITY_NAME));
            if ($entityData) {
                $struct->setEntity1($entityData->first());
            }
        } elseif ($slotType === 'example-two-element') {
            $struct = new ExampleTwoElementStruct();
            $entityData = $result->get(sprintf('%s-%s', $slotType, Entity2Definition::ENTITY_NAME));
            if ($entityData) {
                $struct->setEntity2($entityData->first());
            }
        }

        if ($struct) {
            $slot->setData($struct);
        }
    }

    public function getStruct(): \Shopware\Core\Framework\Struct\Struct
    {
        return new \Shopware\Core\Framework\Struct\EmptyStruct();
    }
}

注册服务时需添加多个type标签:

<service id="YourPlugin\Cms\Resolver\CombinedCmsElementResolver">
    <argument type="service" id="Entity1.repository"/>
    <argument type="service" id="Entity2.repository"/>
    <tag name="shopware.cms.data_resolver" type="example-one-element"/>
    <tag name="shopware.cms.data_resolver" type="example-two-element"/>
</service>

关键注意事项

  • 确保CMS元素的type与Resolver的getType()、服务标签的type完全一致。
  • CriteriaCollection的添加键必须唯一,避免查询结果互相覆盖。
  • 自定义Struct需继承Shopware\Core\Framework\Struct\Struct,并定义对应的数据属性和setter方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:01:20