Product-Properties in Produkt-Slider

addAssociation – wie das Englische Wort add ausdrückt – fügt eine weitere Association hinzu. Es überschreibt nichts.

Je nach Kontext erstellen die Plugins auch ihre eigene Criteria, dass diese dann voreinander getrennt sind.

Was bei dir schlief läuft, ist mir auf den ersten Blick nicht ersichtlich.

@Max_Shop so dachte ich das auch.

Nach meinen Tests liegt es auch nicht an addAssociation, sondern daran, dass bei Plugin 1 die collect-Function und die enrich-Funktion nicht mehr aufgerufen werden. getType() hingegen schon. Woran kann das liegen?

Es ist praktisch so, dass nur die collect-function des zuletzt installierten plugins aufgerufen wird.

Ich habe mir eben deinen Code angesehen…

Deine Class extended nicht die Abstract Class (nicht sicher, ob notwendig)

    foreach ($criteriaCollection as $productCriteria) {
            foreach ($productCriteria as $criteria) {
                $criteria->addAssociation('options.group');
            }
        }

Du erstellst eine $criteria Variable, verwirfst diese nach dem foreach aber wieder. Ich weiß nicht, was du dir da dann erhoffst.

Du musst die $criteria auch wieder der $criteriaCollection zuweisen.

@Max_Shop danke für die Rückmeldung.

Deine Class extended nicht die Abstract Class (nicht sicher, ob notwendig)

Hatte ich nicht gemacht, weil es in den obigen Code-Beispielen auch niemand gemacht hat… Ich habe mal extends auf extends ProductSliderCmsElementResolver eingefügt… machte aber keinen Unterschied

Du erstellst eine $criteria Variable, verwirfst diese nach dem foreach aber wieder. Ich weiß nicht, was du dir da dann erhoffst.

also quasi hiermit:
$criteriaCollection->add('product-slider' . '_' . $slot->getUniqueIdentifier(), ProductDefinition::class, $criteria);

Ich bin mir aber nicht sicher, ob das mein Problem löst… ich habe am Anfang der collect-Funktion ein dump('foobar1') eingefügt. Daher weiß ich, dass die Funktion gar nicht erst ausgeführt wird, wenn das zweite Plugin aktiv ist.

Ich brauche Kaffee… dump ist natürlich eine Symfony-Funktion (ursprüngliche Antwort war Unsinn).

extends AbstractCmsElementResolver wäre als extend vermutlich passender.

In deiner service.xml sind beide Class eingetragen?

@Max_Shop

nein dump läuft wunderbar und wird in der symfony console ausgegeben:

Wie gesagt, es funktioniert ja auch, wenn man nur eines der Plugins betrachtet… nur wenn zwei Plugins da dran wollen, wird die collect-Funktion des anderen nicht mehr ausgeführt…

1 „Gefällt mir“

Aktualisiertes Codebeispiel:

PLUGIN 1:

<?php declare(strict_types=1);

namespace DockwareSamplePlugin\Core\Content\Product\Cms;

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\Element\AbstractCmsElementResolver;
use Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;

class DockwareExtendProductSliderCmsElementResolver extends AbstractCmsElementResolver
{
    /** @var ProductSliderCmsElementResolver $elementResolver */
    private $elementResolver;

    public function __construct(ProductSliderCmsElementResolver $elementResolver)
    {
        $this->elementResolver = $elementResolver;
    }

    public function getType(): string
    {
        return $this->elementResolver->getType();
    }

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

        foreach ($criteriaCollection as $productCriteria) {
            foreach ($productCriteria as $criteria) {
                $criteria->addAssociation('media');
                dump('Dockware!');
                dump($productCriteria);
            }
        }

        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $this->elementResolver->enrich($slot, $resolverContext, $result);
    }
}

<?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="DockwareSamplePlugin\Core\Content\Product\Cms\DockwareExtendProductSliderCmsElementResolver">
            <argument type="service" id="Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver"/>
            <tag name="shopware.cms.data_resolver"/>
        </service>
    </services>
</container>

PLUGIN 2:

<?php declare(strict_types=1);

namespace DockwareFooSamplePlugin\Core\Content\Product\Cms;

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\Element\AbstractCmsElementResolver;
use Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;

class DockwareExtendProductSliderCmsElementResolver extends AbstractCmsElementResolver
{
    /** @var ProductSliderCmsElementResolver $elementResolver */
    private $elementResolver;

    public function __construct(ProductSliderCmsElementResolver $elementResolver)
    {
        $this->elementResolver = $elementResolver;
    }

    public function getType(): string
    {
        return $this->elementResolver->getType();
    }

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

        foreach ($criteriaCollection as $productCriteria) {
            foreach ($productCriteria as $criteria) {
                $criteria->addAssociation('properties.group');
                dump('DockwareFoo!');
                dump($productCriteria);
            }
        }

        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $this->elementResolver->enrich($slot, $resolverContext, $result);
    }
}

<?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="DockwareFooSamplePlugin\Core\Content\Product\Cms\DockwareExtendProductSliderCmsElementResolver">
            <argument type="service" id="Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver"/>
            <tag name="shopware.cms.data_resolver"/>
        </service>
    </services>
</container>

Das einzige, was mir momentan noch auffällt ist, dass bei fehlt. Ich bin mir aber nicht ganz sicher, ob dies in diesem Kontext notwendig ist. Dann duften diese vermutlich gar nicht ausgeführt werden.

Ich teste es später mal per Copy&Past.

@Max_Shop

Das einzige, was mir momentan noch auffällt ist, dass bei fehlt.

Dein Satz war leider nicht ganz vollständig. Falls Du beim Copy & Past einen Fehler findest sag gern bescheid. Ich kann Dir auch einen Dropbox-Link zu den beiden Demoplugins mit dem Code schicken.

@ myshoptheme dürfte ich dich um die beiden Plugins bitten? Sitze gerade vor dem gleichen Problem. Das wär super, danke dir! :slight_smile:
LG Alex

Hallo,

dieses Plugin löst das Problem:

sg Roman

Hej, wurde der Grund gefunden, warum der Resolver des zweiten Plugins nicht collect() und enrich() ausgeführt hatte? Sitze gerade vor dem gleichen Problem und erkenne einfach den Grund nicht.


Ok, habe nun den Grund gefunden:

Die Klasse CmsSlotsDataResolver fügt (Stand 4.12.0) im __construct() alle Einträge von $resolvers in ein assoziatives Array ein. Dabei wird der string von getType des Resolvers als key genutzt und mehrere Resolver eines CMS Elements überschreiben entsprechend den Vorherigen.

Somit ist es derzeit nicht möglich mehrere Resolver zu einem Element zu nutzen. :woozy_face:

Hallo,

komischerweise wird von heute auf auf morgen die enrich und collect Funktion meines Resolvers nicht mehr aufgerufen. Der manufacturer im Product Slider ist jetzt leer. Konstruktor wird aufgerufen, aber in enrich und collect geht er erst gar nicht rein.

Woran kann das liegen? :open_mouth:

Mein Resolver:

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\Element\AbstractCmsElementResolver;
use Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;


class ExtendProductSliderCmsElementResolver extends AbstractCmsElementResolver
{
    /** @var ProductSliderCmsElementResolver $elementResolver */
    private $elementResolver;

    public function __construct(ProductSliderCmsElementResolver $elementResolver)
    {
        $this->elementResolver = $elementResolver;
    }

    public function getType(): string
    {
        return 'extended-product-slider-cms-element-resolver';
    }

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

        foreach ($criteriaCollection as $productCriteria) {
            foreach ($productCriteria as $criteria) {
                $criteria->addAssociation('properties.group');
                $criteria->addAssociation('manufacturer');
            }
        }
        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $this->elementResolver->enrich($slot, $resolverContext, $result);
    }
}

Der Service meiner service.xml

<service id="Bs\ExtendedListing\Core\Content\Product\Cms\ExtendProductSliderCmsElementResolver">
   <argument type="service" id="Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver"/>
   <tag name="shopware.cms.data_resolver"/>
</service>

LG Alex

Was sagt der error log? Shopware-Update, Plugin Update/installiert, PHP Update… ?

Error log nicht verdächtig, Shopware Updates ja in letzter Zeit, Plugin Updates auch ja, genauso PHP Update vom Server. Habe es aber vorhin auf meiner 0815 Docker Installation lokal probiert, da funktioniert es auch nicht mehr :open_mouth: Auf der lokalen Installation laufen keine Plugins und noch SW 6.4.14.0. und PHP 8.0, sollte also funktionieren…

Edit: Lokal funktioniert es jetzt doch, das heißt irgendwo auf meiner Produktionsumgebung ist der Wurm drinnen :open_mouth:

Bringt dir zwar nichts, bei mir läuft es lokal aber auch :grin: Wird eher ein individuelles Problem sein.

1 „Gefällt mir“

Haha danke dir! Das Hilft mir schon sehr viel. Es werkelt scheinbar gerade eine Entwicklerbude an einem ihrer Plugins in der Live Umgebung herum, somit wird das Problem vermutlich irgendwo von ihnen verursacht. Kann leider aktuell keine Plugins deaktivieren, da ich ihnen vermutlich sonst ins Handwerk pfusche :smiley:

Ich bin jetzt weitergekommen. Der Pluginhersteller hatte auch einen Resolver für den CMS Product Slider und scheinbar hat dieser meinen Resolver einfach überschrieben.
Habe mir angeschaut, wie sie das gecoded haben und mir bisschen was abgeschaut. Scheinbar war meine Variante nicht sauber und nachhaltig.

Sie haben nicht den ProductSliderCmsResolver übergeben sondern das CmsElementResolverInterface. Zusätzlich haben sie noch den Service etwas anders in der service.xml registriert. Unten der Auszug aus meinem abgeänderen Code, wie es funktioniert.

use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
use Shopware\Core\Content\Cms\DataResolver\Element\CmsElementResolverInterface;
use Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\DataResolver\CriteriaCollection;


class ExtendProductSliderCmsElementResolver extends ProductSliderCmsElementResolver
{
    /**
     * @var ProductSliderCmsElementResolver
     */
    private $parent;

    public function __construct(CmsElementResolverInterface $parent)
    {
        $this->parent = $parent;
    }

    public function getType(): string
    {
        return 'product-slider';
    }

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

        foreach ($criteriaCollection as $productCriteria) {
            foreach ($productCriteria as $criteria) {
                $criteria->addAssociation('properties.group');
                $criteria->addAssociation('manufacturer');
            }
        }
        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $this->parent->enrich($slot, $resolverContext, $result);
    }
}
<service id="Bs\ExtendedListing\Resolver\ExtendProductSliderCmsElementResolver" decorates="Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver">
       <argument type="service" id="Bs\ExtendedListing\Resolver\ExtendProductSliderCmsElementResolver.inner"/>
       <tag name="shopware.cms.data_resolver" />
</service>

Ich hoffe, das kann auch einigen anderen hier helfen.

LG Alex

2 „Gefällt mir“

Hi zusammen,

vielen Dank für eure vielen hilfreichen Hinweise! Leider hatte ich es damit trotzdem nicht geschafft, in Shopware 6.6 den Hersteller in die Produktslider zu bekommen. In meinem Fall laden die Slider die Produkte aus dynamischen Produktgruppen (AKA product streams). Nach einigem Debuggen habe ich dann herausgefunden, dass bei solchen Slidern in der ProductSliderCmsElementResolver::enrich() nicht einfach das Ergebnis mit den Kriterien aus ProductSliderCmsElementResolver::collect() zurückgegeben wird (dort wäre die komplette Herstellerentität nämlich schon drin), sondern auf Basis der Produkt-IDs nochmal eine separate Abfrage auf das Produkt-Repository gemacht wird (siehe ProductSliderCmsElementResolver::fetchProductsByIds()). Das Ergebnis dieser Abfrage kommt am Ende im Template an - leider ohne den Hersteller und ohne schicke Möglichkeit zum Einklinken.

Am Ende sieht meine Lösung so aus:

src/DataResolver/ProductSliderCmsElementResolver.php

<?php

declare(strict_types=1);

namespace Example\Plugin\DataResolver;

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\CmsElementResolverInterface;
use Shopware\Core\Content\Cms\DataResolver\Element\ElementDataCollection;
use Shopware\Core\Content\Cms\DataResolver\ResolverContext\ResolverContext;
use Shopware\Core\Content\Cms\SalesChannel\Struct\ProductSliderStruct;
use Shopware\Core\Content\Product\ProductEntity;

class ProductSliderCmsElementResolver extends AbstractCmsElementResolver
{
    protected const PRODUCT_SLIDER_ENTITY_FALLBACK = 'product-slider-entity-fallback';

    public function __construct(
        protected CmsElementResolverInterface $decorated,
    ) {
    }

    public function getType(): string
    {
        return $this->getDecorated()->getType();
    }

    public function getDecorated(): CmsElementResolverInterface
    {
        return $this->decorated;
    }

    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        return $this->getDecorated()->collect($slot, $resolverContext);
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $this->getDecorated()->enrich($slot, $resolverContext, $result);

        $config = $slot->getFieldConfig();
        $productConfig = $config->get('products');

        if ($productConfig->isProductStream() && $productConfig->getValue()) {
            $entitySearchResult = $result->get(
                self::PRODUCT_SLIDER_ENTITY_FALLBACK . '_' . $slot->getUniqueIdentifier()
            );

            if ($entitySearchResult === null) {
                return;
            }

            /** @var ProductSliderStruct $slider */
            $slider = $slot->getData();
            $products = $slider->getProducts();

            /** @var \Shopware\Core\Content\Product\ProductEntity $product */
            foreach ($products as $product) {
                $productResult = $entitySearchResult->get($product->getId());

                if ($productResult instanceof ProductEntity) {
                    $product->setManufacturer($productResult->getManufacturer());
                }
            }
        }
    }
}

src/Resources/config/services.xml

<?xml version="1.0" ?>

<container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://symfony.com/schema/dic/services"
           xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"
>
    <services>
        <service id="Example\Plugin\DataResolver\ProductSliderCmsElementResolver"
                 decorates="Shopware\Core\Content\Product\Cms\ProductSliderCmsElementResolver"
                 public="true"
        >
            <argument type="service" id="Example\Plugin\DataResolver\ProductSliderCmsElementResolver.inner"/>
            <tag name="shopware.cms.data_resolver"/>
        </service>
    </services>
</container>

src/Resources/views/storefront/component/product/card/box-standard.html.twig

{% sw_extends "@Storefront/storefront/component/product/card/box-standard.html.twig" %}

{% block component_product_box_name %}
    <a href="{{ seoUrl('frontend.detail.page', {productId: id}) }}"
       class="product-name"
       title="{{ name }}"
    >
        <span class="manufacturer">{{ product.manufacturer.translated.name }}</span>
        {{ name }}
    </a>
{% endblock %}

Die Herstellerentität aus dem ursprünglichen Ergebnis wird also einfach nur in das neue Ergebnis kopiert. Das ist natürlich fehleranfällig, theoretisch könnten Objekte im ursprünglichen Ergebnis fehlen und somit dann auch die Hersteller im neuen Ergebnis. Sauberer wäre es, in solche einem Fall nochmal eine Abfrage zu machen, um die fehlenden Herstellerdaten zu holen. Für meine Zwecke genügt der obige Workaround jedoch.