lenzebusiness / shopware-extension-check
Various checks for shopware extensions
Package info
bitbucket.org/lenzebusiness/shopware-extension-check
pkg:composer/lenzebusiness/shopware-extension-check
Requires
None
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-01 12:33:33 UTC
README
Statische Prüfungen für Shopware-Extensions. Läuft in den Pipelines aller Extensions und bricht den Build ab, wenn eine Prüfung anschlägt.
Der Schwerpunkt liegt auf Fehlern, die zur Laufzeit nichts melden — tote Twig- Overrides, nicht deklarierte Config-Keys, entfernte Include-Ziele. Genau die fallen bei einem Shopware-Minor-Upgrade sonst niemandem auf.
Verwendung
composer require --dev lenzebusiness/shopware-extension-check "dev-main"
vendor/bin/shopware-extension-check .
Das Argument zeigt auf die Wurzel der zu prüfenden Extension — dort, wo die
composer.json liegt. Ein relativer Pfad wird gegen das aktuelle
Arbeitsverzeichnis aufgelöst, ein absoluter direkt übernommen. Aus dem
Shopware-Root heraus also:
vendor/bin/shopware-extension-check custom/plugins/MyExtension
Exit-Codes: 0 = keine Befunde, 1 = mindestens ein Befund.
In der Pipeline
So ist es in LenzPlatformCreditManagement eingebunden — ein eigener Step im
parallel-Block der default-Pipeline:
definitions:
steps:
- step: &lenzebusinesscheck
image: lenzebusiness/pipeline-php:8.2
name: LENZ eBusiness internal checks.
script:
- composer require --dev lenzebusiness/shopware-extension-check "dev-main" shopware/storefront "6.7.*"
- vendor/bin/shopware-extension-check .
pipelines:
default:
- parallel:
steps:
- step: *lenzebusinesscheck
# ... weitere Checks
- step: *shopware-plugin-build
shopware/storefrontgehört mit in diecomposer require-Zeile. Ohne das Paket fehlen die Core-Templates zum Vergleich, undTwigTemplateOverrideüberspringt sich selbst — der Step ist dann grün, ohne die wichtigste Prüfung ausgeführt zu haben. Jeder Bitbucket-Step läuft in einem frischen Container, es hilft also nicht, dass ein anderer Step (etwa PHPStan) das Paket installiert.Die Versionsangabe an die Extension anpassen:
"6.7.*"für eine Extension mit"shopware/core": ">=6.7.0.0 <6.8.0.0". Alternativ den Pfad überSW_STOREFRONT_VIEWSsetzen, siehe Storefront-Templates finden.
Die Checks laufen in der default-Pipeline, also bei jedem Push. Die
tags-Pipeline baut und veröffentlicht nur — was bereits gebaut wird, war schon
geprüft.
Funktionsweise
ShopwareExtensionCheck::check() läuft das Verzeichnis rekursiv ab und
überspringt .git und vendor. Für jede Datei wird jede Klasse aus
src/Inspection/Check/ instanziiert; schlägt isSupported() an, läuft
inspect(). Befunde werden pro Datei gesammelt und am Ende gruppiert ausgegeben.
Vorab wird aus der composer.json der Extension die minimale Shopware-Version
gelesen (Regex auf "shopware/core": ">=X.Y). Versions-abhängige Prüfungen
laufen nur, wenn dieser Wert passt — aktuell exakt 6.7.
Aufbau:
bin/shopware-extension-check Einsprungpunkt, rendert den Report
src/ShopwareExtensionCheck.php Orchestrator: Walk, Discovery, Sammlung
src/Inspection/ Vertrag: Interface, DataBag, Result, Finding
src/Inspection/Check/ die Prüfungen
src/Cli/ExtensionDirectory.php löst das Verzeichnis-Argument auf
src/Twig/TwigSyntax.php zustandslose Twig-Helfer (statisch)
src/Twig/TwigContext.php Kontext pro Lauf, mit den Caches (Instanz)
tests/ Fixture-Suite
Drei Eigenschaften, die man beim Schreiben einer Prüfung kennen muss:
- Inspections werden einmal pro Lauf instanziiert, nicht pro Datei.
Instanz-Properties sind also erlaubt und statischer Zustand unnötig. Alles, was
pro Extension gecacht wird, liegt im
TwigContext, den derInspectionDataBagmitführt — deshalb sieht ein zweiter Lauf im selben Prozess die Caches des ersten nicht. - Discovery ist gehärtet. Eine Datei in
Check/, die keine instanziierbare Inspection ist (Trait, abstrakte Klasse, Notiz), wird übersprungen statt beinewzu fatalen. Aber: nur Inspections gehören dorthin. - Zwei Schweregrade.
addError()bricht den Build,addWarning()nicht. Ein Error muss sicher sein — ein False Positive stoppt sonst die Pipeline aller Extensions. Eine Warnung ist für Befunde, die von innen nicht entscheidbar sind: ein Partial, das vielleicht das Kundentheme rendert, einignore missing-Include, das absichtlich ins Leere zeigt.
Am Ende steht immer eine Zeile N error(s), M warning(s). — auch bei null
Befunden, damit man in einem Pipeline-Log sieht, dass tatsächlich geprüft wurde.
Befunde tragen eine Zeilennummer, wo eine existiert, und sind pro Datei nach Zeile sortiert:
Error in file: src/Resources/views/storefront/component/address/address-personal.html.twig
-> line 7: Block "component_address_form_salutation_select" does not exist ...
-> line 10: Config key "undeclaredOnLine10" is read but not declared ...
Regeln, die von der Abwesenheit einer Sache handeln (fehlendes
declare(strict_types=1);) oder von einer ganzen Datei (ein Template, das nichts
rendert), melden bewusst keine Zeile statt eine zu erfinden.
Der Checker sammelt nur; gerendert wird im Einsprungpunkt über getReport().
Bibliothekscode schreibt nichts auf stdout — auch die Hinweise des TwigContext
(fehlende Storefront, Tippfehler in der Ignore-Datei) werden gesammelt.
Prüfungen
Storefront-Twig
Alle drei Prüfungen dieser Gruppe gelten nur für Templates unter
src/Resources/views/. Nur die nehmen an der Twig-Theme-Inheritance teil.
Templates unter src/Resources/app/administration/ sind Vue-Komponenten-Templates,
die aus JavaScript importiert werden — auf die trifft nichts davon zu.
TwigTemplateOverride
Findet Twig-Overrides und Includes, die stillschweigend nichts tun. Der wichtigste Check im Tool, weil Twig hier keinerlei Fehler produziert:
| Befund | Ursache |
|---|---|
Block "x" does not exist in the inheritance chain of "y" | Der Blockname existiert in der Vererbungskette des erweiterten Templates nicht. Twig ignoriert die Definition — der Override rendert nie. Typisch nach einem Shopware-Upgrade, in dem Core den Block umbenannt oder entfernt hat. |
sw_extends "x", which does not exist in Shopware core | Das erweiterte Template gibt es nicht mehr. Damit rendert die ganze Datei nie. |
Includes "x", which does not exist | sw_include-Ziel existiert nicht. Das wirft erst auf der Seite, die es tatsächlich rendert — kann also lange unentdeckt bleiben. |
Zusätzlich als Warnung:
| Befund | Ursache |
|---|---|
Includes "x" with "ignore missing" and it resolves nowhere | Kein Fehler, ignore missing ist Absicht. Aber die Meldung nennt die optionalen Integrationen, die in diesem Checkout inaktiv sind — und sie ist der einzige Weg, einen Tippfehler in so einem Pfad zu bemerken, denn Twig rendert dann stillschweigend nichts. |
Wichtige Details:
- Verglichen wird gegen die konkret erweiterte Vererbungskette, nicht global gegen alle Core-Templates. Ein globaler Vergleich erzeugt falsche Negative.
- Vor dem Parsen werden Twig-Kommentare (
{# … #}) und{% verbatim %}-Abschnitte entfernt, Whitespace-Control ({%- … -%}) wird berücksichtigt. Ein auskommentierter oder wörtlich ausgegebener Block ist kein Override. - Nur Blocks auf Verschachtelungstiefe 0 gelten als Override. Blocks innerhalb eines überschriebenen Core-Blocks rendern sehr wohl und werden nicht gemeldet.
- Dynamisch zusammengesetzte Include-Ziele
(
'.../partials/' ~ section ~ '.html.twig') werden übersprungen, weil es keinen einzelnen Pfad zu prüfen gibt. ignore missing-Includes sind nie ein Fehler — das ist der dokumentierte Weg, ein optionales Template einer anderen Extension zu referenzieren. Löst der Pfad nirgends auf, gibt es aber eine Warnung.- Ein fremder Bundle-Namespace (
@KlarnaPayment/...) wird übersprungen — der ist eindeutig eine andere Extension. - Ein
@Storefront/...-Pfad, den Core nicht hat, ist nicht von „andere Extension liefert ihn" unterscheidbar. Der Check schlägt deshalb an; für den zweiten Fall gibt es.twig-check-ignore.
TwigConfigKeyDeclared
Findet config('<Extension>.config.x')-Aufrufe auf Keys, die
src/Resources/config/config.xml nicht deklariert. Ein solcher Aufruf ist null,
also ist jedes {% if %} darüber permanent falsch und das Feature stillschweigend
aus. Passiert typischerweise, wenn ein Key in der config.xml umbenannt wurde,
in den Templates aber nicht.
Nur Keys des eigenen Namespace werden geprüft. Keys von Shopware Core
(core.loginRegistration.showSalutation) oder einer anderen Erweiterung
(SwagPayPal.settings.clientId, KlarnaPayment) sind woanders deklariert und von
hier aus nicht verifizierbar — sie werden per Konstruktion ignoriert, es braucht
dafür keine Ausnahme:
{{ config('core.loginRegistration.showAccountTypeSelection') }} {# ignoriert #}
{{ config('SwagPayPal.settings.clientId') }} {# ignoriert #}
{{ config('MyExtension.config.declaredKey') }} {# geprüft, ok #}
{{ config('MyExtension.config.renamedKey') }} {# geprüft -> Fehler #}
Der eigene Namespace wird aus der composer.json abgeleitet
(extra.shopware-plugin-class-Basename, Fallback: erster autoload.psr-4-Key).
Der Basename ist wichtig und nicht dasselbe wie der PSR-4-Prefix: bei
LenzPlatformCreditManagement ist der Prefix Lenz\CreditManagement, das
Config-Präfix aber LenzPlatformCreditManagement.
Ein Key des eigenen Namespace, den die config.xml absichtlich nicht
deklariert — interner Zustand, der programmatisch geschrieben statt im Admin
konfiguriert wird — wird als config-ok deklariert:
config-ok internalLastSync
config-ok internal*
Nicht als Config-Key gezählt werden <name>-Elemente unterhalb von
<options><option>, das sind Option-Labels.
TwigOrphanTemplate
Findet Standalone-Templates, die offenbar nichts rendert. Ein Template ohne
sw_extends ist nur erreichbar, wenn es irgendwo includiert wird oder wenn es
einen Core-Pfad beschattet und daher von Core gerendert wird. Trifft keins von
beidem zu, ist es meist übrig geblieben — ein Partial, dessen Include entfernt
wurde, oder ein Rest aus einem Refactoring.
Warnung, kein Fehler: ein Partial kann legitim vom Theme des Shops oder von
einer anderen Extension gerendert werden, und das ist von hier aus nicht
erkennbar. Solche Fälle mit orphan-ok in
.twig-check-ignore dauerhaft stummschalten.
Als Referenz zählen:
sw_include/include/embedaus den Templates der Extensionsw_extendsaus den Templates der Extension- Template-Pfade als String in den PHP-Dateien der Extension — Dokument-Vorlagen, Exporte und Mails werden über einen Controller oder eine Twig-Umgebung gerendert, nicht über einen Include
- ein gleichnamiger Core-Pfad (dann rendert Core das Template)
Dynamisch zusammengesetzte Includes werden berücksichtigt: bei
'.../partials/' ~ section ~ '-box.html.twig' gilt nicht das ganze Verzeichnis
als referenziert, sondern nur partials/*-box.html.twig. Sonst würde ein
tatsächlich unbenutztes Geschwister-Template im gleichen Ordner maskiert.
PHP
DeclareStrictPhpCheck
Jede .php-Datei muss declare(strict_types=1); enthalten.
PhpShopware67Deprecations
Nur bei minimaler Shopware-Version 6.7. Meldet:
$qb->execute()->fetchAll()→$qb->executeQuery()->fetchAllAssociative()
Administration
AdminJsShopware67Deprecations
Nur bei 6.7, nur .js unter /Resources/app/administration/:
Shopware.Context.api.currentLanguageId→Shopware.Store.get('context').api.languageIdcontext/setApiLanguageId→Shopware.Store.get('context').setApiLanguageId(...)Shopware.Context→Shopware.Store.get('context')@import '~scss/variables.scss';→@import '~scss/variables';
AdminTwigShopware67Deprecations
Nur bei 6.7, nur .html.twig unter /Resources/app/administration/. Prüft
<mt-button>-Tags auf router-link / routerLink / routerlink und verlangt
stattdessen @click="$router.push({ name: '...' })".
config.xml
ConfigXmlValue
Verlangt <defaultValue> statt <value> in src/Resources/config/config.xml.
<value> wird von Shopware nicht als Standardwert übernommen, die Option bleibt
also leer.
CHANGELOG
ChangelogStartNext
CHANGELOG*.md muss mit # NEXT beginnen.
ChangelogNotAllowedCharacters
Typografische Anführungszeichen „, “, ” sind in CHANGELOG*.md nicht
erlaubt.
Assets
SvgActiveContentCheck
Meldet aktive Inhalte in .svg-Dateien, die Shopware nicht akzeptiert:
<script>, Event-Handler-Attribute (onload=, onclick= …), javascript:-URIs,
<foreignObject>, <!DOCTYPE>, <!ENTITY>, Processing Instructions außer der
XML-Deklaration, sowie externe oder data:-href-Referenzen (erlaubt sind nur
lokale Fragment-Referenzen #id).
Storefront-Templates finden
TwigTemplateOverride braucht die Core-Templates zum Vergleich. Gesucht wird in
dieser Reihenfolge:
$SW_STOREFRONT_VIEWS<extension>/vendor/shopware/storefront/Resources/views- drei bzw. vier Ebenen über der Extension (Extension liegt in
custom/plugins/<name>einer Installation) /opt/shopware/vendor/shopware/storefront/Resources/views/shopware/vendor/shopware/storefront/Resources/views
Wird nichts gefunden, erscheint eine sichtbare Meldung und die Twig-Prüfungen werden übersprungen — der Build schlägt nicht fehl. Ein stiller Durchlauf wäre schlimmer als ein Fehlschlag, deshalb die Meldung.
Drei Wege, die Templates bereitzustellen:
# a) im Pipeline-Step mitinstallieren - der empfohlene Weg, Nr. 2 der Suchliste
composer require --dev lenzebusiness/shopware-extension-check "dev-main" shopware/storefront "6.7.*"
# b) Pfad explizit setzen, z. B. wenn eine Shopware-Installation vorliegt
SW_STOREFRONT_VIEWS=/path/to/vendor/shopware/storefront/Resources/views \
vendor/bin/shopware-extension-check .
// c) dauerhaft in der composer.json der Extension
"require-dev": {
"shopware/storefront": ">=6.7.0.0 <6.8.0.0"
}
Variante a) hält die Extension-composer.json frei und steht direkt neben dem
Aufruf, ist also beim Lesen der Pipeline nicht zu übersehen. Variante c) wirkt
auch lokal, ohne dass man an den Pfad denken muss.
Wer die Extension innerhalb einer Shopware-Installation prüft
(custom/plugins/<name>), braucht nichts davon — Punkt 3 der Suchliste greift.
.twig-check-ignore
Manches lässt sich lokal nicht verifizieren. Der Hauptfall: Templates, die eine
andere Extension liefert. Die werden unter dem @Storefront-Namespace
adressiert wie Core-Templates — „von Core entfernt" und „von anderer Extension
geliefert" sind daher nicht unterscheidbar. Der Check schlägt konservativ an; die
Ausnahme erklärst du in dieser Datei.
Die Datei liegt im Wurzelverzeichnis der geprüften Extension, direkt neben
composer.json:
MyExtension/
├── composer.json
├── .twig-check-ignore
└── src/
Format
Eine Regel pro Zeile: Direktive, Whitespace, Pattern. # beginnt einen
Kommentar. Patterns sind fnmatch-Globs, in denen * auch / matcht.
| Direktive | Pattern bezieht sich auf | Wirkung |
|---|---|---|
external | namespacetes Template (@Storefront/...) | Pfad wird von einer anderen Extension geliefert. Kein Befund bei sw_extends oder sw_include darauf; bei sw_extends werden zusätzlich die Blocks nicht geprüft, weil der Parent nicht lesbar ist. |
ignore | Pfad relativ zu src/Resources/views/ | Template komplett von allen Twig-Prüfungen ausnehmen. |
ignore | <pfad>:<blockname> | Nur diesen einen Block ausnehmen. |
orphan-ok | Pfad relativ zu src/Resources/views/ | Standalone-Template, das von außerhalb der Extension gerendert wird — vom Theme des Shops oder von einer anderen Extension. Schaltet die Warnung von TwigOrphanTemplate aus. |
config-ok | Config-Key-Name (ohne Namespace-Präfix) | Key des eigenen Namespace, den die config.xml absichtlich nicht deklariert — interner Zustand statt Admin-Option. Nur für den eigenen Namespace nötig; Core- und Fremd-Keys werden ohnehin nicht geprüft. |
Beispiel
# Exceptions for shopware-extension-check
#
# Jeder Eintrag braucht eine Begruendung. Eine undokumentierte Ausnahme ist der
# Weg, auf dem sich der naechste stille Fehler versteckt - wer nicht sagen kann,
# warum ein Pfad nicht pruefbar ist, hat wahrscheinlich keinen Sonderfall,
# sondern einen Bug.
# Die Klarna-Box auf der Confirm-Page. KlarnaPayment liefert diese Templates
# unter dem @Storefront-Namespace, sie fehlen also ohne diese Extension - genau
# deshalb benutzen die Includes `ignore missing`.
external @Storefront/storefront/klarna/*
# Wird vom Theme des Kunden gerendert, nicht von dieser Extension.
ignore storefront/component/custom/legacy-teaser.html.twig
# Der Block existiert nur im Theme XY, das dieses Template weiterreicht.
ignore storefront/page/product-detail/index.html.twig:xy_special_slot
# Cursor des naechtlichen Imports. Wird vom Command geschrieben, nicht im Admin
# gepflegt, hat also absichtlich keinen Eintrag in der config.xml.
config-ok importCursor
Hinweise
- Eine unbekannte Direktive wird gemeldet, nicht ignoriert. Ein Tippfehler soll keine Prüfung stillschweigend abschalten.
- Für einen fremden Bundle-Namespace (
@KlarnaPayment/...) braucht es keine Regel — der wird ohnehin übersprungen.externalist nur für Pfade unter@Storefrontnötig. - Für ein optionales Template ist
{% sw_include ... ignore missing %}die bessere Lösung als eineexternal-Regel: das ist zur Laufzeit sicher und dokumentiert die Absicht direkt im Template. - Ohne die Datei verhält sich alles wie ohne Ausnahmen; sie ist optional.
Eine neue Prüfung schreiben
Neue Klasse in src/Inspection/Check/:
<?php
namespace LenzEbusiness\ShopwareExtensionCheck\Inspection\Check;
use LenzEbusiness\ShopwareExtensionCheck\Inspection\AbstractInspection;
use LenzEbusiness\ShopwareExtensionCheck\Inspection\InspectionDataBag;
use LenzEbusiness\ShopwareExtensionCheck\Inspection\InspectionResult;
class MyCheck extends AbstractInspection
{
public function isSupported(InspectionDataBag $inspectionDataBag): bool
{
return str_ends_with($inspectionDataBag->getFileName(), '.php');
}
public function inspect(InspectionDataBag $inspectionDataBag): InspectionResult
{
$inspectionResult = new InspectionResult();
$content = $this->getFileContent($inspectionDataBag->getFilePath());
if (str_contains($content, 'foo')) {
$inspectionResult->addError('Do not use foo, use bar instead.');
}
if (str_contains($content, 'baz')) {
// Does not fail the build.
$inspectionResult->addWarning('baz is discouraged, consider bar.');
}
return $inspectionResult;
}
}
Es braucht keine Registrierung — der Ordner wird zur Laufzeit gescannt.
Regeln:
- Nur Inspections in
src/Inspection/Check/. Der Scanner instanziiert jede Datei in diesem Ordner als Inspection. Hilfsklassen gehören woanders hin, z. B. nachsrc/Twig/(sieheTwigContext). - Nichts auf eine konkrete Extension hartcodieren — Namespaces und Pfade aus
der
composer.jsonder geprüften Extension ableiten. - Schweregrad bewusst wählen.
addError()bricht den Build und muss sicher sein. Ist ein Befund von innen nicht entscheidbar — weil das Theme des Shops oder eine andere Extension die Antwort kennt — dannaddWarning(). - Fehlermeldungen sagen, was zu tun ist, nicht nur, was falsch ist. Sie landen in einer Pipeline-Ausgabe, ohne den Code daneben.
- Negativ testen. Eine Prüfung, die nie anschlägt, ist schlimmer als keine — sie erzeugt Vertrauen, das sie nicht verdient. Also gegen eine absichtlich kaputte Datei laufen lassen und den Befund sehen.
Für teure Schritte (Verzeichnisse ablaufen, XML parsen, Core-Templates lesen)
static-Caches benutzen, da pro Datei neu instanziiert wird.
Tests
php tests/run.php # alle Fixtures und Invarianten
php tests/run.php dead-block # nur eine Fixture
php tests/run.php directory-argument # nur eine Invariante
Ein Name, der weder Fixture noch Invariante ist, bricht mit Exit 1 ab. Ein gefilterter Lauf, der nichts getroffen hat, hat nichts geprüft und darf nicht grün aussehen.
Jede Fixture unter tests/Fixtures/<name>/ ist eine minimale Extension, die genau
einen Sachverhalt verkörpert. Die Erwartung liegt außerhalb der Fixture in
tests/expected/<name>.php — sonst würde DeclareStrictPhpCheck auf dem
Test-Gerüst selbst anschlagen. Sie prüft strukturierte Daten (Anzahl Errors und
Warnungen, betroffene Dateien, Stichworte) statt wörtlicher Meldungstexte; sonst
invalidiert jede Umformulierung alle Erwartungen.
Als Core-Templates dient der Stub in tests/Fixtures/_storefront/ und nicht das
echte shopware/storefront. Die Suite soll beantworten „verhält sich der Checker
richtig", nicht „wie sieht Shopware 6.7.11 gerade aus" — mit den echten Templates
würde sie bei jedem Shopware-Update aus dem falschen Grund rot. Ob Core einen Block
tatsächlich umbenannt hat, beantwortet der Lauf gegen echte Extensions.
Warum es Paare gibt
Die Fixtures kommen in zwei Sorten, und die zweite ist die wichtigere:
dead-block,missing-include,undeclared-config-key… — muss gemeldet werdenvalid-nested-block,valid-whitespace-control,valid-verbatim… — darf nicht gemeldet werden
Eine valid-*-Fixture allein reicht aber nicht: sie erwartet „nichts gemeldet" und
besteht damit auch dann, wenn die Prüfung überhaupt nicht läuft. Genau das trat
auf — extendedTemplate() erkannte {%- sw_extends -%} nicht, die Override-Prüfung
wurde stumm übersprungen, und valid-whitespace-control blieb grün.
Darum hat jede Parsing-Variante ein Gegenstück detects-*, das dieselbe Syntax
benutzt und trotzdem einen echten Fehler enthält. Nur beide zusammen decken die
Variante ab.
Invarianten ohne Fixture
Vier Eigenschaften lassen sich nicht als Fixture ausdrücken, weil sie das Verhalten des Checkers selbst betreffen und nicht seinen Befund. Der Runner prüft sie zusätzlich:
discovery-guard— eine ungültige Datei inCheck/(Trait, abstrakte Klasse, Datei ohne Klasse) wird übersprungen statt zu fatalen. Die Testdaten dafür liegen intests/Discovery/.repeated-run-does-not-accumulate— zweimalcheck()auf derselben Instanz meldet nicht doppelt.two-extensions-stay-isolated— zwei Extensions im selben Prozess sehen die Caches der anderen nicht.directory-argument— das Verzeichnis-Argument des Einsprungpunkts, absolut wie relativ. Nicht als Fixture abbildbar, weilbin/einen Composer-Autoloader braucht, den es im Repo ohne Install nicht gibt; getestet wird deshalbExtensionDirectory::resolve().
Eine neue Prüfung testen
- Fixture-Verzeichnis mit
composer.json,src/Resources/config/config.xmlund den Dateien unter Test anlegen. tests/expected/<name>.phpschreiben.- Den Fix testweise zurücknehmen und prüfen, dass die Fixture rot wird. Ein Test, der nie rot war, ist nichts wert. Alle Prüfungen hier sind so verifiziert — und in drei Fällen war die Fixture dabei aus dem falschen Grund grün.
Bekannte Einschränkungen
- Keine Zeilennummern. Befunde werden pro Datei gemeldet, nicht pro Zeile.
- Twig-Prüfungen brauchen die Core-Templates. Ohne sie überspringen sie sich
mit einer Meldung, siehe
Storefront-Templates finden. In der Pipeline
gehört
shopware/storefrontdeshalb in diecomposer require-Zeile. - Nur der
@Storefront-Namespace wird verifiziert. Erweitert eine Extension ein Template einer anderen Extension über deren eigenen Namespace (@FooPlugin/...), wird nichts geprüft — die Templates liegen nicht vor. - Config-Keys werden nur in Twig geprüft. Ein
SystemConfigService::get()auf einen nicht deklarierten Key in PHP fällt nicht auf, obwohl es dieselbe stille Wirkung hat (null). Eine Erweiterung darauf wäre unkritisch: die Beschränkung auf den eigenen Namespace gilt dort genauso. - Twig wird per Regex gelesen, nicht geparst. Kommentare,
{% verbatim %}und Whitespace-Control sind behandelt; ein{% block %}innerhalb eines String-Literals wäre es nicht. In der Praxis nicht aufgetreten. - Kein JSON-Output. Der Report ist für Menschen. Die Befunde liegen aber
strukturiert vor (
getErrors(),getWarnings(),Finding::$line), eine maschinenlesbare Ausgabe wäre also eine kleine Ergänzung.