Search code examples
shopwareshopware6

Shopware 6 - Custom CMS elements: How to get the data from two repositories into a custom CMS block?


We are working on a custom shopware 6 plugin. This plugin contains a custom CMS block with two CMS elements. The CMS elements need data from two different custom repositories which are not associated to each other.

We tried to set up two DataResolver (one for each CMS element) but they are overwriting each other. So we tried to put everything in one DataResolver. We checked how some other plugins do this but it is not very clear to us.

Can someone help us what we need to put into the CMSElementReslover.php file especially into these two methods:

public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
{
     // Some other plugins return null here(?)       
}


public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
{
    // If we return null at the collect method, our $result variable is empty. 
    // We need the two custom repositories here...
}

We setup two additional classes for each element which extends our CmsElementResolver, e.g. like this:

class ExampleOneCmsElementResolver extends CmsElementResolver
{
    public function getType(): string
    {
        
    }

    public function getStruct(): Struct
    {
        
    }

The documentation is not very detailed: https://developer.shopware.com/docs/guides/plugins/plugins/content/cms/add-data-to-cms-elements

Thanks for any hint! 🙏🏼
Best!

#shopware #shopware6

We tried to add both repositories to the collection, e.g. like this:

public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        $config = $slot->getFieldConfig();
        $criteria = new Criteria();

        $criteriaCollection = new CriteriaCollection();
        $criteriaCollection->add(
            Entity1Definition::ENTITY_NAME,
            Entity1Definition::class,
            $criteria
        );

        $criteria = new Criteria();
        $criteriaCollection->add(
            Entity2Definition::ENTITY_NAME,
            Entity2Definition::class,
            $criteria
        );

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

Solution

  • You are on the right track with adding your criteria to the collection.

    Let's say you want to fetch a media and a product entity.

    In the collect method you simply provide a unique key with both your criteria.

    In the enrich method you retrieve the result of the respective search with the same key you used for the criteria.

    Then it's simply a matter of setting your entities you retrieve from the search results to the slot by using an instance of Struct, e.g. ArrayStruct.

    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        $mediaIdConfig = $slot->getFieldConfig()->get('mediaId');
        $productIdConfig = $slot->getFieldConfig()->get('productId');
    
        if ($mediaIdConfig === null || $productIdConfig === null) {
            return null;
        }
    
        $criteriaCollection = new CriteriaCollection();
    
        $criteria = new Criteria([$mediaIdConfig->getStringValue()]);
        $criteriaCollection->add('media_' . $slot->getUniqueIdentifier(), MediaDefinition::class, $criteria);
    
        $criteria = new Criteria([$productIdConfig->getStringValue()]);
        $criteriaCollection->add('product_' . $slot->getUniqueIdentifier(), ProductDefinition::class, $criteria);
    
        return $criteriaCollection;
    }
    
    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $mediaSearchResult = $result->get('media_' . $slot->getUniqueIdentifier());
        $productSearchResult = $result->get('product_' . $slot->getUniqueIdentifier());
    
        if ($mediaSearchResult === null || $productSearchResult === null) {
            return;
        }
    
        $slot->setData(new ArrayStruct([
            'media' => $mediaSearchResult->first(),
            'product' => $productSearchResult->first(),
        ]));
    }