Markus Michalski FAQ

Sylius SEO Suite Pro: Technik

Technik von Sylius SEO Suite Pro: SeoData-Pipeline als Diagramm, acht Tabellen mit ER-Diagramm, Migrationen, Plugin-Struktur, Request-Lebenszyklus, Namenskonventionen und Tests.

English Version

Zurück zur Übersicht

Sylius SEO Suite Pro: Technik

Diese Seite beschreibt den Aufbau des Plugins für Integratoren: den Datenfluss einer Anfrage, die Datenbanktabellen, die Verzeichnisstruktur und die Namenskonventionen. Erweiterungspunkte stehen unter Erweiterbarkeit.

Architektur: die SeoData-Pipeline

Storefront und Shop API holen ihre Daten aus derselben Quelle, dem SeoDataProviderInterface. Dadurch können beide Frontends nicht auseinanderlaufen. Das Ergebnis ist ein unveränderliches SeoData-Objekt mit Meta-Daten, Open Graph, Twitter Card, strukturierten Daten und hreflang-Alternativen.

graph TD
    REQ["Storefront-Request"] --> HOOK["Twig Hook sylius_shop.base#metatags"]
    HOOK --> FN["Twig-Funktion mmd_seo_suite_pro_seo"]
    FN --> CTX["RequestSubjectResolver: Produkt, Kategorie oder Startseite"]
    CTX --> PROV["SeoDataProviderInterface"]
    API["API Platform: GET /shop/seo/products/code und /shop/seo/taxons/code"] --> APIP["SeoResourceProvider"]
    APIP --> PROV
    PROV --> META["SubjectMetaDataResolver: Meta-Titel, Beschreibung, Canonical, Robots"]
    META --> TPL["SEO-Template-Renderer und Platzhalter"]
    META --> FACET["FacetRobotsPolicy"]
    PROV --> SCHEMA["StructuredDataBuilder: Schema-Provider und Enricher"]
    PROV --> SOCIAL["SocialTagsFactory und OgImageCardUrlResolver"]
    PROV --> HREF["HreflangAlternatesBuilder"]
    META --> DATA["SeoData"]
    SCHEMA --> DATA
    SOCIAL --> DATA
    HREF --> DATA
    DATA --> TWIG["Template shop/metatags.html.twig"]
    DATA --> RES["API-Ressource Seo"]
    TWIG --> TITLE["TitleListener ersetzt title bei kernel.response"]

Die Schritte im Einzelnen:

Tabellen und Datenmodell

Das Plugin legt neun Tabellen an. Alle tragen das Präfix mmd_sylius_seo_suite_pro_, und keine hat einen Fremdschlüssel zu Sylius-Core-Tabellen. Die Bindung an einen Channel ist rein logisch über die Spalte channel_code.

erDiagram
    SYLIUS_CHANNEL ||--o| CHANNEL_SETTINGS : channel_code
    SYLIUS_CHANNEL ||--o{ SEO_TEMPLATE : channel_code
    SYLIUS_CHANNEL ||--o| HREFLANG_SETTINGS : channel_code
    SYLIUS_CHANNEL ||--o| SCHEMA_SETTINGS : channel_code
    SYLIUS_CHANNEL ||--o| OG_IMAGE_SETTINGS : channel_code
    SYLIUS_CHANNEL ||--o{ REDIRECT : channel_code
    SYLIUS_CHANNEL ||--o{ NOT_FOUND_LOG : channel_code
    SYLIUS_CHANNEL ||--o{ AUDIT_RUN : channel_code
    AUDIT_RUN ||--o{ AUDIT_ISSUE : run_id

Das Diagramm zeigt nur logische Beziehungen. Weder zwischen Plugin und Sylius noch zwischen Audit-Lauf und Befund gibt es Datenbank-Fremdschlüssel, die Zuordnung läuft über channel_code beziehungsweise run_id. Bei einem Redirect ist channel_code optional (leer bedeutet alle Channels).

Entity Tabelle Zweck
ChannelSettings mmd_sylius_seo_suite_pro_channel_settings Einstellungen pro Channel: robots.txt-Inhalt, Facet-Robots, Social Tags, Open-Graph- und Twitter-Angaben
SeoTemplate mmd_sylius_seo_suite_pro_template Titel- und Beschreibungs-Templates je Channel, Sprache (leer = alle) und Typ
HreflangSettings mmd_sylius_seo_suite_pro_hreflang_settings hreflang je Channel: Aktivierung, Gruppe, x-default-Sprache
SchemaSettings mmd_sylius_seo_suite_pro_schema_settings Attribut-Zuordnung für GTIN, MPN, Marke und zusätzliche Eigenschaften im Product-Knoten
OgImageSettings mmd_sylius_seo_suite_pro_og_image_settings Gestaltung und Schalter der generierten Social-Karten je Channel
Redirect mmd_sylius_seo_suite_pro_redirect Weiterleitungen (manuell, automatisch, Import) mit Trefferzähler
NotFoundLog mmd_sylius_seo_suite_pro_not_found_log Protokoll der 404-Pfade ohne Redirect
AuditRun mmd_sylius_seo_suite_pro_audit_run Ein Audit-Lauf je Channel mit Status, Heartbeat und Sperre (intern, per SQL)
AuditIssue mmd_sylius_seo_suite_pro_audit_issue Einzelner Befund eines Audit-Laufs

Die Entities (und ihre Interfaces) liegen unter src/Entity. Die Ressourcen sind bei Sylius mit dem Alias-Präfix mmd_sylius_seo_suite_pro_plugin registriert.

Migrationen

Es gibt acht Migrationen in src/Migrations, eine je Funktionsblock (Channel-Einstellungen, Social-Spalten der Channel-Einstellungen, Templates, Redirects mit 404-Log, hreflang, Schema, Audit, OG-Bilder). Sie sind ausschließlich für MySQL 8 und MariaDB geschrieben: Auf jeder anderen Plattform überspringt sich jede Migration selbst (skipIf) und wird als ausgeführt vermerkt, die Tabellen entstehen dann nicht.

Die Pfadspalten von Redirect (source, source_key, target) und NotFoundLog (path, path_key) verwenden die Kollation utf8mb4_bin. Der Vergleich von Redirect-Quellen läuft über den kleingeschriebenen source_key, so dass er bei Groß- und Kleinschreibung nicht unterscheidet, während der Originalpfad exakt erhalten bleibt. Die Sperre des Audits beruht auf dem eindeutigen lock_key, der nach einem Lauf auf NULL gesetzt wird.

Ausgeführt werden die Migrationen mit bin/console mmd:seo-suite-pro:setup. Der Befehl führt nur die offenen Migrationen dieses Plugins aus, nie die des Hosts, und verlangt, dass die Sylius-Core-Migrationen vorher durch sind. Doctrines Tabelle doctrine_migration_versions ist die einzige Quelle der Wahrheit. Siehe Installation.

Struktur des Plugins

sylius-seo-suite-pro/
├── src/
│   ├── Api/                 API-Platform-Ressource Seo und State Provider
│   ├── Audit/               Audit-Lauf, Store, Dashboard und die Checks (Check/)
│   ├── Command/             Konsolenbefehle (setup, audit, og-image, redirects)
│   ├── Controller/          /robots.txt, Karten-Route /seo/og/... und Admin-Controller (Admin/)
│   ├── DependencyInjection/ Konfigurationsbaum und Extension des Bundles
│   ├── Doctrine/            Listener für automatische Redirects bei Slug-Änderung
│   ├── Entity/              Doctrine-Entities und ihre Interfaces
│   ├── EventListener/       404-Redirect, Titelersatz, Ressourcen-Listener für Redirects
│   ├── Factory/             vorbelegter Redirect aus dem 404-Log
│   ├── Form/                Admin-Formulare (Type/) und SEO-Felder an den Übersetzungsformularen (Extension/)
│   ├── Grid/                eigene Grid-Filter
│   ├── Hreflang/            hreflang-Provider, Builder, URL-Bau und Einstellungs-Lookup
│   ├── Menu/                Eintrag in der Admin-Sidebar
│   ├── Migrations/          die acht Migrationen
│   ├── Model/               Interfaces und Traits für die Übersetzungsklassen des Shops
│   ├── OgImage/             Planer, Quelle laden, Renderer (GD), Datei-Cache, Prune
│   ├── Redirect/            Pfadregeln, Store, Ketten, 404-Recorder, CSV-Import und -Export
│   ├── Schema/              Schema-Provider (JSON-LD), Enricher, GTIN-Prüfung, Attribut-Lader
│   ├── Seo/                 Meta-Daten, SeoData, Provider, Template-Renderer, Facets, Sitemap-Ausschluss
│   ├── Settings/            Repositories für die Einstellungs-Entities
│   ├── Twig/                Twig-Funktionen und -Filter
│   ├── Validator/           Constraints für Templates, Redirects, hreflang und Schema
│   └── MmdSyliusSeoSuiteProPlugin.php   Bundle-Klasse
├── config/
│   ├── config.yaml          Bundle-Grundkonfiguration
│   ├── services.php         Service-Definitionen und Tags
│   ├── grids/               Admin-Grids
│   ├── routes/              admin.yaml und shop.yaml (vom Host zu importieren)
│   └── twig_hooks/          Hook-Registrierungen für Admin und Shop
├── Resources/fonts/         mitgelieferte Schriften DejaVu Sans und Sans Bold für die OG-Karten
├── templates/
│   ├── admin/               Admin-Templates (Audit, Redirects, Formulare, Grid-Aktionen)
│   └── shop/metatags.html.twig   Head-Template für die Storefront
├── translations/            messages und validators in Deutsch und Englisch
└── tests/                   Unit, Integration, Functional, Behat und TestApplication

Lebenszyklus einer Storefront-Anfrage

Bei jeder Produkt-, Kategorie- und Startseite läuft die SeoData-Pipeline genau einmal. Das Ergebnis liegt als Attribut an der Hauptanfrage (_mmd_seo_suite_pro_data), weitere Aufrufe der Twig-Funktion im selben Request kosten nichts. Der Titel wird erst bei kernel.response in das fertige HTML eingesetzt.

Kosten und Zwischenspeicher pro Anfrage:

Namenskonventionen

Bereich Präfix oder Muster Beispiel
Konsolenbefehle mmd:seo-suite-pro: mmd:seo-suite-pro:audit:run
Datenbanktabellen mmd_sylius_seo_suite_pro_ mmd_sylius_seo_suite_pro_redirect
Konfigurationswurzel mmd_sylius_seo_suite_pro config/packages/mmd_sylius_seo_suite_pro.yaml
Service-IDs, Parameter, Übersetzungsschlüssel mmd_sylius_seo_suite_pro. mmd_sylius_seo_suite_pro.sitemap_exclusion
Service-Tags (Erweiterungspunkte) mmd_sylius_seo_suite_pro.<art> mmd_sylius_seo_suite_pro.schema_provider
Manuelle Admin-Routen mmd_sylius_seo_suite_pro_admin_ mmd_sylius_seo_suite_pro_admin_audit
Generierte Ressourcen-Routen mmd_sylius_seo_suite_pro_plugin_admin_<ressource>_<aktion> mmd_sylius_seo_suite_pro_plugin_admin_seo_redirect_index
Shop-Routen mmd_sylius_seo_suite_pro_ mmd_sylius_seo_suite_pro_robots_txt, mmd_sylius_seo_suite_pro_og_image
Eigene Hook-Wurzeln mmd_sylius_seo_suite_pro. mmd_sylius_seo_suite_pro.seo_audit.index
Hook-Schlüssel innerhalb von Core-Hooks, Twig-Funktionen mmd_seo_suite_pro_ mmd_seo_suite_pro_seo
Ressourcen-Alias und UI-Schlüssel mmd_sylius_seo_suite_pro_plugin mmd_sylius_seo_suite_pro_plugin.ui.<ressource>

Die Ressourcennamen tragen ein Präfix (zum Beispiel seo_suite_pro_channel_settings), weil Sylius die Admin-Hooks nur nach dem Ressourcenteil des Alias benennt. Ein allgemeiner Name würde die Buttons dieses Plugins auf Seiten anderer Plugins zeigen. Admin-URLs und Tabellennamen sind davon nicht betroffen.

Die Admin-Routen liegen unter %sylius_admin.path_name%, nicht unter einem festen /admin. Die Shop-Routen (/robots.txt und /seo/og/...) gehören auf die oberste Ebene und nicht unter das Locale-Präfix.

Als @internal gekennzeichnete Klassen (zum Beispiel die Admin-Controller und einzelne Listener) sind keine Erweiterungs-API. Alles, was nicht in den Interfaces der Seite Erweiterbarkeit steht, gilt als Implementierungsdetail. Erweitere über die getaggten Interfaces, siehe Erweiterbarkeit.

Entwicklung und Tests

Für Integratoren ist nur wenig davon relevant. Das Repository bringt eine Docker-Umgebung mit, ein lokales PHP ist nicht nötig:

make init       # compose.override.yml kopieren, composer install, Assets bauen, Container starten
make static     # PHPStan und ECS
make phpunit    # Unit-, Integration- und Functional-Tests
make php-shell  # Shell im PHP-Container

Die Integrations- und Functional-Tests bauen das Schema selbst aus dem ORM-Mapping und brauchen nur eine erreichbare Datenbank (APP_ENV=test). Unter tests/TestApplication liegen die Produkt- und Kategorie-Unterklassen samt Migration, wie ein Shop sie für das Zuschalten der SEO-Felder schreibt. Das ist die Referenz zur Anleitung in der Installation.