5. Januar 2018 // von Nathalie

Praktikum bei Thomann in Berlin – Feature "Hot Deals bestellen"

Die Hot Deals gibt es bei Thomann seit 1992. Hierbei handelt es sich um ein Faltblatt mit aktuellen Angeboten, das den Kunden gratis per Post zugesandt wird. Auf der Desktop-Seite www.thomann.de kann sich ein Kunde für die postalische Zustellung der Hot Deals sowohl an- als auch abmelden – die mobile Seite m.thomann.de sowie die Apps bieten diese Möglichkeit bisher nicht. Daher wurde es zu meiner Aufgabe, dieses Feature zu implementieren. Dazu muss eine ganz neue Seite erstellt werden, die über eine eigene URL erreichbar sein muss, den Standard-Header und -Footer einbindet und responsive ist. Die Hauptfunktionalität besteht aus einem Formular, in das der Kunde seine Adressdaten eingeben und abschicken kann, um die Hot Deals zu bestellen. Nach einer erfolgreichen clientseitigen Validierung des Formulars müssen die Adressdaten schließlich zum Kundencenter weitergeleitet werden, wo ein Mitarbeiter schließlich die Anmeldung vornimmt.
Analog zur Arbeit an den Webtests (in meinem nächsten Blogartikel :-)) handelt es sich bei diesem Projekt nicht um die Erweiterung eines bereits bestehenden Moduls, sondern um die grundlegende Neuimplementierung eines Features. Die Daten aus dem Anmeldeformular müssen nicht nur in der Datenbank gespeichert werden, sondern auch zum Kundencenter weitergeleitet werden, wo alle Hotdeals-Anfragen ankommen sollen, egal ob sie von der Desktop-, der mobilen Seite oder von den Apps aus geschickt werden. In allen Fällen muss hierfür eine XML-Datei in einer bestimmten Struktur generiert werden, die dem richtigen Ansprechpartner im Kundencenter zugeteilt wird. Zusammen mit meinen Betreuern wurden die einzelnen To-Dos besprochen, das Projekt in kleinere Zwischenschritte unterteilt und schließlich von mir umgesetzt.

API-Endpunkt erstellen

Damit das Anmeldeformular in der Datenbank gespeichert werden kann, muss sie über eine Schnittstelle verfügen, die die Daten entgegen nehmen kann. Daher galt es zunächst, einen entsprechenden API-Endpunkt zu implementieren.

Bei der Interaktion mit Datenbanken muss die Funktionalität des mit der Datenbank kommunizierenden Moduls zwingend durch Tests sichergestellt werden. Aus diesen Gründen habe ich einerseits geprüft, ob die an das Kundencenter weiterzuleitende XML-Datei korrekt erstellt wird, ob die übergebenen Daten alle den richtigen Feldern zugewiesen werden, ob alle Daten korrekt verarbeitet werden und schließlich ob der Prozess mit HTTP-Statuscode 201 abgeschlossen wird.

Userdatr Client erweitern

Der Userdatr Client stellt die Verbindung zwischen Webservices und API her. Hier wird die Methode implementiert, die vom Webservice später genutzt werden soll, um die Informationen an den zuvor implementierten REST-Endpunkt /hotdeals/subscribe weiterzureichen.

Webservice implementieren

Im Webservice wird die eigentliche Seite implementiert. Er ist dafür zuständig, dass Anfragen an die Middleware geschickt werden, die mehrere solcher Aufträge parallel in Empfang nehmen und verarbeiten kann. Die Middleware sammelt letztlich alle durch den Execution Plan angeforderten Einzelelemente für eine ganze Seite zusammen und schickt diese dann als Antwort zurück. Ein Execution Plan kann mehrere Webservices einbinden, sodass er weitere Aufträge verschachtelt ausführen kann.
In meinem Fall war es allerdings nicht notwendig, weitere Webservices einzubinden, da alle benötigten Elemente von einem einzigen erzeugt werden konnten. Neben der korrekten Generierung von Meta-Daten der Seite und dem Nutzer-freundlichen Abfangen von Fehlern ist es die fundamentale Aufgabe eines Webservices, den Inhalt der Seite zu erstellen und dafür die benötigten Render-Requests, die letztlich für die Darstellung der Seite zuständig sind, abzusenden.

Des Weiteren muss bei einem Submit clientseitig sichergestellt werden, dass die Schnittstelle angesprochen wird und die Daten korrekt und im richtigen Format an die API übermittelt werden. Im Fehlerfall sollen sowohl Entwickler als auch der Nutzer informiert werden.

function handleSubmit(WebserviceRequest $webserviceRequest) {
    if (AjaxValidationHelper::isAnswerAjaxValidationRequest($webserviceRequest)) {
        return AjaxValidationHelper::validateFormObject($webserviceRequest, HotdealsCatalogueForm::formBinder());
    }

    try {
        /** @var HotdealsCatalogueForm $form */
        $form = HotdealsCatalogueForm::formBinder()
            ->applyParametersToFormObject($webserviceRequest->getAllQueryParameters());

        $this->userdatrClient->postHotdealsSubscription($form->asJsonMap(), RequestUtils::populateFormMetaData($webserviceRequest));

        return $this->notifySubscriptionSuccessful($webserviceRequest);

    } catch (ThomannException $e) {
       // error-handling
       // ...
    }
}

Die HandleSubmit-Methode wird aufgerufen, sobald ein Submit (entweder für die Formularvalidierung, s.u. oder für das Abschicken des Formulars) getriggert wird.

Template & Styling

Das Rendern des Templates übernimmt die Render-Engine Dust.js. Hierbei konnte ich mich einerseits an den bereits bestehenden Templates orientieren und die einzelnen Felder für meine Zwecke anpassen. Andererseits galt es hier, die genaue Arbeitsweise des Tools zu verstehen, um an den richtigen Stellen Daten reinzureichen beziehungsweise Felder auszulesen, was speziell für den letzten Punkt eine große Rolle spielte.

<div class="hotdeals-form">

    <form action="{submitUrl}" method="POST" data-validation-url="{submitUrl}"
          id="hotdeals-catalogue-form">
        <input type="hidden" name="submitHotdealsCatalogue" value="true">

        <div class="form-control-row">
            <input type="text" name="company" class="form-control" value="{form.company}"
                   placeholder="[lp.general.form.firmaband] ([lp.general.form.optional])">
        </div>

        <div class="form-control-row">
            <div class="form-control-group">
                <input type="text" name="firstname" class="form-control {?errors.firstname}error{/errors.firstname}"
                       placeholder="[lp.general.form.vorname]" value="{form.firstname}" data-validate>
            </div>
            <div class="form-control-group">
                <input type="text" name="familyname" class="form-control {?errors.familyname}error{/errors.familyname}"
                       placeholder="[lp.general.form.nachname]" value="{form.familyname}" data-validate>
            </div>
        </div>

        <div class="form-control-row">
            <div class="error-message {^errors.firstname}hidden{/errors.firstname}"
                 data-validation-error-for="firstname">
                [lp.mobile.checkout.firstName.fail]
            </div>
        </div>

        <div class="form-control-row">
            <div class="error-message {^errors.familyname}hidden{/errors.familyname}"
                 data-validation-error-for="familyname">
                [lp.mobile.checkout.lastName.fail]
            </div>
        </div>

Formularvalidierung

Die Formularvalidierung stellte den letzten Schritt vor der Veröffentlichung der Hot Deals-Seite dar. Auch hier konnte ich auf ein bestehendes Modul zurückgreifen: Der AjaxValidator überprüft mithilfe eines speziell auf das betreffende Formular angepassten FormBinders, ob die gelieferten Werte mit den vorgegebenen Typen im FormBinder übereinstimmen. Im Template wird durch den Namen und das -Attribut markiert, welche Werte dem Formbinder übermittelt werden sollen. Sind alle Elemente korrekt miteinander verknüpft, wird nach jeder Bearbeitung eines Inputfeldes über eine eigene Submit-URL ein HTTP-Request geschickt, der im Webservice die korrekte Struktur der Elemente überprüft und gegebenenfalls eine Fehlermeldung anzeigt, noch bevor der Nutzer das Formular abschicken kann.

Veröffentlichung

Nach mehreren Feedback-Runden in Pullrequests war es schließlich soweit: Meine Arbeit konnte gemerged werden, sodass das Hot Deals bestellen-Feature mittlerweile über m.thomann.de/de/hotdeals_catalogue.html erreichbar ist.

Dieses Projekt war hervorragend geeignet, um einen intensiven Einblick in die gesamte Struktur der Webseite zu erhalten, da von der Frontend-Seite, mit der der Nutzer interagiert, über die eigentliche Funktionalität im Backend bis hin zum API-Endpunkt alles neu implementiert werden musste. Hinzu kommt, dass ich hierbei nicht nur das Webprojekt selbst kennenlernte, sondern auch erfahren habe, wie bei Thomann in Berlin sämtliche Arbeitsprozesse ablaufen.

Verwandte Blogposts