Wie stelle ich eine Variable aus meinem Plugin im gesamten Frontend (in allen Twig Templates) zur Verfügung?

Hallo,

in meinem Plugin lade ich ein Bild hoch und möchte dieses Bild in Twig zur Verfügung haben. Wie ich es via Controller in einem Twig Template zur Verfügung stelle, weiß ich. Was mir jedoch nicht klar ist: Wie kann ich die Variable „überall“ zur Verfügung stellen.

Hier mal mein aktueller Stand via eigenem Controller:

„src/Resources/config/config.xml“

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/platform/trunk/src/Core/System/SystemConfig/Schema/config.xsd">
    <card>
        <title>Bild</title>
        <component name="sw-media-field">
            <name>pluginMedia</name>
            <label>Upload media or choose one from the media manager</label>
        </component>
    </card>
</config>

„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="MeinPlugin\Storefront\Controller\TestController" public="true">
            <call method="setContainer">
                <argument type="service" id="service_container"/>
            </call>
            <argument type="service" id="media.repository"/>
            <argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
        </service>
    </services>
</container>

„src/Resources/config/routes.xml“

<?xml version="1.0" encoding="UTF-8" ?>

<routes xmlns="http://symfony.com/schema/routing"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">

    <import resource="../../Storefront/Controller/**/*Controller.php" type="annotation"/>
</routes>

„src/Storefront/Controller/TestController.php“

<?php

namespace MeinPlugin\Storefront\Controller;

use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Controller\StorefrontController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;

/**
 * @RouteScope(scopes={"storefront"})
 */
class TestController extends StorefrontController
{
    private EntityRepositoryInterface $mediaRepository;
    private SystemConfigService $systemConfigService;

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

    /**
     * @Route("/test", name="frontend.testplugin.test", methods={"GET"})
     */
    public function showPage(Request $request, SalesChannelContext $salesChannelContext, Context $context): Response
    {
        $pluginMedia = $this->systemConfigService->get('MeinPlugin.config.pluginMedia');
        $image = $this->mediaRepository->search(new Criteria([$pluginMedia]), $context);

        return $this->renderStorefront('@MeinPlugin/storefront/page/test/index.html.twig', [
            'customString' => $image,
        ]);
    }
}

„src/Resources/views/storefront/page/test/index.html.twig“

{% sw_extends '@Storefront/storefront/base.html.twig' %}

{% block base_content %}
    {{ dump( customString ) }}
{% endblock %}

Wenn ich im Frontend nun die Route „meineseite.de/test“ aufrufe, habe ich dort ja „bild“ zur Verfügung.

Was ich jedoch wie gesagt nicht verstehe ist, wie ich es anstelle, dass „bild“ einfach im gesamten Frontend zur Verfügung steht. sodass ich es in jedem Twig Template nutzen kann, welches ich jetzt oder auch in der Zukunft erstelle.

Wäre über jede Hilfe dankbar.

Allgemein hast du im Template mit config('MeinPlugin.config.pluginMedia') Zugriff auf den Pluginconfig Wert.
Da bei deinem Fall aber die Media ID gespeichert wird, müsstest du im Template aber die Media URL nachladen.
Ich weiß gerade nicht, ob es hierfür bereits einen Standard Weg gibt. Ansonsten müsstest du dir ein JS Plugin schreiben, welches dir die Media URL anhand der ID ermittelt und im Storefront entsprechend ausgibt.

Ok, danke schon mal. Aber es müsste doch auch einen Weg geben, jede beliebige Variable im gesamten Frontend zur Verfügung zu stellen, oder?

Über GenericPageLoadedEvent könntest du jeder Page deine Variable als Extension hinzufügen.

Danke dir. Dass es über einen Subscriber gehen könnte, habe ich mir schon gedacht. Dachte aber wirklich, dass es eine elegantere Lösung gibt. Eventuell weiß ja jemand noch etwas besseres? Ich lasse meine „Lösung“ jetzt mal hier als Referenz da:

„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="MeinPlugin\Subscriber\MySubscriber">
            <argument type="service" id="media.repository"/>
            <argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>
</container>

„src/Subscriber/MySubscriber.php“

<?php declare(strict_types=1);

namespace MeinPlugin\Subscriber;

use Shopware\Core\Content\Category\Event\NavigationLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Struct\ArrayEntity;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class MySubscriber implements EventSubscriberInterface
{
    private EntityRepositoryInterface $mediaRepository;
    private SystemConfigService $systemConfigService;

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

    public static function getSubscribedEvents(): array
    {
        return [
            NavigationLoadedEvent::class => 'onNavigationLoaded'
        ];
    }

    public function onNavigationLoaded(NavigationLoadedEvent $event): void
    {
        $pluginMedia = $this->systemConfigService->get('MeinPlugin.config.pluginMedia');
        $image = $this->mediaRepository->search(new Criteria([$pluginMedia]), $event->getContext())->first();

        //declare an array
        $array = ['key1' => $image];

        //add the array to the context as an extension
        $event->getContext()->addExtension('testContextExtension', new ArrayEntity($array));
    }
}

Ich habe das „NavigationLoadedEvent“ genommen, weil ich das Bild in der Navigation benötige.
Referenz: Gibt es eine Liste von Events fuer Shopware 6? - #2 von patchee500
Referenz2: https://shopwarian.com/how-to-get-the-data-from-php-to-the-twig-template/

Im Twig Template komme ich dann an URL per:
{{ dump( context.context.extensions.testContextExtension[‚key1‘].url ) }}

Bzgl. deinem ersten Hinweis, wäre man so an die Plugin Config im Twig Template gekommen:

Referenz1

Dieser Text wird ausgeblendet

{{ config(‚MeinPlugin.config.pluginMedia‘) }}

Referenzen2

Weitere Refrenzen:
Use plugin configuration - Shopware Developer
Data Abstraction Layer - Shopware Developer
Add custom controller - Shopware Developer
Reading data - Shopware Developer

Vielleicht hilft es jemand.

Falls trotzdem noch jemand eine bessere Lösung kennt, immer gerne her damit.

Ich benutze für solche Fälle das HeaderPageletLoadedEvent, der wird mWn immer geladen.

@zlep , ich kenne zwar deine Anforderung nicht, aber wenn es nur um die Anzeige des Bildes geht, wäre es hier nicht besser das entsprechende Layout (Erlebniswelt) anzupassen?

@AlexBS Ok, danke. Also ist es über Events / Subscriber grundsätzlich schon richtig?!

@abdullah
Müsste ich mal schauen, aber ich glaube nicht. Ich habe mir mein komplett eigenes Menu-Plugin gebaut. Am einfachsten wäre sowieso gewesen, ich hätte das Bild per Asset eingefügt, aber ich wollte es etwas dynamischer machen, sodass man das Bild ggf. auch über die Plugin Config hochladen und austauschen kann.

Außerdem bin ich sowieso noch am Shopware 6 lernen, da kam mir so eine Aufgabe genau richtig :slight_smile: Habe durchaus einiges über Services, Controller, Subscriber usw. gelernt :slight_smile:

Danke euch auf jeden Fall.

Ich vermute es mal haha Zumindest ist es ja so, dass du alles was du im Frontend siehst, irgendein Attribut einer Klasse ist und über das Extension Array, das viele Klassen mitbringen, eigene Variablen mitgeben kannst.