CRUD in PHP mit Repositories und Models

Aufbauend auf dem Artikel zum Thema CRUD in PHP und MySQL mit PDO erstellen möchte ich hier noch ein wenig mehr auf die Strukturierung eines solchen Projekts eingehen.

Ich verwende dabei die Idee des Repository-Patterns unter der Verwendung einzelner Model-Klassen für jede Tabelle.

 

Als Beispiele verwende ich hier erneut Tabellen aus meiner Kochbuch-Anwendung. Hierbei werden Rezepte (Recipes) und Zutaten (Ingredients) verwaltet.

Model

Zunächst erstellen wir eine Modelklasse zu jeder unserer Tabellen. Haben wir z.B. eine Ingredient-Tabelle mit den Spalten Name, Anzahl, Einheit, Kommentar und Rezept-ID, sieht die Klasse dazu folgendermaßen aus:

Zu jedem Feld der Klasse gibt es nun noch passende Getter und Setter.

Hier die Getter und Setter am Beispiel des Felds Name:

Beim Setter wird der übergebene Parameter noch auf den passenden Typ geprüft und ggf. umgewandelt.

 

Das Model kann derüber hinaus noch weitere hilfreiche Methoden enthalten. Etwa eine Methode clear(), welche alle Werte auf null setzt oder Umwandlungsmethoden wie toArray():

Auch sind Factory-Methoden denkbar:

 

Das Model dient allerdings nur dazu, die Daten aus der Datenbanktabelle zu tragen. Es enthält keinerlei Businesslogik oder -funktionen.

 

Repository

Das Repository ist dafür zuständig, die Daten aus der Datenbank zu lesen oder in ihr zu schreiben, bzw. zu aktualisieren. Dabei arbeitet es entweder mit einfachen Werten (Strings, Integer, …) oder eben mit unseren Model-Klassen.

Die Methoden der Repository-Klassen sollten einem einheitlichen Muster folgen. So sollten alle Methoden, die einen Datensatz aus der Tabelle auslesen find…() heißen, alle die einen Datensatz löschen delete…(), alle die einen Datensatz aktualisieren update…() und das neu Anlegen sollte create() oder save() heißen. Wenn die Methoden in allen verwendeten Repositories einheitlich benannt sind, fällt uns die Verwendung hinterher leichter.

 

Das Repository für unser Ingredient-Model etwa könnte die folgenden Methoden haben:

Ich verwende hier als Schnittstelle save() zum Erstellen oder Aktualisieren eines Datensatzes. Der Aufrufer muss sich dann nicht darum kümmern, ob der Datensatz nun neu ist und create() aufrufen muss oder ob er eine Aktualisierung durch update() anzustoßen hat.

Die save()-Methode sieht dabei folgendermaßen aus:

Die beiden internen Methoden createIngredient() und updateIngredient() sind private und von außen somit nicht erreichbar.

 

Verwaltung des PDO-Objekts

Wie wir ein PDO-Objekt für den Zugriff auf die Datenbank erstellen, habeich im Artikel CRUD in PHP und MySQL mit PDO erstellen bereits beschrieben.

Im oben vorgestellten Repository wird das PDO-Objekt als Parameter übergeben. Das ist auch gut so, dann kann es in Unit-Tests einfach durch eine Mock- oder Stub-Implementierung ersetzt werden (wem das jetzt nichts sagt, der sollte das mal auf unserem Blog zum Thema Code-Qualität nachlesen).

Die Frage ist aber, wie der Aufrufer (ein Controller oder besser ein Service) das PDO-Objekt bekommt.

Dafür gibt es zwei Lösungen

  1. Wir erstellen das PDO-Objekt zentral in unserer index.php und überall dort, wo wir es benötigen, definieren wir es als global.
    Hier ein Beispiel:

  2. Wir erstellen eine eigene Klasse, z.B. Database. Diese hat eine statische Methode connect(), die die Verbindung herstellt, falls nock keine bestehen sollte. Hier der Code dazu:

Bisher habe ich die erste Lösung verwendet. Sie funktioniert, fühlt sich aber irgendwie seltsam an. Ich werde nun nur noch die Lösung über die statische Fabrik verwenden.

 

Posted in PHP

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.