ich möchte in einem Plugin nach der neuen Pluginstruktur Less-Variablen aus der Konfiguration holen. Um die Events etwas zu strukturieren habe ich mir daher Subscriber angelegt und befinde mich daher in einer classSubscriber ``implementsSubscriberInterface.
Mit dem unteren Code kann ich mir die Konfiguration in LESS-Variablen sammeln. Schön und gut. Nun möchte ich jedoch die Konfiguration je Subshop / Multishop separat speichern.
public function onCollectLessFiles(\Enlight_Event_EventArgs $args)
{
$less = new LessDefinition(
//configuration
[
'less-variablenname' => Shopware()->Config()->get('less-config-element')
],
//less files to compile
[__DIR__. '/../Resources/Views/frontend/_public/src/less/all.less'],
//import directory
__DIR__
);
return new ArrayCollection([$less]);
}
In der alten Plugin-Bootstrap hätte ich mir zunächst eine Instanz des Shops geholt.
public function addLessFiles(Enlight_Event_EventArgs $args)
{
$shop = $args->getShop();
$config = $this->collection->getConfig($this->name,$shop);
$less = new LessDefinition(
//configuration
array(
'less-variablenname' => $config->get('less-config-element'),
),
//less files to compile
array(
__DIR__. '/Views/frontend/_public/src/less/all.less'
),
//import directory
__DIR__
);
return new ArrayCollection([$less]);
}
In dem Subscriber bekomme ich hiermit beim Kompilieren einen JSON Fehler.
Wie macht man das also in der neuen Plugin-Struktur + in einem Subscriber?
Du musst also den config Service in der services.xml angeben. Wie im Beispiel statt dem slogan Service. Der config Service geht einfach dumm „config“ ;)
Ups. Sorry. Der Sevice heißt auch “shopware.plugin.cached_config_reader” und nicht “config”. Die Liste ist schlecht und einfach nicht richtig gepflegt und unvollständig.
Könnte ich hier nun auch problemlos den shopware.plugin. cached _config_reader verwenden? Soll ja performanter sein, aber was wären die Nachteile? Man muss den Cache leeren? Muss man das nicht eh?
Auch konnte ich es noch nicht testen, da ich unter vagrant keinen Multishop habe -.- Sieht das nun so korrekt aus?
Ne, wenn du das so machst ist die Dependency Injection nicht notwendig. Allerdings sollte man vermeiden das globale Shopware() Objekt zu benutzen. Es ist schlechter Programmierstil globale Objekte zu nutzen. Das verhindert, das du irgendwann mal Tests für deine Software schreiben könntest. Also es funktioniert, ist aber schlechter Stil
Du kannst in deiner Zeile auch den cached_config_reader nutzen. Der cached Reader speichert Konfig Einträge die du aufgerufen hast im Arbeitsspeicher. Wenn du also auf einen Konfig Wert öfter in deinem Request zugreifst, und ihn dir nicht selber in einer Variablen speicherst, spart man sich ein Paar Datenbank Abfragen. Ist aber kein großes Ding. Nachteile sind zu vernachlässigen. Den Cache leeren muss man auch nicht.
Den Zugriff auf das Shopware-Objekt mache ich, weil es so in der Doku stand und in einem Subscriber $this->container nicht funktioniert. Wie wäre es sauberer?
Also da gibt es auch mehere Ansätze. Du kannst einfach den ganzen Service Container in deine Subscriber Klasse reinreichen. Das ist bequem und du hast keine Probleme. Nachteil ist, dass man nicht wirklich auf den ersten Blick sehen kann, von welchen anderen Services dein Service abhängig ist (die Subscriber Klasse ist auch ein Service). Das mag erstmal kein Problem sein, schränkt aber die Testbarkeit deines Services ein. Wenn du nicht weist welche Services du nutzt, weist du auch nicht welche du in deinen Tests mocken musst. Dies bezieht sich jetzt aber jetzt nur auf die Testbarkeit. Da bei Shopware sowieso so gut wie niemand Tests schreibt ist das aber auch zu vernachlässigen. Falls du deinen Programmierstil weiter entwickeln willst, wäre es aber schon gut sich daran zu orientieren
Bequem - service.xml
1plus mit Sternchen - service.xml
%dein_plugin.plugin_name%
hier nur dein_plugin ersetzen. “.plugin_name%” soll wirklich so da stehen.
Bequem - constructor deine Subscriber Klasse
container = $container;
}
}
Hier kannst du jetzt mit $this->container->get() auf sämtliche Services zugreifen.
1plus mit Sternchen - constructor deine Subscriber Klasse
Hier hast du jetzt nur die Services reingereicht, die ein eigener Service nutzt. Das ist sehr explizit und man weiß wovon dein Service anhängt und welche Services man testen mocken muss.
HTH, Arne
PS: Der Abschnitt aus der Doku stammt soagr von mir. Ich hatte die globale Abhängigkeit dort auch rausgelöscht. Aber Shopware wollte es lieber, dass es für die Kompatibilität drin bleibt.
bei deiner 1+ Sterchen Lösung kommt leider eine Fehlermeldung im Backend:
deinPlugin\Subscriber\Subscriber::__construct() must be an instance of Shopware\Models\Shop\Shop, none given, called in /home/vagrant/www/sw-plugins/var/cache/production____REVISION___/proxies/
Edit: Bezüglich der xml bekomme ich auch einen Fehler:
Fatal error: Uncaught Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: The service "dein_plugin.subscriber.subscriber" has a dependency on a non-existent service "shop"
habe ich dann weggelassen - dann gehts
Edit 2:
Uncaught TypeError: Argument 1 passed to deinPlugin\Subscriber\Subscriber::__construct() must implement interface Symfony\Component\DependencyInjection\ContainerInterface
%deinPlugin.plugin_name%
Sorry. shop gibt es tatsächlich nicht als Service. Mein Fehler. Der Servide heißt shopware_storefront.context_service und den Shop bekommt men durch getShopContext()->getShop(); Ich hab mein Beispiel oben angepasst.
zu Edit 2:
Hm das wundert mich etwas. Hast du vorher die bequeme Lösung probiert und vielleicht vergessen den Cache zu leeren? Hab die Erfahrung gemacht, dass man nach Änderungen an der service.xml den Cache leeren muss.
Leider kann ich deinen 1+ mit Sternchen weg nicht nachvollziehen, weil die Probleme mit dem Service Shop und getShopContext() nicht aktualisiert wurden… kannst Du mir hier vll. weiterhelfen?
Konkret habe ich Probleme den Subshop zu bekommen.