TYPO3 Tipps und Tricks: PSR-15 Middleware am Beispiel Mailchimp Webhook

Das Konzept bzw. Design-Pattern "Middlewares" (auch bekannt als "Chain of Responsibility" bzw. "Zuständigkeitskette") - wurde in TYPO3 9 eingeführt. Das Konzept beschreibt wie HTTP-Requests sehr flexibel verarbeitet werden können. Wir werden den Einsatz von "PSR-15 Middelware" am Beispiel "Mailchimp Webhook" zeigen.

Dieses Konzept wird wie von TYPO3 bekannt auch im Core verwendet, um HTTP-Anfragen zu verarbeiten. Damit ein Request verarbeitet wird, durchläuft dieser eine "Chain" (fixen Ablauf) und wird dabei von einer Middleware verarbeitet, eine Middleware kann einen Response erzeugen oder auch einfach zur nächsten Middleware weitergeleitet werden. Über das Backend kann man sich die Liste über "Konfiguration -> HTTP-Middlewaren (PSR-15)" anzeigen.

TYPO3-Middleware im Backend
TYPO3-Middleware im Backend Modul Konfiguration

Da die TYPO3 rest Erweiterung zum Verfassungsdatum des Artikels noch nicht TYPO3 10 kompatibel ist, mussten wir nach einer Alternative suchen um einen POST-Request für den Mailchimp Webhook entgegenzunehmen. Der Kunde verwendet Mailchimp als Newsletter-System und auf der Website des Kunden können Benutzer auch ein Profil erstellen und sich dort vom Newsletter an und abmelden. Meldet sich der Benutzer über den Link in einner Newsletter-Mail ab, soll natürlich auch die Checkbox im Benutzerprofil deaktiviert werdenn. Dazu bietet Mailchimp einen Webhook an. Dabei kann man eine URL angeben und diese wird bei einer Aktualisierung per POST-Request aufgerufen. Die Dokumentation von Mailchimp findet sich hier.

Middleware Konfiguration

Um diesen Webhook entgegenzu nehmen, haben wir eine eigene entwickelt. Um die neue Middleware zu registrieren, muss im Configuration-Ordner der TYPO3-Erweiterung eine Datei mit dem Namen "RequestMiddlewares.php" erstellen.

<?phpreturn [    'frontend' => [        'varioous/rest/mail-chimp-middleware' => [            'target' => Varioous\Rest\MailChimpMiddleware::class,            'before' => [                'typo3/cms-frontend/eid',                'typo3/cms-frontend/tsfe',            ],        ],    ],];

Middleware-Klasse

In der Middleware-Klasse (in der Konfiguration oben registriert) wird der Prozess verarbeitet.

<?phpnamespace Varioous\Rest;use Psr\Http\Message\ResponseInterface;use Psr\Http\Message\ServerRequestInterface;use Psr\Http\Server\MiddlewareInterface;use Psr\Http\Server\RequestHandlerInterface;use TYPO3\CMS\Core\Http\Response;use TYPO3\CMS\Core\Utility\GeneralUtility;use Varioous\Utility\MailchimpUtility;class MailChimpMiddleware implements MiddlewareInterface{    /**     * @param \Psr\Http\Message\ServerRequestInterface $request     * @param \Psr\Http\Server\RequestHandlerInterface $handler     *     * @return \Psr\Http\Message\ResponseInterface     */    public function process(        ServerRequestInterface $request,        RequestHandlerInterface $handler    ): ResponseInterface {        #get called url        $normalizedParams = $request->getAttribute('normalizedParams');        $uri = $normalizedParams->getRequestUri();        #check if url is callled        if (strpos($uri, '/rest/mailchimp-webhook') === 0) {            #check if request is post request and a secret id is submitted (for security reason)            if ($request->getMethod() == 'POST' && isset($_GET['id']) && $_GET['id'] == 'various Interactive ist cool') {                #call method that handles the data that mailchimp sends                MailchimpUtility::mailchimpProfileUpdated(GeneralUtility::_POST());                #after processing data return 200                return (new Response())                    ->withHeader('content-type', 'text/plain; charset=utf-8')                    ->withStatus(200);            } else {                #Mailchimp need that the same URL returns a 200 status on same URL on GET-Request                return (new Response())                    ->withStatus(200);            }        }        #call next middleware        return $handler->handle($request);    }}

Weitere Einsatzmöglichkeiten

  • Slim-Framework: Man könnte so auch ein anderes Framework wie zum Beispiel "Slim" einsetzen und einfach eine komplette REST-Schnittstelle bauen. Hierfür gibt es sogar schon ein Projekt auf github (Allerdings zur Zeit auch noch nicht TYPO3 10 Kompatibel).
  • Middlewares können sowohl für das Frontend als auch Backend eingesetzt werden (siehe oben die Konfiguration).
  • Gewisse Bereiche der Website für bestimmte Benutzer sperren/freischalten.
  • Sprache oder Inhalt der Seite des Benutzers auf Basis einer Abfrage des Standorts anhand der IP durchführen.

Und noch viele weitere Möglichkeiten. Ist man mit diesem Konzept vertraut, ist man in Zukunft viel flexibler in der Umsetzung/Konzeption, da man verschiedene Anwendungsfälle einfach und flexibel umsetzen kann.

Nützliche Links / Quellen