Support Form: Technische Details
Support Form für Sylius - Ablauf einer Anfrage als Diagramm, Dual-Mode im Überblick, Plugin-Struktur, die sechs Tabellen, Migrationen und Details der Admin-Oberfläche
Support Form: Technische Details
Live Demo: Teste dieses und weitere Plugins live — ohne Installation, ohne Risiko: demo.markus-michalski.net
Ablauf einer Anfrage
Storefront und Shop API laufen in dieselbe Verarbeitung. Dort wird zuerst das Event ausgelöst, und nur wenn kein Listener ablehnt, geht die Anfrage weiter.
graph TD
A["Kunde: POST /support"] --> B{"Formular gültig?"}
H["Client: POST /shop/support-requests"] --> I["Entity-Validierung"]
I --> J["Betreff gegen Auswahlliste prüfen"]
J --> K["Antworten mit Formularregeln prüfen"]
B -->|Ja| M["Antworten und E-Mail-Adresse ableiten"]
K --> M
M --> N["Betreff-Code in Bezeichnung auflösen"]
N --> O["Event PRE_PERSIST"]
O --> Q{"Von Listener abgelehnt?"}
Q -->|Ja| U["Storefront: Fehlermeldung, API: 422"]
Q -->|Nein| R["Anfrage speichern"]
R --> S["Mail an den Betreiber"]
R --> T["Bestätigung an den Kunden"]
S --> V["Storefront: Erfolgsmeldung, API: 201"]
T --> V
Die Verarbeitung (SupportRequestSubmissionHandler) ist der einzige Ort, an dem gespeichert und benachrichtigt wird. Controller und API-Prozessor rufen sie nur auf. Jede der beiden Mails hat einen eigenen Fehlerschutz: Scheitert eine, ist die Anfrage trotzdem gespeichert, und die andere geht raus. Protokolliert werden nur Exception-Klasse und Code, nie die Meldung, weil sie personenbezogene Daten enthalten kann.
Dual-Mode im Überblick
| Fähigkeit | Storefront | Shop API |
|---|---|---|
| Anfrage absenden | GET/POST /support |
POST /shop/support-requests |
| Zusatzfelder | Im Formular als field_<ID> |
GET /shop/support-form-fields |
| Antworten | Eingabefelder field_<ID> |
Objekt answers, Schlüssel ist die ID des Feldes |
| Betreff-Auswahl | Feld „Betreff“ im Formular | GET /shop/support-form-subject-choices |
| Bestätigung an den Kunden | Wenn die Anfrage eine Adresse hat | Wenn answers eine beantwortete E-Mail enthält |
| Anfragen ansehen | /admin/support-requests |
GET /admin/support-requests |
Plugin-Struktur
src/
├── Api/ # Shop-API-Prozessor und -Provider, Prüfung der Antworten, Betreff-Auswahl als DTO
├── Command/ # SetupCommand, PurgeSupportRequestsCommand
├── Controller/ # SupportRequestController (Storefront)
├── DependencyInjection/ # Bundle-Erweiterung (leere Konfiguration)
├── Entity/ # SupportRequest, SupportFormField (+ Übersetzung), SupportFormChannelConfiguration, Enums
├── Event/ # SupportRequestEvents, SupportRequestPrePersistEvent
├── Factory/ # SupportFormFieldFactory
├── Form/Type/ # SupportRequestType und die Admin-Formulare
├── Handler/ # SupportRequestSubmissionHandler
├── Mailer/ # SupportRequestMailer, Emails
├── Menu/ # Admin-Sidebar-Eintrag in der Gruppe „MMKreativ Plugins“
├── Migrations/ # Drei Doctrine-Migrationen
├── Repository/ # Repositories der drei Ressourcen
├── Resolver/ # Betreff-Auswahl, Antwort-Sammler, Datenschutz-Link
└── Twig/ # PluginVersionExtension
config/
├── grids/ # Drei Admin-Grids
├── routes/ # admin.yaml, shop.yaml
├── twig_hooks/ # admin.yaml, shop.yaml
└── mailer.yaml # Zwei E-Mail-Templates
templates/
├── admin/ # Titelzeilen und Formulare, Detailansicht
├── emails/ # Benachrichtigung und Bestätigung
└── shop/ # Formular und Footer-Link
translations/ # messages, validators, flashes in de und en
Tabellen und Migrationen
Das Plugin legt sechs Tabellen an.
graph LR
A["support_request"] -->|"channel_id, SET NULL"| C["sylius_channel"]
B["support_form_channel_configuration"] -->|"channel_id, CASCADE"| C
B --- D["configuration_product"]
B --- E["configuration_taxon"]
F["support_form_field"] --- G["support_form_field_translation"]
| Tabelle | Inhalt |
|---|---|
mmd_sylius_support_form_support_request |
Eingegangene Anfragen: created_at, email, subject, consent, channel_id, field_values |
mmd_sylius_support_form_field |
Zusatzfelder: field_type, required, position, Grenzwerte, select_options |
mmd_sylius_support_form_field_translation |
Bezeichnung und Platzhalter je Sprache |
mmd_sylius_support_form_channel_configuration |
Eine Zeile pro Channel: subject_mode, recipient_email, privacy_policy_page |
mmd_sylius_support_form_channel_configuration_product |
Zugeordnete Produkte |
mmd_sylius_support_form_channel_configuration_taxon |
Zugeordnete Kategorien |
Die Antworten auf die Zusatzfelder liegen als JSON-Liste aus label und value in der Spalte field_values der Anfrage und nicht in einer eigenen Tabelle. Das Plugin liest sie nie einzeln, sondern immer gemeinsam mit der Anfrage. Weil jede Antwort ihre Bezeichnung mitbringt, bleibt sie lesbar, wenn du das Feld später änderst oder löschst.
Die Spalte channel_id einer Anfrage wird beim Löschen eines Channels auf NULL gesetzt, die Konfiguration des Channels dagegen mit gelöscht.
| Migration | Änderung |
|---|---|
Version20260928095114 |
Legt alle sechs Tabellen an |
Version20260929120000 |
Ergänzt recipient_email an der Channel-Konfiguration |
Version20260929140000 |
Ergänzt privacy_policy_page an der Channel-Konfiguration |
Admin-Details
- Das Plugin liest keine Bundle-Konfiguration, die Konfigurationsklasse ist leer.
- Grids und Twig Hooks hängt das Plugin selbst in die Anwendungskonfiguration ein, ein eigener Import ist nicht nötig.
- Das Formular für Channel-Konfigurationen nutzt die Autocomplete-Felder von Sylius für Produkte und Kategorien. Das einfache Auswahlfeld würde in dieser Sylius-Version keine funktionierende Auswahl liefern.
- Die Titelzeile im Admin zeigt die installierte Plugin-Version (Twig-Funktion
support_form_plugin_version(), liestComposer\InstalledVersions). Bei einem getaggten Release ist das die Versionsnummer, bei einer lokalen Pfad-Installationdev-mainplus die ersten Zeichen des Commit-Hashes. - Der Menüeintrag liegt in der Gruppe „MMKreativ Plugins“. Die Gruppe legt jedes Plugin selbst an, falls sie fehlt. Mehrere MMKreativ-Plugins teilen sich deshalb einen Sidebar-Eintrag.