Search code examples
javascriptsymfonyvue.jstwigshopware

Shopware 6 | Cloning CmsElement and get null as data


I try to clone the content element image-slider or image-gallery (the error will come at both) to extend them. First I register a new CmsElement like the original only changes the name from image-slider to image-slider-example

import './component';
import './config';
import './preview';

Shopware.Service('cmsService').registerCmsElement({
    name: 'image-slider-example',
    label: 'sw-cms.elements.imageSlider.label',
    component: 'sw-cms-el-image-slider',
    configComponent: 'sw-cms-el-config-image-slider',
    previewComponent: 'sw-cms-el-preview-image-slider',
    defaultConfig: {
        sliderItems: {
            source: 'static',
            value: [],
            required: true,
            entity: {
                name: 'media'
            }
        },
        displayMode: {
            source: 'static',
            value: 'standard'
        },
        minHeight: {
            source: 'static',
            value: '300px'
        },
        verticalAlign: {
            source: 'static',
            value: null
        }
    },
    enrich: function enrich(elem, data) {
        if (Object.keys(data).length < 1) {
            return;
        }

        Object.keys(elem.config).forEach((configKey) => {
            const entity = elem.config[configKey].entity;

            if (!entity) {
                return;
            }

            const entityKey = entity.name;
            if (!data[`entity-${entityKey}`]) {
                return;
            }

            elem.data[configKey] = [];
            elem.config[configKey].value.forEach((sliderItem) => {
                elem.data[configKey].push({
                    newTab: sliderItem.newTab,
                    url: sliderItem.url,
                    media: data[`entity-${entityKey}`].get(sliderItem.mediaId)
                });
            });
        });
    }
});

Now It shows me the new element in the Shopping Experience, where I can use it.

After that I create for the storefront the cms-element-image-slider-example.html.twig file, which will be loaded by Shopware.

{% sw_extends '@Storefront/storefront/element/cms-element-image-slider.html.twig' %}

{% block element_image_slider_alignment %}
    <pre>
        {{ dump(element) }}
    </pre>
    {{ parent() }}
{% endblock %}

Now I extend the original storefront element from which I was cloning and add a dump to see all data. But there I have the issue, that the element.data are null but there should be all images stored.


Solution

  • You need to create a data resolver which should look like:

    <?php declare(strict_types=1);
    
    namespace PluginName\Core\Content\Media\Cms;
    
    use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
    use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;
    use Shopware\Core\Content\Cms\DataResolver\Element\AbstractCmsElementResolver;
    use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
    use Shopware\Core\Content\Cms\DataResolver\FieldConfig;
    use Shopware\Core\Content\Cms\DataResolver\ResolverContext\EntityResolverContext;
    use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
    use Shopware\Core\Content\Cms\SalesChannel\Struct\ImageStruct;
    use Shopware\Core\Content\Media\MediaDefinition;
    use Shopware\Core\Content\Media\MediaEntity;
    use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
    
    class ImageCmsElementResolver extends AbstractCmsElementResolver
    {
        public function getType(): string
        {
            return 'image';
        }
    
        public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
        {
            $config = $slot->getFieldConfig();
            $mediaConfig = $config->get('media');
    
            if (!$mediaConfig || $mediaConfig->isMapped() || $mediaConfig->getValue() === null) {
                return null;
            }
    
            $criteria = new Criteria([$mediaConfig->getValue()]);
    
            $criteriaCollection = new CriteriaCollection();
            $criteriaCollection->add('media_' . $slot->getUniqueIdentifier(), MediaDefinition::class, $criteria);
    
            return $criteriaCollection;
        }
    
        public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
        {
            $config = $slot->getFieldConfig();
            $image = new ImageStruct();
            $slot->setData($image);
    
            if ($urlConfig = $config->get('url')) {
                if ($urlConfig->isStatic()) {
                    $image->setUrl($urlConfig->getValue());
                }
    
                if ($urlConfig->isMapped() && $resolverContext instanceof EntityResolverContext) {
                    $url = $this->resolveEntityValue($resolverContext->getEntity(), $urlConfig->getValue());
                    if ($url) {
                        $image->setUrl($url);
                    }
                }
    
                if ($newTabConfig = $config->get('newTab')) {
                    $image->setNewTab($newTabConfig->getValue());
                }
            }
    
            $mediaConfig = $config->get('media');
            if ($mediaConfig && $mediaConfig->getValue()) {
                $this->addMediaEntity($slot, $image, $result, $mediaConfig, $resolverContext);
            }
        }
    
        private function addMediaEntity(CmsSlotEntity $slot, ImageStruct $image, ElementDataCollection $result, FieldConfig $config, ResolverContext $resolverContext): void
        {
            if ($config->isMapped() && $resolverContext instanceof EntityResolverContext) {
                /** @var MediaEntity|null $media */
                $media = $this->resolveEntityValue($resolverContext->getEntity(), $config->getValue());
    
                if ($media !== null) {
                    $image->setMediaId($media->getUniqueIdentifier());
                    $image->setMedia($media);
                }
            }
    
            if ($config->isStatic()) {
                $image->setMediaId($config->getValue());
    
                $searchResult = $result->get('media_' . $slot->getUniqueIdentifier());
                if (!$searchResult) {
                    return;
                }
    
                /** @var MediaEntity|null $media */
                $media = $searchResult->get($config->getValue());
                if (!$media) {
                    return;
                }
    
                $image->setMedia($media);
            }
        }
    }
    

    If you create your Resolver, you need to register the resolver in your src/Resources/config/services.xml

    
    <?xml version="1.0" ?>
    
    <container xmlns="http://symfony.com/schema/dic/services"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="PluginName\Core\Content\Media\Cms\ImageCmsElementResolver">
                <tag name="shopware.cms.data_resolver"/>
            </service>
        </services>
    </container>