Product-Properties in Produkt-Slider

Moin Zusammen,

nachdem ich bereits die Listings um Properties und Hersteller-Daten erweitert habe, möchte ich auch Produkte die in Erlebniswelt-Slidern um diese Daten erweitern. Hierzu haben mir bisher hauptsächlich diese beidem Threads geholfen (danke!):

https://forum.shopware.com/discussion/62944/daten-von-subscriber-controller-an-cms-element-uebergeben
https://forum.shopware.com/discussion/68787/wie-bekomme-ich-properties-in-cms-element-mit-produkt

Mein collect sieht aktuell so aus:

class SliderElementResolver extends ProductSliderCmsElementResolver
{
    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        $criteriaCollection = new CriteriaCollection();

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

        if (!$products || $products->isMapped() || $products->getValue() === null) {
            return null;
        }

        if ($products->isStatic() && $products->getValue()) {
            $criteria = new Criteria($products->getValue());
            $criteria->addAssociation('properties.group');
            $criteria->addAssociation('manufacturer.media');
            $criteriaCollection->add('product-slider' . '_' . $slot->getUniqueIdentifier(), ProductDefinition::class, $criteria);
        }

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

Die Gruppierung der Daten erfolgt im bereits vorhandenen ProductEvents::PRODUCT_LOADED_EVENT Listener.

Eigentlich funktioniert das auch so. Was mich nur wundert ist, dass in $criteriaCollection->add der erste Parameter $key von mir hardcecodet mit product-slider geprefixt werden musste, obwohl hierfür in der Eltern-Klasse ProductSliderCmsElementResolver eine Konstante STATIC_SEARCH_KEY = "product-slider" existiert und diese dort auch als Prefix für $key genutzt wird.

Diese ist aber private, nicht protected und kann somit nicht genutzt werden. So ist das Ganze auf meiner Seite nicht sonderlich Update-resistent. Es gibt auch noch ein getType(), was ebenfalls ‚product-slider‘ zurückgibt - aber ebenfalls hard und nicht per STATIC_SEARCH_KEY.

Ist das von Shopware unsauber programmiert, oder mache ich hier grundsätzlich etwas falsch? (Worauf mich das private ja vielleicht hinweisen möchte…) Frown

Besten Dank,
devnulroot

Moin Zusammen,

als Hinweis: Die grundsätzliche Herangehensweise ist mir beim Update auf die 6.3.1.0 auf die Füße gefallen, weshalb ich dank @Shyim‍ nun Dependency Injection benutze. Falls noch mal wer hierdrüber stolpert:

class MyResolver
{
    /** @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 = new CriteriaCollection();

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

        if (!$products || $products->isMapped() || $products->getValue() === null) {
            return null;
        }

        if ($products->isStatic() && $products->getValue()) {
            $criteria = new Criteria($products->getValue());
            $criteria->addAssociation('properties.group');
            $criteria->addAssociation('manufacturer.media');
            $criteriaCollection->add('product-slider' . '_' . $slot->getUniqueIdentifier(), ProductDefinition::class, $criteria);
        }
        return $criteriaCollection->all() ? $criteriaCollection : null;
    }

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

services.xml Auszug:

Beste Grüße,
devnullroot

@devnullroot‍ Danke für deinen Code. Hast du deinen Service über das Decorator Pattern registriert? Falls nein, muss noch etwas anderes in services.xml stehen?

Sorry, hab grade so gar keine Zeit, aber der Code sollte, bis auf Namensanpassungen, genau so laufen. Bei mir ist jedenfalls nicht mehr drin, hab eben kurz nachgesehen.

Beste Grüße,
devnullroot

Kurzer Nachtrag: Der Code funktioniert NICHT bei Slidern mit dynamischen Produktgruppen. Hinter der if Abfrage mit isStatic() habe ich als Fallback die Original-Methode aufgerufen:

else {
    $criteriaCollection = $this->elementResolver->collect($slot, $resolverContext);
}

Die dynamischen Produktgruppen werden da über die private Methode “collectByProductStream” abgefrühstückt. Die habe ich nicht angepasst/überschrieben und auch keine Möglichkeit gefunden hier $criteria zu erweitern :frowning:

Beste Grüße,
devnullroot

Ich habe heute diese Funktion ebenfalls benötigt. Vielen dank für die Ausführung. Es ist aber grundsätzlich nicht nötig den collect komplett neu zu definieren. Hier besteht aus meiner sicht auch eher das Problem das bei einem update der collect im zweifels fall auch angepasst werden muss. es Funktioniert auch mit dem Parent collect welcher dann nur um die Association erweiter

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

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

    return $criteriaCollection;
}

hier sollten dann auch die Probleme mit den Privaten Klassen Constanten nicht mehr existieren und bei mir funktioniert auch ein dynamische Produkt Gruppe

1 Like

Moin @Stephan4p ,

super, vielen Dank für die wesentlich bessere und elegantere Implementierung!

Beste Grüße,
devnullroot

Moin zusammen,
ich bin auch gerade dabei einen Resolver mit den Decorator Pattern zu erweitern ich möchte das Hersteller-Logo rein bekommen. Also die URL dazu. Leider wird mir die URL bisher noch nicht ausgeben.

Bisher habe ich das hier gebaut:

        $criteria->addAssociation('manufacturer.media');

        $criteriaCollection = new CriteriaCollection();
        $criteriaCollection->add('product_' . $slot->getUniqueIdentifier(), ProductDefinition::class, $criteria);

Ein dump($criteriaCollection) gibt mir nur leere Felder bei manufacturer.media aus.
Wie kann ich die Werte bekommen?
Muss ich einen API call machen?