Während ich eine App in Laravel 4 erstellte, nachdem ich T. Otwells Buch über gute Designmuster in Laravel gelesen hatte, stellte ich fest, dass ich für jede Tabelle in der Anwendung Repositorys erstellte.
Am Ende hatte ich folgende Tabellenstruktur:
- Schüler: ID, Name
- Kurse: ID, Name, Lehrer_ID
- Lehrer: ID, Name
- Aufgaben: ID, Name, Kurs-ID
- Scores (fungiert als Dreh- und Angelpunkt zwischen Schülern und Aufgaben): student_id, assign_id, Scores
Ich habe Repository-Klassen mit Methoden zum Suchen, Erstellen, Aktualisieren und Löschen für alle diese Tabellen. Jedes Repository verfügt über ein eloquentes Modell, das mit der Datenbank interagiert. Beziehungen werden im Modell gemäß der Dokumentation von Laravel definiert: http://laravel.com/docs/eloquent#relationships .
Wenn ich einen neuen Kurs erstelle, rufe ich nur die create-Methode im Course Repository auf. Dieser Kurs hat Aufgaben, daher möchte ich beim Erstellen einer Aufgabe auch für jeden Kursteilnehmer einen Eintrag in der Punktetabelle erstellen. Ich mache das über das Assignment Repository. Dies impliziert, dass das Zuweisungs-Repository mit zwei eloquenten Modellen kommuniziert, mit dem Zuweisungs- und dem Studentenmodell.
Meine Frage ist: Da diese App wahrscheinlich größer wird und mehr Beziehungen eingeführt werden, empfiehlt es sich, mit verschiedenen Eloquent-Modellen in Repositorys zu kommunizieren, oder sollte dies stattdessen mit anderen Repositorys erfolgen (ich meine, andere Repositorys aus dem Zuweisungs-Repository aufzurufen) ) oder sollte es in den Eloquent-Modellen alle zusammen gemacht werden?
Ist es auch eine gute Praxis, die Punktetabelle als Dreh- und Angelpunkt zwischen Aufgaben und Schülern zu verwenden, oder sollte sie woanders durchgeführt werden?
$a = $this->account->getById(1)
kann ich Methoden wie nicht einfach verketten$a->getActiveUsers()
. Okay, ich könnte verwenden$a->users->...
, aber dann gebe ich eine Eloquent-Sammlung und kein stdClass-Objekt zurück und bin wieder an Eloquent gebunden. Was ist die Lösung dafür? Deklarieren Sie eine andere Methode im Benutzer-Repository wie$user->getActiveUsersByAccount($a->id);
? Würde gerne hören, wie Sie diesesIch beende ein großes Projekt mit Laravel 4 und musste alle Fragen beantworten, die Sie gerade stellen. Nachdem ich alle verfügbaren Laravel-Bücher bei Leanpub und jede Menge Googeln gelesen hatte, kam ich auf die folgende Struktur.
Nehmen wir also an, ich baue eine Filmdatenbank auf. Ich hätte mindestens die folgenden folgenden eloquenten Modellklassen:
Eine Repository-Klasse würde jede Eloquent Model-Klasse kapseln und für CRUD-Operationen in der Datenbank verantwortlich sein. Die Repository-Klassen könnten folgendermaßen aussehen:
Jede Repository-Klasse würde eine BaseRepository-Klasse erweitern, die die folgende Schnittstelle implementiert:
Eine Service-Klasse wird zum Zusammenkleben mehrerer Repositorys verwendet und enthält die eigentliche "Geschäftslogik" der Anwendung. Controller kommunizieren nur mit Serviceklassen für Aktionen zum Erstellen, Aktualisieren und Löschen.
Wenn ich also einen neuen Movie-Datensatz in der Datenbank erstellen möchte, verfügt meine MovieController-Klasse möglicherweise über die folgenden Methoden:
Es liegt an Ihnen, zu bestimmen, wie Sie Daten an Ihre Controller senden. Angenommen, die von Input :: all () in der postCreate () -Methode zurückgegebenen Daten sehen ungefähr so aus:
Da das MovieRepository nicht wissen sollte, wie Schauspieler-, Director- oder Studio-Datensätze in der Datenbank erstellt werden, verwenden wir unsere MovieService-Klasse, die ungefähr so aussehen könnte:
Was uns also bleibt, ist eine nette, vernünftige Trennung der Bedenken. Repositorys kennen nur das Eloquent-Modell, das sie einfügen und aus der Datenbank abrufen. Controller interessieren sich nicht für Repositorys, sie geben lediglich die vom Benutzer gesammelten Daten weiter und geben sie an den entsprechenden Dienst weiter. Dem Dienst ist es egal, wie die empfangenen Daten in der Datenbank gespeichert werden. Er gibt lediglich die relevanten Daten, die er vom Controller erhalten hat, an die entsprechenden Repositorys weiter.
quelle
$studio->movies()->associate($movie);
).Ich denke gerne darüber nach, was mein Code tut und wofür er verantwortlich ist, anstatt "richtig oder falsch". So breche ich meine Verantwortlichkeiten auseinander:
Vor diesem Hintergrund ist es jedes Mal sinnvoll, ein Repository zu verwenden (ob Sie interfaces.etc. Erstellen, ist ein ganz anderes Thema). Ich mag diesen Ansatz, weil ich genau weiß, wohin ich gehen muss, wenn ich bestimmte Arbeiten ausführen muss.
Ich neige auch dazu, ein Basis-Repository zu erstellen, normalerweise eine abstrakte Klasse, die die Hauptstandards definiert - im Grunde CRUD-Operationen, und dann kann jedes Kind einfach nach Bedarf Methoden erweitern und hinzufügen oder die Standardeinstellungen überladen. Durch das Injizieren Ihres Modells ist dieses Muster auch recht robust.
quelle
Stellen Sie sich Repositories als einen konsistenten Aktenschrank Ihrer Daten vor (nicht nur Ihrer ORMs). Die Idee ist, dass Sie Daten in einer konsistenten, einfach zu verwendenden API erfassen möchten.
Wenn Sie nur Model :: all (), Model :: find (), Model :: create () ausführen, werden Sie wahrscheinlich nicht viel davon profitieren, ein Repository zu abstrahieren. Wenn Sie andererseits Ihre Abfragen oder Aktionen etwas geschäftlicher gestalten möchten, möchten Sie möglicherweise ein Repository erstellen, um die Verwendung der API für den Umgang mit Daten zu vereinfachen.
Ich denke, Sie haben gefragt, ob ein Repository der beste Weg ist, um mit der ausführlicheren Syntax umzugehen, die zum Verbinden verwandter Modelle erforderlich ist. Abhängig von der Situation kann ich einige Dinge tun:
Wenn ich ein neues untergeordnetes Modell von einem übergeordneten Modell (eins-eins oder eins-viele) abhänge, füge ich dem untergeordneten Repository eine Methode hinzu, die
createWithParent($attributes, $parentModelInstance)
einfach$parentModelInstance->id
in dasparent_id
Feld der Attribute eingefügt wird, und rufe create auf.Wenn ich eine Viele-Viele-Beziehung anhänge, erstelle ich tatsächlich Funktionen für die Modelle, damit ich $ instance-> attachChild ($ childInstance) ausführen kann. Beachten Sie, dass hierfür auf beiden Seiten vorhandene Elemente erforderlich sind.
Wenn ich verwandte Modelle in einem Durchgang erstelle, erstelle ich etwas, das ich als Gateway bezeichne (es kann etwas von Fowlers Definitionen abweichen). So kann ich $ gateway-> createParentAndChild ($ parentAttributes, $ childAttributes) anstelle einer Reihe von Logik aufrufen, die sich möglicherweise ändert oder die Logik, die ich in einem Controller oder Befehl habe, komplizieren würde.
quelle