Markus Michalski FAQ

Newsletter Management: Technische Details

Architektur, Plugin-Struktur, Tabellen und Entities, Migrationen, Entwurfsentscheidungen, Tests und Entwicklungs-Workflow des Sylius-Newsletter-Management-Plugins

English Version

Zurück zur Übersicht

Newsletter Management: Technische Details

Diese Dokumentation bezieht sich immer auf die aktuellste veröffentlichte Version.

Diese Seite beschreibt Aufbau und Interna des Plugins für Integratoren und Entwickler: den Ablauf von Anmeldung und Versand, die Struktur, die Tabellen und die wichtigsten Entwurfsentscheidungen.

Architektur

Anmeldungen laufen über genau einen Einstiegspunkt, den NewsletterSubscriptionManager. Egal ob Storefront-Formular, Registrierungs-Checkbox oder Shop API: Alle rufen dieselben Methoden zum Anmelden, Bestätigen, Ändern und Abmelden auf. Der Footer-Teaser ruft den Manager nicht selbst auf, er übergibt per GET an das Formular auf /newsletter. Es gibt keine zweite Geschäftslogik für die API.

graph TD
    A["Storefront: Formular, Registrierung"] --> M["NewsletterSubscriptionManager"]
    B["Shop API: Processors und Provider"] --> M
    M --> E{"Event PRE_SUBSCRIBE"}
    E -->|"abgelehnt"| R["Abgelehnt: Flash oder 422"]
    E -->|"frei"| P["Abonnement speichern"]
    P --> ML["NewsletterMailer: Bestätigung, Willkommen, Bereits angemeldet"]
    P --> S["Synchronisation des Customer-Newsletter-Flags"]
    P --> T["Tracking: Einwilligung und Löschung"]

Der Versand läuft getrennt davon über Cron:

graph LR
    C["Cron: mmd:newsletter:send"] --> SV["NewsletterSendingService"]
    SV --> D["Zustellungen reservieren"]
    D --> MS["NewsletterMailSender"]
    MS --> RE["NewsletterRenderer"]
    RE --> TH["Theme des Channels"]
    RE --> LT["NewsletterLinkTracker"]
    MS --> TR["Symfony Mailer"]
    ADM["Admin: Senden, Planen, Abbrechen"] --> SV

Plugin-Struktur

sylius-newsletter-management/
├── assets/            Admin- und Shop-Assets
├── config/
│   ├── config.yaml
│   ├── mailer.yaml    E-Mail-Codes der drei Abonnenten-Mails
│   ├── services.php   alle Services in einer Datei
│   ├── grids/         Admin-Grids
│   ├── routes/        admin.yaml, shop.yaml
│   └── twig_hooks/    admin.yaml, shop.yaml
├── src/
│   ├── Api/           Shop-API: Processors, Provider, Query-Extension
│   ├── Command/       setup, send, subscription:purge, tracking:purge
│   ├── Controller/    Storefront, Dashboard, Vorschau, Versand, Tracking, Export
│   ├── DependencyInjection/
│   ├── Entity/        Entities, Interfaces und Enums
│   ├── Event/         PRE_SUBSCRIBE
│   ├── EventListener/ Customer-Checkbox, Löschschutz
│   ├── Factory/
│   ├── Form/          Form-Typen und Modelle
│   ├── Mailer/        Abonnenten-Mails
│   ├── Manager/       NewsletterSubscriptionManager
│   ├── Menu/          Admin-Menü
│   ├── Migrations/    11 Doctrine-Migrationen
│   ├── Newsletter/    Platzhalter, Renderer, Textgenerator, Theme, URLs
│   ├── Repository/
│   ├── Sender/        Newsletter-Versand pro Empfänger
│   ├── Sending/       Versand-Orchestrierung
│   ├── Settings/      Einstellungen pro Channel, Datenschutz-Link, Einwilligungstext
│   ├── Statistics/    Zahlen für Dashboard und Newsletter-Detail
│   ├── Sync/          Abgleich mit dem Customer-Newsletter-Flag
│   ├── Tracking/      Link-Tracker, Recorder, Signatur
│   └── Twig/          Twig-Extension
├── templates/         admin, emails, shop
├── tests/             Unit, Integration, Functional, TestApplication
└── translations/      messages, flashes, validators (de, en)

Entities und Tabellen

Alle Tabellen tragen das Präfix mmd_sylius_newsletter_management_.

Entity Tabelle Inhalt
NewsletterSubscription ..._subscription Ein Abonnement pro Adresse und Channel (eindeutig). Status, Quelle, Tokens, Zeitstempel, Einwilligung zum Tracking, Channel und Customer (optional).
NewsletterCategory ..._category Kategorie mit Code, Position und Aktiv-Schalter
NewsletterCategoryTranslation ..._category_translation Übersetzbarer Name und Beschreibung
NewsletterChannelConfiguration ..._channel_configuration Einstellungen pro Channel (genau eine Zeile pro Channel)
Newsletter ..._newsletter Betreff, Preheader, HTML, Text, Status, Zeitplan, Empfängerzahl
NewsletterDelivery ..._delivery Versandprotokoll: eine Zeile pro Newsletter und Adresse (eindeutig)
NewsletterLink ..._link Verfolgte Links eines Newsletters: Code und URL
NewsletterTrackingHit ..._tracking_hit Anonymer Zähler pro Newsletter, Tag und Ziel
NewsletterTrackingEvent ..._tracking_event Einzelnes Ereignis (Öffnung oder Klick) eines zustimmenden Abonnenten

Dazu kommen drei Verknüpfungstabellen: ..._subscription_category (Kategorien eines Abonnements), ..._newsletter_category (Zielgruppe eines Newsletters) und ..._category_channel (Channels, in denen eine Kategorie angeboten wird; leer = alle).

erDiagram
    SUBSCRIPTION }o--o{ CATEGORY : "waehlt"
    NEWSLETTER }o--o{ CATEGORY : "Zielgruppe"
    CATEGORY ||--o{ CATEGORY_TRANSLATION : "uebersetzt"
    NEWSLETTER ||--o{ DELIVERY : "Versandprotokoll"
    SUBSCRIPTION |o--o{ DELIVERY : "empfaengt"
    NEWSLETTER ||--o{ LINK : "verfolgt"
    NEWSLETTER ||--o{ TRACKING_HIT : "zaehlt"
    NEWSLETTER ||--o{ TRACKING_EVENT : "protokolliert"
    SUBSCRIPTION ||--o{ TRACKING_EVENT : "loest aus"

Enums (als PHP-Backed-Enums, keine eigenen Tabellen):

Enum Werte
NewsletterStatus draft, ready, scheduled, sending, sent, cancelled
NewsletterSubscriptionStatus pending, confirmed, unsubscribed
NewsletterSubscriptionSource storefront, api, registration, admin
NewsletterDeliveryStatus pending, sending, sent, failed, skipped
NewsletterTrackingMode off, anonymous, personal
NewsletterTrackingEventType open, click

Migrationen

Das Plugin bringt 11 Migrationen mit. Eingespielt werden sie mit bin/console mmd:newsletter-management:setup (siehe Installation).

Nr. Zweck
1 Tabellen für Abonnements, Kategorien (mit Übersetzung), Channel-Einstellungen und die Kategorie-Zuordnung
2 Vor- und Nachname am Abonnement
3 Datenschutzseite pro Channel
4 last_notified_at am Abonnement (Mail-Drosselung)
5 Newsletter-Tabelle samt Kategorie-Zuordnung
6 Channel-Beschränkung der Kategorien
7 Versand: Zeitplan- und Fortschrittsspalten, Versandprotokoll, Mailer-Transport pro Channel
8 Anonymes Tracking: Modus und Aufbewahrung, Link-Tabelle, Tageszähler
9 Personenbezogenes Tracking: Einwilligung, Ereignistabelle, Einwilligungstext und Aufbewahrung pro Channel
10 Aufbewahrung abgemeldeter Abonnements pro Channel
11 Aufbewahrung unbestätigter Anmeldungen pro Channel

Entwurfsentscheidungen

Tests

Verzeichnis Inhalt
tests/Unit/ Unit-Tests: DependencyInjection, Entity, EventListener, Manager, Newsletter, Settings, Sync, Twig
tests/Integration/ Integrationstest des Setup-Befehls (Command)
tests/Functional/ Funktionale Tests, z. B. Anmeldefluss, Shop API, Versand, Tracking, Statistik, Theme, Aufräumbefehle
tests/TestApplication/ Sylius-Testanwendung (config, src, templates)

Entwicklung

Entwickelt wird ausschließlich im Container (PHP 8.3, MySQL 8.4, nginx). Ein lokales PHP ist nicht vorgesehen.

Befehl Zweck
make init Compose-Override anlegen, composer install, Frontend der Testanwendung bauen, Container starten
make database-init Datenbank anlegen und Migrationen ausführen
make load-fixtures Sylius-Fixtures laden (die funktionalen Tests brauchen sie)
make phpunit Unit- und funktionale Tests
make phpstan Statische Analyse
make ecs Code-Style
make up, make down, make clean Container starten, stoppen, samt Volumes entfernen
make php-shell Shell im PHP-Container

Diese Befehle gehören zur Entwicklung des Plugins selbst. Für den Betrieb in deinem Shop brauchst du sie nicht.