Shopware

Wenn der Shopware-Kern eine Plugin-Route verdrängt

Ein Minor-Update kann eine Plugin-Route stilllegen, ohne dass irgendwo ein Fehler erscheint. Wir haben den Fall in zwei Runtimes nebeneinandergestellt und gemessen, welche Route gewinnt.

Pixup MediaVeröffentlicht am 7 Min. Lesezeit

Ein Plugin läuft seit Monaten. Es installiert sauber, es ist aktiv, seine Konfiguration steht im Backend, und die Datei, die es ausliefern soll, ist im Shop erreichbar. Trotzdem stammt ihr Inhalt nicht mehr aus dem Plugin.

Das ist kein Einzelfall und kein Bug. Es ist die normale Arbeitsweise des Routers — und sie wird zum Problem, sobald der Kern einen Pfad belegt, den vorher ein Plugin hatte.

Der Aufbau

Wir betreiben für Kompatibilitätsprüfungen zwei Shopware-Runtimes parallel, mit identischem Pluginstand:

RuntimeVersionZweck
pixup-sw66-compat6.6.10.6Nachweis, dass Erweiterungen auf der Vorgängerlinie weiterlaufen
pixup-sw67-compat6.7.13.1Prüfung derselben Erweiterungen auf der aktuellen Linie

In beiden ist eine Erweiterung installiert, die eine Route auf /robots.txt registriert. Die Frage war nicht, ob sie installiert ist — das war sie in beiden. Die Frage war, ob sie noch etwas ausliefert.

Die Messung

Ein einziger Befehl beantwortet das:

bin/console debug:router | grep robots

Shopware 6.6.10.6 — eine Route:

frontend.pixup.robotstxt      GET   /robots.txt

Shopware 6.7.13.1 — zwei Routen auf demselben Pfad:

frontend.robots.txt           GET   /robots.txt
frontend.pixup.robotstxt      GET   /robots.txt

Der Kern hat den Pfad übernommen. Beide Routen sind registriert, beide akzeptieren GET, beide haben dasselbe Pfad-Regex {^/robots\.txt$}sDu.

Welche antwortet? Auch das lässt sich messen, statt es zu vermuten:

bin/console router:match /robots.txt --method=GET
[OK] Route "frontend.robots.txt" matches

Die Kernroute gewinnt. Die Pluginroute ist registriert, sichtbar, konfiguriert — und wird nie aufgerufen.

Warum das so ist

Symfony behandelt Routen als geordnete Liste und nimmt die erste, deren Pfad und Methode passen. Es gibt keinen Prioritätswert, den ein Plugin hochsetzen könnte, und es gibt keine Warnung bei doppelten Pfaden. Aus Sicht des Routers ist das kein Konflikt, sondern eine beantwortete Anfrage.

Entscheidend ist damit allein die Ladereihenfolge — und die Routendateien des Kerns werden vor denen der Plugins gelesen. Ein Plugin kann eine Kernroute auf demselben Pfad also nicht überstimmen, solange es nur eine weitere Route registriert.

Das ist der unangenehme Teil: Die Erweiterung verhält sich in jeder sichtbaren Hinsicht korrekt. plugin:list zeigt sie als aktiv. Das Backend zeigt ihre Einstellungen. Die URL liefert eine gültige Antwort mit Status 200. Nur der Inhalt kommt von woanders. Es gibt keinen Log-Eintrag, keine Health-Check-Warnung und keinen Deprecation-Hinweis, der darauf zeigt.

Woran man es merkt — und woran nicht

PrüfungSchlägt an?
plugin:list zeigt das Plugin aktivnein, es ist aktiv
HTTP-Status der URLnein, 200
Log-Dateiennein, kein Fehler
Backend-Konfiguration lässt sich speichernnein, sie wird nur nicht mehr gelesen
Inhalt der Antwort mit der erwarteten Ausgabe vergleichenja
debug:router, Pfad kommt doppelt vorja
router:match <pfad> nennt eine fremde Routeja

Die drei unteren Zeilen sind der Grund, warum ein Kompatibilitätstest nicht bei „installiert und Seite lädt" aufhören darf. Ein Plugin gilt uns erst dann als lauffähig auf einer neuen Minor-Version, wenn seine Wirkung gemessen ist — nicht seine Anwesenheit.

Was Plugin-Entwickler daraus mitnehmen

Eigene Pfade wählen, die der Kern nicht braucht. Ein Plugin, das unter einem eigenen Präfix arbeitet, gerät nie in diese Lage. Standardpfade wie /robots.txt, /sitemap.xml oder /health sind Kandidaten dafür, in einer kommenden Version im Kern aufzutauchen.

Beim Versionswechsel Pfade gegeneinander prüfen. debug:router vor und nach dem Update, Ausgabe vergleichen, doppelte Pfade suchen. Das dauert eine Minute und ist die einzige Prüfung, die dieses Muster zuverlässig findet.

Nicht auf einen Fehler warten. Diese Klasse von Regression meldet sich nicht. Sie fällt auf, wenn jemand den ausgelieferten Inhalt anschaut — im schlechtesten Fall Monate später, wenn eine Suchmaschine sich anders verhält als erwartet.

Was Shopbetreiber daraus mitnehmen

Nach einem Minor-Update ist die Frage nicht „läuft der Shop", sondern „tun die Erweiterungen noch, wofür sie gekauft wurden". Der Unterschied klingt klein und ist er nicht: ein Shop kann vollständig funktionieren, während drei Erweiterungen still nichts mehr beitragen.

Eine kurze Prüfliste nach jedem Minor-Update:

  1. Welche Erweiterungen liefern eine Datei oder Route aus? Deren Ausgabe direkt abrufen und mit dem Erwarteten vergleichen.
  2. debug:router auf doppelte Pfade durchsehen.
  3. Erweiterungen, die Felder am Produkt schreiben, gegen die aktuelle Definition prüfen — Shopware macht Felder zwischen Versionen auch schreibgeschützt. Wie das aussieht, steht in Produktdaten übersetzen, ohne Daten zu verlieren.

Warum wir das aufgeschrieben haben

Wir entwickeln eigene Shopware-Erweiterungen und pflegen sie über Versionswechsel hinweg — die vier öffentlich verfügbaren stehen unter Shopware Plugins. Dieser Befund stammt aus genau dieser Arbeit: aus der Kompatibilitätsprüfung, nicht aus einem Kundenvorfall.

Wenn Sie eine Erweiterung betreiben, die auf einem Standardpfad arbeitet, ist der Befehl oben eine Minute gut investierter Zeit. Wenn Sie unsicher sind, welche Ihrer Erweiterungen betroffen sein könnten, hilft ein Blick von außen: Shopware-Support beschreibt, wie wir solche Prüfungen durchführen.

Häufige Fragen

Warum meldet Shopware keinen Fehler, wenn zwei Routen denselben Pfad haben?
Weil es aus Sicht des Routers kein Fehler ist. Symfony sammelt alle Routen in einer geordneten Liste und nimmt die erste, die passt. Doppelte Pfade sind erlaubt; die späteren sind schlicht unerreichbar. Es gibt keine Kollisionsprüfung, die anschlägt.
Hilft es, dem Plugin eine höhere Priorität zu geben?
Es gibt keinen Prioritätswert für Routen in Symfony. Was zählt, ist die Reihenfolge, in der die Routendateien geladen werden — und Kernrouten werden vor Pluginrouten geladen. Ein Plugin kann sich nicht davorschieben, ohne in den Ladevorgang einzugreifen.
Wie finde ich betroffene Routen im eigenen Shop?
bin/console debug:router listet alle Routen mit Pfad. Wenn derselbe Pfad zweimal auftaucht, ist eine davon tot. bin/console router:match <pfad> sagt, welche gewinnt.
Betrifft das nur /robots.txt?
Nein. Der Pfad ist nur der Fall, an dem wir es gemessen haben. Das Muster gilt für jede Route, die ein Plugin auf einem Pfad registriert, den der Kern später selbst belegt — und Shopware ergänzt in Minor-Releases regelmäßig Storefront-Routen.