Daten von Subscriber/Controller an CMS Element übergeben

Ich habe ein custom CMS Element mit einer Konfiguration + Plugin Konfiguration und würde nun gerne Daten von meinem (PHP) Subscriber im Plugin an mein CMS Element übergeben.

Ich bin mir gerade nicht sicher wie das funktionieren soll.

Muss ich hier einen custom Storefront Controller bauen und dann in meinem CMS Element über ein Javascript Plugin & dem HttpClient service den API Endpunkt vom custom Storefront Controller aufrufen? Oder wie genau ist hier der Weg? 

Kann mir hiere jemand auf die Sprünge helfen, wie das ganze hier genau funktionieren soll?

 

Hast du nun ein CMS Element oder eine Storefront-Seite? Die Pluginkonfiguration kannst du im Template ganz einfach auslesen.

{{ shopware.config.DeinPlugin.config.deinWert}}

Über Storefront Subscriber kenne ich nur die Extension-Variante… Bsp.

    public function onHeaderPageletLoadedEvent(HeaderPageletLoadedEvent $event): void
    {

        $page = $event->getPagelet();

        $pluginConfig = $this->systemConfigService->getDomain('DeinPlugin.config');

        $page->addExtension('DeinPlugin', new ArrayEntity(['config' => $pluginConfig, 'providers' => [
            'facebook' => ['icon' => 'fab fa-facebook-f', 'label' => 'moorl-sign-in.loginFacebook'],
            'google' => ['icon' => 'fab fa-google', 'label' => 'moorl-sign-in.loginGoogle'],
            'amazon' => ['icon' => 'fab fa-amazon', 'label' => 'moorl-sign-in.loginAmazon'],
           
        ]]));

    }

 

1 Like

Danke dir erst einmal für die Antwort.

Ich habe ein CMS Element, welches in der Storefront ausgeben wird :slight_smile:

Aber ich muss ja in meinem CMS twig template für die Storefront irgndwie an die Daten kommen welche von meinen Subscriber kommen.

$event->getPagelet() hatte ich mir schon angeschaut von dem “data to storefront” how-to. Aber ich steige nich dahinter wie jetzt Daten von meinen bspw. Subscriber an mein spezifisches CMS Element übergebe welches halt in der Storefront ausgegeben wird.

Du hast ja praktisch: Administration ggf. Plugin Konfiguration -> CMS Element mit Config -> Subscriber/PHP Class/what ever -> Storefront

{{ dump() }}

benutz einfach die dump() funktion in twig, ganz unten findest du dann die im subscriber definierten extensions. Ob man nun die CMS Elemente gezielt subscriben kann weiß ich nicht.

Falls du Inhalte deines CMS elementes asynchron nachladen willst, geht das nur über JS + Controller.

 

Dump kenne ich natürlich, danke dafür :) 

@Moorleiche schrieb:

Ob man nun die CMS Elemente gezielt subscriben kann weiß ich nicht.

Das ist eben die große Quizfrage. Prinzipiell eigentlich nur: Wie übergebe ich Daten an mein custom CMS Element.

Asynchron klar - Dann wäre JS+Controller sinnvoll. Aber ich würde einfach gerne wissen wollen wie das generell geht.

Bspw. habe ich im Produkt CMS Element Slidergesucht, wie die Produkte rein geladen werden. Hier wird eine element variabel übergeben ( wie in jedem CMS twig template ). Nur wie diese eben übergeben wird / wo sie hier kommt ist halt die Quizfrage

Jemand vielleicht noch einen Tip, wie ich Daten von meinen Subscriber an mein spezifisches CMS Element übergebe?

Hallo,

ich weiß es leider auch nicht sicher, aber ich würde jetzt vermuten, dass du für ein eigenes CMS Element auch einen eigenen Resolver benötigst. Wie z.B. den Resolver für die ProductBoxes https://github.com/shopware/platform/blob/master/src/Core/Content/Product/Cms/ProductBoxCmsElementResolver.php
Diesen Doku-Artikel Shopware 6: Adding a custom CMS element hattest du schon durch gelesen oder?

Viele Grüße aus Schöppingen

cool Michael Telgmann

1 Like

[@Michael Telgmann](http://forum.shopware.com/profile/17553/Michael Telgmann “Michael Telgmann”)‍  Die Doku Artikel habe ich gelesen, jop. Das CMS Element an sich habe ich auch, nur eben weiß ich nicht ganz wie ich die Daten nun an das twig Template geben soll. Ich habe es jetzt schon einmal so:

    /**
     * @RouteScope(scopes={"sales-channel-api"})
     * @Route("sales-channel-api/v1/sns/test", name="sns.test", methods={"GET"})
     */
    public function getTest(): Response
    {
        return $this->renderStorefront('@Storefront/element/cms-element-meinelement.html.twig', ['test' => 'test']);
    }

Ich habe es mir von hier abgeschaut: https://github.com/shopware/platform/blob/98e2cc6672a40a671d9d3a86b737f5ae52c55cec/src/Storefront/Controller/CheckoutController.php#L88-L96

Die Variabel test wird nun zumindest im Storefront CMS Element ausgegeben, allerdings wird das Element so auch nur ausgegben, wenn man die API abfragt, logischerweise. Das twig Template an sich gibt die Variabel nicht aus.

Also API gibt zurück: - Test ist in diesem Fall im Twig Template {{ test }}

	test

Rufe ich die Seite gaz normal auf, so gibt das CMS Element mir nur das leere Div zurück, ohne die Variabel Test, weil das twig Template ja nicht direkt die API antingelt.  Hoffe das ist verständlich ^^

Vielleicht müsste ich das jetzt einfach kombinieren mit dem element-replace.helper.js Helper, sodass der Inhalt dann über Javascript ersetzt wird.

Ich bin mir aber nicht ganz sicher, ob das überhaupt der richtige Weg ist.

Den Resolver schaue ich mir noch einmal gesondert an, danke dafür.

Andere Alternative wäre eine twig-Extension. So kannst du eigene twig funktionen in deinem template nutzen, egal ob als cms element oder im header/footer

Service dazu:

 

1 Like

Hallo,

der Resolver sollte die Lösung zu dem Problem sein. Jedes Element, dass im Core vorhanden ist, hat ja seinen eigenen Resolver. Dementsprechend müssen auch Custom Elemente einen eigenen Resolver mitbringen. 
Irgendwelche Krücken über Twig Funktionen oder Nachladen per JS sollten nicht der Way-To-Go sein. 

Viele Grüße aus Schöppingen

cool Michael Telgmann

1 Like

[@Michael Telgmann](http://forum.shopware.com/profile/17553/Michael Telgmann „Michael Telgmann“)‍

Was wäre deiner Meinung nach die bessere Alternative zu Twig Funktionen/Filtern?

Vom Gefühl her ist wesentlich umständlicher beispielsweise eine Funktion über den Event-Subscriber und eigene Template Extensions einzubinden.

In diesen Fall ist der Resolver der richtige Weg, hab mich zwar noch nicht damit befasst, aber das kommt sicher auch noch :stuck_out_tongue:

LG

Mir gings jetzt auch nur um diesen konkreten Fall der Custom CMS Elemente  Wink
Das gilt jetzt natürlich nicht allgemein für alles  Smile

[@Michael Telgmann](http://forum.shopware.com/profile/17553/Michael Telgmann “Michael Telgmann”)‍  Hättet Ihr in Zukunft vielleicht ein How-To für Dummies mit dem Resolver? :slight_smile:

Das CMS Element How-To gibt ja in der Storefront prinzipiell lediglich die configs aus dem CMS Element aus. Jetzt habe ich das CMS Element, fertig - Aber die Daten werden über die API & den entsprechenden Storefront Controller geholt, sowie es sich anscheinend nicht gehört  Grin

Hallo,
ja, wir haben für die Doku bereits Tickets vorliegen. Ich hoffe, dass diese zeitnah umgesetzt werden können. 

Viele Grüße aus Schöppingen

cool Michael Telgmann

1 Like

Hey @Shopwareianer‍, wie ihr schon rausgefunden habt, wird für jedes Element ein eigener CMS Element Resolver benötigt. Dieser wird immer dann aufgerufen, wenn eine CMS Seite mit deinem eigenen Element angefragt wird - egal ob via Storefront oder API, da die unterliegende Implementierung immer gleich funktioniert.

Du brauchst nun also eine PHP Klasse die das Shopware\Core\Content\Cms\DataResolver\Element\CmsElementResolverInterface Interface implementiert. Ich empfehle aber von der abstrakten Klasse Shopware\Core\Content\Cms\DataResolver\Element\AbstractCmsElementResolver abzuleiten, da dort noch Helferfunktionen enthalten, die für das dynamische Mapping von Entitäten da sind.

Das Interface gibt 3 Methoden vor, die implementiert werden müssen:

  1. getType() - Diese Methode gibt den technischen Namen für dein Element zurück, damit wir wissen, wenn ein Element mit diesem Namen aufgelöst werden soll, nimm diese Implementierung.

  2. collect() - Dort bekommst du eine SlotEntity und den ResolverContext rein. In der SlotEntity ist nun die Config für dein Element, also das, was z.B. in der Administration konfiguriert wurde. (eine Produkt ID oder eine Liste von Medien oder oder oder…). Diese Methode ist dafür gedacht, Suchkriterien für weitere Daten zu erstellen. Bedeutet, wenn du z.B. eine Produkt ID konfiguriert hast, möchtest du, dass die ID zu einem Produkt aufgelöst wird. Du kannst also ein neues Criteria Objekt erstellen, wo du diese Produkt ID hinterlegst. Wir kümmern uns später darum, dass es für dich aufgelöst wird - darum brauchst du dich in der Regel nicht kümmern.

  3. enrich() - Nachdem wir von allen Element wissen, welche Daten die angefordert haben (z.B. das Produkt XY), versuchen wir möglichst effizient alle angefragten Daten nachzuladen. Wenn das passiert ist, wird diese Methode (enrich) aufgerufen und bekommt als Parameter wieder die SlotEntity sowie eine Collection der aufgelösten Daten. Und hier ist nun der Knackpunkt: In der SlotEntity hast du Zugriff auf setData(). Das ist dein Tor zur Storefront. Alles was du nun hier rein packst, wird dir auch in der Storefront (und API) zusätzlich zu deinem Element zur Verfügung stehen. 

Hier mal ein simples Beispiel mit Kommentaren:

class MyForumElementResolver extends AbstractCmsElementResolver
{
    public function getType(): string
    {
        return 'my_forum'; // technischer Name des Elements
    }

    public function collect(CmsSlotEntity $slot, ResolverContext $resolverContext): ?CriteriaCollection
    {
        // Konfiguration des Elements auf der CMS Seite (Daten aus Administration)
        $config = $slot->getFieldConfig();

        // z.B. ein konfiguriertes Produkt, das nun aufgelöst werden soll
        $productConfig = $config->get('product');

        // Wir müssen keine weiteren Daten anfragen wenn:
        // 1. die Config nicht existiert
        // 2. die Daten aus einem anderen Feld bezogen werden (mapped)
        // 3. keine Value für die Config existiert
        if (!$productConfig || $productConfig->isMapped() || $productConfig->getValue() === null) {
            return null;
        }

        // neues Criteria Objekt, welches das konfigurierte Produkt laden soll
        $criteria = new Criteria([$productConfig->getValue()]);

        $criteriaCollection = new CriteriaCollection();

        // Die Anfrage für das Produkt muss nun dieser Liste hinzugefügt werden, da auch mehrere Daten
        // angefragen werden können
        $criteriaCollection->add(
            'my_forum_product', // einzigartiger Key, damit wir die Daten später wiederfinden
            ProductDefinition::class, // Auf welche Entität bezieht sich das Criteria Objekt
            $criteria
        );

        return $criteriaCollection;
    }

    public function enrich(CmsSlotEntity $slot, ResolverContext $resolverContext, ElementDataCollection $result): void
    {
        $config = $slot->getFieldConfig();

        // Ein neues Objekt welches in der Storefront zur Verfügung steht
        $data = new ArrayEntity();
        $slot->setData($data);

        // Aus dem ResultSet das Produkt raus holen und in $data mappen
        $product = $result->get('my_forum_product')->first();
        $data->set('product', $product);

        // die Daten stehen nun via Storefront + API bereit
    }
}

Der Resolver muss dann noch im Container hinzugefügt und mit shopware.cms.data_resolver getagged werden.

5 Likes

Der Resolver muss dann noch im Container hinzugefügt und mit shopware.cms.data_resolver getagged werden.

Wo macht man das?  

in der services.xml

Ich hab mich da am ProductSliderCmsElementResolver orientiert.

Hi, 

könnt Ihr sowas vielleicht in die Docs (beim Howto für Custom CMS-Element z.B.) mit aufnehmen?

Man sucht sich ja sonst kaputt oder baut sich kurzerhand eine eigene, weniger elegante Lösung.

Viele Grüße,

Sebastian

oh manno, 

den Thread jetzt gefunden, nachdem ich Tage verbracht hab, die Produktboxen vernünftig in die Storefront zu bekommen. Hier wäre echt super, wenn ihr das in die Docs aufnehmt mit einem konkreten Beispiel …

LG, Oliver