Header Pagelet - Assign Variable ausgeben

Hallo!

 

Ich teste gerade die neue Pluginentwicklung.

In einem Subscriber versuche ich mir bestimmte Daten an die View zu geben:

 

class FrontendSubscriber implements EventSubscriberInterface
{
    const CONFIG_NAMESPACE = 'CompraSW6Test.config.';

    /**
     * @var SystemConfigService
     */
    private $systemConfigService;

    public function __construct(SystemConfigService $systemConfigService)
    {
        $this->systemConfigService = $systemConfigService;
    }

    public static function getSubscribedEvents()
    {
        return [
            HeaderPageletLoadedEvent::NAME => 'onHeaderPageletLoaded'
        ];
    }

    /**
     * @param HeaderPageletLoadedEvent $event
     * @throws \Shopware\Core\System\SystemConfig\Exception\InvalidDomainException
     */
    public function onHeaderPageletLoaded(HeaderPageletLoadedEvent $event)
    {
        if (!$this->systemConfigService->get('CompraSW6Test.config.active')) {
            return;
        }

        $pluginConfig = $this->systemConfigService->getDomain(self::CONFIG_NAMESPACE);
        $event->getPagelet()->assign($pluginConfig);
    }
}

 Die Daten kommen auch in der View an. Wenn ich mir die Variablen mit {{ dump() }} ausgeben lasse, wird mir folgendes angezeigt:

array:9 [▼
  "page" => NavigationPage {#3106 ▼
    #cmsPage: CmsPageEntity {#3114 ▶}
    #header: HeaderPagelet {#2050 ▼
      -navigation: Tree {#2825 ▶}
      -offcanvasNavigation: Tree {#2975 ▶}
      -languages: LanguageCollection {#3006 ▶}
      -currencies: CurrencyCollection {#3048 ▶}
      -activeLanguage: LanguageEntity {#3007 ▶}
      -activeCurrency: CurrencyEntity {#1047 ▶}
      -serviceMenu: CategoryCollection {#2124 ▶}
      #extensions: []
      +"CompraSW6Test.config.active": true
      +"CompraSW6Test.config.customText": "custom text"
      +"CompraSW6Test.config.readonlyText": "readonly"
      +"CompraSW6Test.config.selectColor": "red"
      +"CompraSW6Test.config.selectStyle": array:1 [▶]
    }
    #footer: FooterPagelet {#3062 ▶}
    #context: SalesChannelContext {#1632 ▶}
    #extensions: []
  }
  "shopware" => array:3 [▶]
  "controllerName" => "Navigation"
  "controllerAction" => "home"
  "context" => SalesChannelContext {#1632 ▶}
  "activeRoute" => "frontend.home.page"
  "formViolations" => null
  "app" => AppVariable {#268 ▶}
  "isHMRMode" => false

 

Ich versuche nun verzweifelt mir die Variable für den CustomText im Header ausgeben zu lassen, allerdings wird nichts ausgegeben:

{% sw_extends '@Storefront/layout/header/top-bar.html.twig' %}

{% block layout_header_top_bar_language %}
    {{ page.header.CompraSW6Test.config.customText }}
    {% if context.customer %}

        
            
                {{ 'compra-sw6test.index.salutationText'|trans }} {{ context.customer.firstName }} {{ context.customer.lastName }}
                    (Abmelden)
            
        
    {% endif %}
    {{ parent() }}
{% endblock %}

 

Kann das reproduzieren… sehe meine Variablen auch im dump, kann diese allerdings ebenfalls nicht ausgeben… 

Die Keys sind das Problem bei dir 

Denn du willst nicht: page.header.CompraSW6Test.config.customTex

sondern: page.header[‘CompraSW6Test.config.customTex’]

Ich würde die Keys anders nennen z.b so page.header.CompraSW6TestconfigcustomTex ohne Punkte dann sollte das klappen

@Rainware schrieb:

Die Keys sind das Problem bei dir 

Denn du willst nicht: page.header.CompraSW6Test.config.customTex

sondern: page.header[‚CompraSW6Test.config.customTex‘]

Ich würde die Keys anders nennen z.b so page.header.CompraSW6TestconfigcustomTex ohne Punkte dann sollte das klappen

 

Auch mit dem anderen Key-Zugriff funktioniert es nicht. Bisher konnte ich die Daten nur ausgeben lassen, wenn ich statt assign die Daten mit addExtension und einer Data + DataService Klasse bereitsgestellt habe

Wenn du deine Konstante änderst in: 

const CONFIG_NAMESPACE = 'CompraSW6Test';

und den Aufruf im Template mit 

{{ page.header.CompraSW6Test.customText }}

machst, dann sollte es gehen. Bei mir klappt es so.

Ich nehme an, dass die Konstante im String keinen Punkt enthalten darf, da dieser ja zum Navigieren im Array genutzt wird. 

 

//Edit: Ach quatsch. Du holst dir die config ja mit getDomain() und dann werden die bei dir immer mit CONFIG_NAMESPACE.config assigned… 
Holt man sich jeden Wert einzeln und weist diese der View zu, kann man das unterbinden…

 

Hi,

um Daten in Shopware 6 zu erweitern könnt ihr das extension System benutzen. Jedes Objekt in Shopware 6 leitet von der Struct Klasse ab welches es ermöglicht über ->addExtension($key, $struct) und ->getExtension($key) weitere Daten an ein Objekt zuzuweisen. 

[@Oliver Skroblin](http://forum.shopware.com/profile/1871/Oliver Skroblin „Oliver Skroblin“)‍ 

Gibt es einen speziellen Trick wie man über twig auf die extensions zugreift?

Habe dem Header mal eine extension hinzugefügt und diese wird auch im dump ausgegeben:

 

Und so versuche ich im template drauf zuzugreifen:

{{ page.header.extensions.my_extension.data.pixel_id }}

 

funktioniert aber nicht

 

//Edit: ohne „data“ gehts. also {{ page.header.extensions.my_extension.pixel_id }}

Hey @robjke‍,

schau dir nochmal den Dump genauer an.
extensions  ist ein Array von Extensions, keine Überraschung. Aber jede Extension, so wie in diesem Fall my_extension, ist jedoch ein ArrayEntity.

Da die ArrayEntity Klasse das ArrayAccess Interface implementiert, kannst du darauf zugreifen wie auf ein Array, und zwar so wie du es bereits getan hast: Ohne das „data“ dazwischen.
Du könntest es aber auch weiterhin als eine Klasseninstanz benutzen und direkt ->get(‚pixel_id‘) bzw. ->offetGet(‚pixel_id‘) aufrufen.

Vielleicht hilft dir das weiter beim Verständnis.

Gruß,
Patrick  Shopware

1 „Gefällt mir“

[@Patrick Stahl](http://forum.shopware.com/profile/1869/Patrick Stahl “Patrick Stahl”)‍

Ok, das werde ich mal ausprobieren, danke. 

Aber grundsätzlich sollte man als best practice immer mit addExtension arbeiten oder?!

Könnte es zu addExtension() vielleicht ein How To geben?

Mir ist das mit dem Struct noch nicht ganz klar und im Paypal-Plugin komme ich nicht ganz klar.
Mit assign() ein Array an Konfigurationen zu assignen geht auch, aber wie würde man das mit addExtension() machen?

Hallo @mdsw‍,

das gibt es hier. :slight_smile:

Gruß,
Patrick  Shopware

2 „Gefällt mir“

In dem Beispiel ist der Struct aber nicht “dynamisch”, sondern der feste wert ‘foo’

Das ganze verwirrt mich irgendwie noch mehr.

Wie bekomme ich jetzt ganz konkret die Werte meiner Plugin-Konfiguration beispielsweise in das Struct bzw in die addExtension() rein.

Bitte für dummies und ohne einzelne Stichwörter.

 

Bin auch gerade am herumprobieren. Hier vielleicht mal ein konkreteres Beispiel, was ich hier vor habe. In SW 5 ließ sich das mit einem einfachen assign eines arrays an die view lösen:

 

Ich habe hier einen Subscriber, der lauscht auf das Event  StorefrontRenderEvent::NAME , könnte aber beispielsweise auch auf das Event  HeaderPageletLoadedEvent::NAME subscriben. In diesem Fall wollte ich mal Ersteren austesten.

config = $config;
	}

	public static function getSubscribedEvents(): array
	{
		return[
			StorefrontRenderEvent::NAME => 'onStorefrontRenderLoaded'
		];
	}

	public function onStorefrontRenderLoaded(StorefrontRenderEvent $event)
	{
		if (!$this->config->get('PluginName.config.active')) {
			return;
		}

		$pluginConfig = array
		(
			'foo' => $this->config->get('PluginName.config.foo'),
			'bar' => $this->config->get('PluginName.config.bar')
		);


		/**
		 * hier das ganze mal mit Struct
		 */
		$event->getSalesChannelContext()->addExtension(self::CONFIG_NAMESPACE, new MyCustomStruct());

		/**
		 * das hier geht auch ^^ ganz ohne Struct
		 */
		$event->setParameter(self::CONFIG_NAMESPACE, $pluginConfig);

	}
}

 

Hier stehen einem nun verschiedene Möglichkeiten bereit, die Werte aus der Konfiguration an die Storefront zu übertragen. Dabei unterscheiden sich die Möglichkeiten je nach Event. Und das führt in der Storefront auch zu einer jeweils anderen Untergliederung. Überflüssig zu sagen, dass die Werte der Konfiguration je nach Event und Vorgehensweise mal direkt in erster Ebene des arrays ( siehe dump() im template ), mal unter page.header, mal unter context… usw erreichbar sind… ich denke das ist klar… aber auch hier… wie sollen Plugins hier vorgehen?

 

 

 

  1. ganz ohne Struct und mit setParameter bei dem Event  StorefrontRenderEvent::NAME

$event->setParameter(self::CONFIG_NAMESPACE, $pluginConfig);

 

  1. mit Struct und mit setParameter bei dem Event  StorefrontRenderEvent::NAME

    $event->setParameter(self::CONFIG_NAMESPACE, new MyCustomStruct());

 

3. ohne Struct und mit assign bei dem Event  HeaderPageletLoadedEvent::NAME

$event->getPagelet()->assign([self::CONFIG_NAMESPACE => $pluginConfig]);

 

  1. mit Struct und getSalesChannelContext bei den Events  StorefrontRenderEvent::NAME oder  HeaderPageletLoadedEvent::NAME

$event->getSalesChannelContext()->addExtension(self::CONFIG_NAMESPACE, new MyCustomStruct());

 

 

 

FRAGE 1: Wo schmeißt man - auf gut deutsch gesagt - seine Konfiguration am besten hin? setParameter ermöglicht einem den Zugriff auf seine Variablen und Werte direkt über {{ PluginName.foo }} während andere Lösungen einem die Variablen zum Beispiel über {{ page.header.PluginName.foo }} ermöglicht.

FRAGE 2: Wenn nun der Weg über ein Struct der saubere und gewollte Weg ist, was muss ich dann im Struct machen? Muss ich hier die Konfiguration mittels SystemConfigService auslesen und dann über den Struct irgendwie bereitstellen?

 

Sowas in der Richtung? Klar… funktioniert nicht, aber vielleicht anhand dieses Beispiels mal aufklären…

config = $config;
	}

	public function getConfig()
	{
		return array(
		'foo' => $this->config->get('PluginName.config.foo'),
		'bar' => $this->config->get('PluginName.config.bar'),
		);
	}
}

 

2 „Gefällt mir“

Weiß hier irgendjemand schon näheres?

[@Patrick Stahl](http://forum.shopware.com/profile/1869/Patrick Stahl “Patrick Stahl”)‍ Ich denke, dass das hier ein zentrales Thema für viele Plugin-Entwickler ist. Sieht man ja auch an den Views dieses Themas. Magst Du hier vielleicht Licht ins Dunkel bringen? Nicht jeder Designer ist ein Symfony-PHP-Crack Undecided

*push*

@robjke schrieb:

In dem Beispiel ist der Struct aber nicht „dynamisch“, sondern der feste wert ‚foo‘

Das ganze verwirrt mich irgendwie noch mehr.

Wie bekomme ich jetzt ganz konkret die Werte meiner Plugin-Konfiguration beispielsweise in das Struct bzw in die addExtension() rein.

Bitte für dummies und ohne einzelne Stichwörter.

Vielleicht hilft dir dieses Beispiel (use cases und namespace lasse ich mal außen vor). Da die Konfiguration aktuell noch keine Default-Values unterstützt, habe einen entsprechenden Rework in der Struct implementiert. Außerdem fiel mir gerade noch auf, dass der Methodenname „setValues“ etwas unglücklich gewählt ist.

Struct

setValues($pluginConfig, 'alwaysVisible', false);
        $this->setValues($pluginConfig, 'position', 'br');
        $this->setValues($pluginConfig, 'colorBorder', '#617183');
        $this->setValues($pluginConfig, 'colorBackground', '#d9400b');
        $this->setValues($pluginConfig, 'colorText', '#ffffff');
        $this->setValues($pluginConfig, 'transparency', '1.0');
        $this->setValues($pluginConfig, 'STPdistanceX', 15);
        $this->setValues($pluginConfig, 'STPdistanceY', 15);
        $this->setValues($pluginConfig, 'padding', 15);
        $this->setValues($pluginConfig, 'fontSize', 14);
    }

    /**
     * @return mixed
     */
    public function getConfig() : array
    {
        return $this->config;
    }

    /**
     * @param array $config
     */
    public function setConfig(array $config): void
    {
        $this->config = $config;
    }

    /**
     * @param array $pluginConfig
     * @param string $key
     * @param null $default
     */
    public function setValues(array $pluginConfig, string $key, $default = null): void
    {
        if(array_key_exists($this->configPath . $key, $pluginConfig)) {
            $this->config[$key] = $pluginConfig[$this->configPath . $key];
        }
        else {
            $this->config[$key] = $default;
        }
    }
}

Der Subscriber

class Storefront implements EventSubscriberInterface
{
    /**
     * @var SystemConfigService
     */
    private $systemConfigService;

    /**
     * Storefront constructor.
     * @param SystemConfigService $systemConfigService
     */
    public function __construct(SystemConfigService $systemConfigService)
    {
        $this->systemConfigService = $systemConfigService;
    }

    /**
     * @return array
     */
    public static function getSubscribedEvents(): array
    {
        return [
            FooterPageletLoadedEvent::NAME => 'onFooterLoaded'
        ];
    }

    /**
     * @param FooterPageletLoadedEvent $event
     * @throws InvalidDomainException
     */
    public function onFooterLoaded(FooterPageletLoadedEvent $event) :void
    {
        $config = $this->systemConfigService->getDomain('saltySw6ScrollToTop.config', $event->getSalesChannelContext()->getSalesChannel()->getId(), true );
        $configValues = new StorefrontPageData($config);

        $event->getPagelet()->addExtension('saltySw6ScrollToTop', $configValues);
    }

 

das jeweilige Template

{{ page.footer.extensions["saltySw6ScrollToTop"].config["padding"] }}

 

4 „Gefällt mir“

Danke für den Input, das sieht schon mal sehr gut aus. 

@DenKon26 schrieb:

@Rainware schrieb:

Die Keys sind das Problem bei dir 

Denn du willst nicht: page.header.CompraSW6Test.config.customTex

sondern: page.header[‚CompraSW6Test.config.customTex‘]

Ich würde die Keys anders nennen z.b so page.header.CompraSW6TestconfigcustomTex ohne Punkte dann sollte das klappen

 

Auch mit dem anderen Key-Zugriff funktioniert es nicht. Bisher konnte ich die Daten nur ausgeben lassen, wenn ich statt assign die Daten mit addExtension und einer Data + DataService Klasse bereitsgestellt habe

Spricht etwas dagegen, sich die Daten über:  {{ shopware.config.CompraSW6Test.config.customTex }} ausgeben zu lassen?

Hallo flix,

nein, ganz im Gegenteil.
Grundsätzlich steht die ganze Config überall im Template unter “shopware.config” zur Verfügung. Man muss sich also als Plugin nicht selber darum kümmern, dass die Plugin Config im Template verfügbar ist. 

Viele Grüße aus Schöppingen

cool Michael Telgmann

1 „Gefällt mir“

Hallo, für mich ist da alles auch noch nicht so klar
ich hab ein Array mit einer Liste die ich anzeigen möchte

in meinem Subscriber verwende ich das addExtension mit dem ArrayStruct

in twig kann ich dann aber nicht mit einem for loop darüber loopen
ich kann die Elemente aber mit dem normalen indexen abrufen [0] [1]
der length filter sagt mir dass das array nur 1 Element hat was falsch ist.

Ich verwende jetzt das Assign, da ich dadurch einfach nur das Array bekomme.

Beste Grüße Lukas

Wie kann ich addExtension verwenden und dann loopen ?

Und warum zeigt mir das dump bei dem Struct ein data field, auf das ma nicht zugreifen kann bzw null ist ?
Warum braucht man das Struct überhaupt
Wäre nice wenns da auch in der Doku ne Erklärung gebe :slight_smile: (Oder Kommentare im Code :D)