Zum Inhalt

Termin 2: Dynamische Webseiten, MVC-Architektur, Routing & Datenbanken

Ziel dieser Einheit ist die Entwicklung von sauberem, d.h., gut wartbarem, strukturiertem und objektorientiertem PHP-Code. Hierzu setzen wir das vordefinierte EWA_Framework ein, dieses basiert auf der MVC-Architektur. Ferner stellen wir in dieser Einheit die Datenbankanbindung zur Web-Applikation her, um Daten zu lesen und zu schreiben. Ansonsten soll ein leichtgewichtiges Routing implementiert werden.

Vorbereitung

Erledigen Sie diese Aufgaben VOR dem Übungstermin

Voraussetzung: Die vier in Termin 1 erstellten PHP-Seiten werden ordnungsgemäß vom Webserver ausgeliefert und erzeugen standardkonformen HTML-Code.

  1. Machen Sie sich mit dem EWA_Framework vertraut. Dieses findet Sie in ihrem Repository oder im Moodlekurs.

  2. Informieren Sie sich über die MVC Architektur.

  3. Versuchen Sie mit dem Getting started vom EWA_FRAMEWORK das Zusammenspiel der verschiedenen Klassen zu verstehen. Klären Sie folgende Fragen:

    • Wo erfolgt der eigentliche Aufruf zur Erstellung einer HTML-Seite?
    • Was tun die Methoden getData(), generateResponse() und processData()? In welcher Reihenfolge werden sie aufgerufen?
    • Was passiert im Controller, Model und View?
    • Was sind Partials?
    • Wie funktioniert das Routing?
  4. Analysieren Sie das zugelieferte Datenmodell für den Pizzaservice mit phpMyAdmin

    • Die Datenbank "pizzaservice" ist bereits angelegt.
    • Wenn der Webserver und der Datenbankserver (MariaDB) laufen, rufen Sie phpMyAdmin auf durch http://127.0.0.1/phpmyadmin.
    • Loggen Sie sich mit dem Benutzer root und den Passwort ganzGeheim ein, um root-Rechte zu bekommen
    • Analysieren Sie die Tabellenelemente mit Primär und Fremdschlüsseln. Beachten Sie auch die Einträge, die bereits in den Tabellen enthalten sind. Falls Einträge automatisch erzeugt werden, so ist dies in Klammern hinter dem Attribut angegeben (z.B. auto_increment).

Datenbankschema erweitern

  • Falls Sie zusätzliche Einträge in der Datenbank anlegen wollen (z.B. neue Einträge für die Speisekarte) oder minimal die Datenbank erweitern wollen, so tun Sie das bitte in der Datein 01-Pizzaservice_Database & 02-Pizzaservice_Database_Entries.sql im Verzeichnis mariadb.setup.
  • Anschließend müssen Sie die Datenbank neu bauen. Wie das funktioniert steht in der README.md und Makefile.
  • So stellen Sie sicher, das jeder der mit ihrem Projekt arbeitet immer das richtige Datenbankschema nutzt.

Aufgaben

In Termin 1 wurden die Seiten zunächst als statische *.php-Seiten umgesetzt. In dieser Einheit werden diese Seiten Schritt für Schritt in dynamische, über Routing erreichbare Endpunkte innerhalb der MVC-Architektur überführt.

EWA_FRAMEWORK

  • Nutzen Sie hierbei sowohl die Ordner- als auch die Dateistruktur der vom EWA-Framework zur Verfügung gestellten Vorlagen.
  • Orientieren Sie sich an dem "Getting started" vom EWA_Framework um ein Gefühl für die Funktionsweise des Frameworks zu bekommen.
  • Schauen Sie sich insbesondere das Routing-Beispiel genau an, um zu verstehen, was von Ihnen erwartet wird.

Routing

  1. Realisieren Sie ein zentrales Routing.

  2. Verwenden Sie dazu einen zentralen Einstiegspunkt (index.php). Neue Endpunkte werden über Routing ergänzt, nicht über zusätzliche *.php-Einstiegspunkte.

  3. Schauen Sie sich die .htaccess Datei an und versuchen Sie zu verstehen was dort passiert und wie diese das Routing beeinflusst.

  4. Definieren Sie neue Routen in einem switch-case in der index.php (z. B. case 'baker':) und verknüpfen Sie diese mit dem passenden Controller (z. B. BakerController).

  5. Nicht vorhandene Routen sollen ein 404 Statuscode ausgeben und entsprechend eine schöne 404 Seite anzeigen.

MVC-Architektur

  1. Legen Sie pro Seite einen Controller und eine View an, z. B. BakerController.php und baker.view.php. Die URL wird über die Route aufgerufen (z. B. /baker), nicht über eine eigene Datei im Root.

  2. Für Datenbankzugriffe verwenden Sie fachlich benannte Models (z. B. ArticleModel & OrderingModel). Lagern Sie dort die benötigten CRUD-Methoden zentral aus.

  3. Rufen Sie die jeweiligen Views im Controller über renderHtml() (aus BaseController) auf und nutzen Sie in den Views eine saubere Kombination aus Embedded PHP und HTML. Für Kontrollstrukturen nutzen Sie bitte die alternative PHP-Syntax.

  4. Navigation/Seitenteile können als Partials umgesetzt werden.

  5. Erstellen Sie Links zwischen Seiten über den Router (z. B. Router::generateUrl('baker')), damit die Routen konsistent bleiben.

  6. Verteilen Sie den HTML-Code aus der vorherigen Übung auf die zuständigen View-Dateien und Partials.

  7. Ergänzen Sie Hilfsmethoden oder zusätzliche Klassen nur bei Bedarf. Änderungen an den Signaturen von Methoden in BaseController und BaseModel sind zu vermeiden.

  8. Prüfen Sie abschließend, ob alle Routen die erwarteten Seiten/Endpunkte korrekt ausgeben und ob der generierte HTML-Code weiterhin standardkonform ist.

Ordnerstruktur

So sollte zum jetzigen Zeitpunkt ungefähr ihre Projektstruktur aussehen.

MVC-Ordnerstruktur

Meilenstein

An diesem Punkt sind alle Endpunkte gemäß MVC-Architektur inklusive Routing umgesetzt. Die Inhalte sind derzeit noch statisch und werden im nächsten Schritt dynamisch gestaltet.

Datenbankzugriff & dynamische Seitengenerierung

  1. Analysieren Sie den Konstruktor der Klasse BaseModel.php. Der Konstruktor baut die Datenbankverbindung auf. Verwenden Sie folgende Credentials:
    $user = 'public';
    $passwort = 'public';
    $database = 'pizzaservice';
    
  2. Implementieren Sie alle benötigten Datenbankzugriffe (CREATE, READ, UPDATE, DELETE) in den zuständigen Models. Folgendes soll beachtet werden:

    • Der Zugriff auf die Datenbank erfolgt objektorientiert über die Klasse MySQLi. Alle Models erben das Objekt $this->db vom BaseModel.php.
    • Zugriff auf die Datenbank erfolgt nur in den jeweiligen Models mittels CRUD-Methoden, welche Sie implementieren sollen.
    • In den Methoden getData() und processData() der jeweiligen Controller wird ausschließlich auf die Methoden vom Model mittels einem Objekt zugegriffen.
      • Die Methode processData() fängt alle Formulardaten ab und verarbeitet diese. Hier soll später auch das PRG-Pattern realisiert werden.
      • Die Methode getData() holt mit Hilfe vom jeweiligen Model die benötigten Daten aus der Datenbank und leitet diese an z.B. generateResponse() weiter.
    • Darüber hinaus darf im Controller natürlich zusätzliche Ablauf- oder Geschäftslogik implementiert werden, z. B. Validierungen, Weiterleitungen oder die Entscheidung, welche View geladen wird.
  3. Ersetzen Sie statische Codeteile schrittweise durch Datenbankabfragen (READ): Beginnen Sie beim Endpunkt /order und ersetzen Sie dort zuerst die statischen Artikeldaten durch Daten aus der Datenbank. Übertragen Sie dieses Vorgehen anschließend auf alle weiteren Endpunkte.

  4. Testen und validieren Sie anschließend die dynamisch generierten Inhalte.

Meilenstein

An diesem Punkt sind die Inhalte jetzt dynamisch. Als nächstes wollen wir Inhalte in die Datenbank schreiben oder aktualisieren.

Daten- und Formularverarbeitung

  • Passen Sie die Formulare so an, dass sie ihre Daten nicht mehr an das Echo-Skript schicken, sondern an die tatsächlichen Endpunkte, welchen Sie zur Datenverarbeitung nutzen wollen.

  • Neue Bestellungen speichern (CREATE):
    Implementieren Sie die Speicherung der abgeschickten Bestellung in den entsprechenden Datenbanktabellen. Dies erfolgt in der processData()-Methode vom OrderController.php mittels einer create()-Methode vom jeweiligen Model.

  • Daten für Bäcker und Fahrer aktualisieren (UPDATE):
    Aktualisierungen von Bestelldaten (z. B. durch Bäcker oder Fahrer) erfolgen ebenfalls in der processData()-Methode in den dazugehörigen Controllern. Nutzen Sie hierfür eine update()-Methode des jeweiligen Models.

  • Abgeschlossene Bestellungen löschen (DELETE):
    Sobald eine Bestellung vollständig ausgeliefert wurde, soll sie aus der Datenbank entfernt werden. Implementieren Sie hierzu eine delete()-Methode in dem jeweiligen Model und rufen Sie diese anschließend in der processData()-Methode vom DriverController.php auf.

Tipps zur Umsetzung

  • Nutzen Sie die vordefinierte Methode dump($myVariable) (wird vererbt von DebugHelper) für die schnelle Testausgabe. Alternativ: var_dump($myVariable).
  • $mysqli->insert_id liefert die Autoincrement-ID nach INSERT INTO (Wichtig für die Erstellung von ordnering und ordered_article)
  • Eine geschickte Datenbankabfrage (z.B. mit einem JOIN oder ORDER BY) kann Ihnen viel Implementierungsaufwand ersparen.

PRG-Pattern

Das Post/Redirect/Get-Pattern (PRG) hilft dabei, doppelte Formularübermittlungen zu vermeiden und sorgt für einen sauberen, stabilen Ablauf nach dem Absenden von Formularen.

  1. POST
    Das Formular wird per POST an den passenden Endpunkt gesendet (z. B. /order).
    Im zuständigen Controller werden die übermittelten Formulardaten in processData() verarbeitet (z. B. in die Datenbank geschrieben).

  2. REDIRECT
    Nach der Verarbeitung erfolgt eine Weiterleitung auf ein Ziel-Endpunkt, damit der ursprüngliche POST-Request aufgelöst wird.
    Beispiel:

    header('Location: ' . Router::generateUrl('customer'));
    exit;
    
    Optional kann eine Rückmeldung per GET-Parameter übergeben werden (z. B. message=success):
    header('Location: ' . Router::generateUrl('customer') . '?message=success');
    exit;
    
    Im View kann die Rückmeldung abhängig vom GET-Parameter angezeigt werden.

  3. GET
    Die Seite /customer wird anschließend mit einer normalen GET-Anfrage geladen, also ohne die ursprünglichen Formulardaten.
    Vorteil: Die Seite kann aktualisiert oder erneut aufgerufen werden, ohne erneute Formularübermittlung.

Das macht den Ablauf fehlerfreier, sicherer und benutzerfreundlicher – deshalb ist es ein bewährter Standard, nach einem POST oft ein GET folgen zu lassen. Am Besten zusätzlich mit einem visuellen Feedback für den Benutzer.

Sie sollten dieses Pattern überall in ihrem Projekt anwenden, wo es Sinn macht.

Großer Meilenstein

Ihr Projekt ist jetzt vollständig dynamisch und der gesamte Bestellprozess funktioniert durchgängig über Datenbank und Routing. Konkret bedeutet das:

  • Alle relevanten Seiten lesen ihre Inhalte aus der Datenbank (READ).
  • Neue Bestellungen werden korrekt angelegt und in den zugehörigen Tabellen gespeichert (CREATE).
  • Statusänderungen durch Bäcker und Fahrer werden zuverlässig übernommen (UPDATE).
  • Ausgelieferte Bestellungen werden fachlich korrekt entfernt (DELETE).
  • Formulare werden über die vorgesehenen Endpunkte verarbeitet und das PRG-Pattern wird an den passenden Stellen eingesetzt.
  • Die Navigation zwischen den Endpunkten funktioniert konsistent über den Router.

Hinweis

Ihr Webauftritt ist mittlerweile so weit fertig, dass Sie gerne auch jetzt schon das Design und das Layout der Anwendung angehen können (siehe Selbststudium II: Styling & Responsives Design).

Nachbereitung

Setzen Sie noch eventuell fehlende Teile der obigen Aufgabe bis zum Abgabetermin um.

Ergebnisse

Die folgenden Ergebnisse müssen für eine erfolgreiche Durchführung der Praktikumseinheit vorliegen:

Ergebnisse

  • Implementierung der Endpunkte /order, /customer, /baker und /driver samt Controllern, notwendiger Models, Views, Partials Routing & Datenbankanbindung.
  • Implementierung der Datenbankzugriffe mittels MySQLi
  • Die Endpunkte /order, /customer, /baker und /driver erfüllen die Anforderungen. Insbesondere gilt:
    • Die "Speisekarte" auf der Bestellseite wird mit den Daten aus den Datenbank erzeugt
    • Die Daten, welche die Bestellseite abschickt, werden in der Datenbank abgelegt.
    • Die Bäckerseite zeigt die bestellten Pizzen. Ein veränderter Status einer Pizza kann mit den Radio-Buttons (oder über einen Submit-Button abgeschickt) werden und wird in die Datenbank übernommen.
    • Die Fahrerseite zeigt die Bestellungen, die bereit für die Auslieferung sind. Ein veränderter Status einer Bestellung kann abgeschickt werden und wird in die Datenbank übernommen.
    • Ist die Bestellung ausgeliefert, wird diese aus der Datenbank gelöscht.
  • Sie haben das alles mit der vorgegebenen MVC-Archtiektur gelöst und CRUD-Methoden angewendet.
  • Routing funktioniert.
  • Sie haben erfolgreich, wo benötigt, das PRG-Pattern angewendet.