Der Inhalt dieses Artikels befasst sich mit der Analyse von Verträgen im Rahmen des Larave-Frameworks. Freunde in Not können sich darauf beziehen.
Verträge
Laravels Verträge sind eine Reihe von Schnittstellen, die die vom Framework bereitgestellten Kerndienste definieren, wie zum Beispiel den Benutzerschutzvertrag IllumninateContractsAuthGuard, den wir im Kapitel „Benutzereinführung“ gesehen haben Authentifizierung Und der Benutzeranbietervertrag IlluminateContractsAuthUserProvider
und der IlluminateContractsAuthAuthenticatable-Vertrag, der durch das Framework-eigene AppUser
-Modell implementiert wird.
Warum Verträge verwenden?
Anhand der Quellcodedateien der oben genannten Verträge können wir erkennen, dass es sich bei dem von Laravel bereitgestellten Vertrag um eine Reihe von Schnittstellen handelt, die für das Kernmodul definiert sind . Laravel stellt für jeden Vertrag entsprechende Implementierungsklassen bereit. In der folgenden Tabelle sind die von Laravel für die drei oben genannten Verträge bereitgestellten Implementierungsklassen aufgeführt.
契约 | Laravel内核提供的实现类 |
---|---|
IllumninateContractsAuthGuard | IlluminateAuthSessionGuard |
IlluminateContractsAuthUserProvider | IlluminateAuthEloquentUserProvider |
IlluminateContractsAuthAuthenticatable | IlluminateFoundationAuthAuthenticatable(User Model的父类) |
Wenn also in einem selbst entwickelten Projekt das von Laravel bereitgestellte Benutzerauthentifizierungssystem die Anforderungen nicht erfüllen kann, können Sie die Implementierungsklassen des Wächters und des Benutzeranbieters entsprechend den Anforderungen definieren. Zum Beispiel das Projekt, an dem ich zuvor gearbeitet habe Da die Benutzerauthentifizierung auf der API des Mitarbeiterverwaltungssystems beruhte, habe ich die Implementierungsklassen der Guard- und User-Provider-Verträge selbst geschrieben, sodass Laravel die Benutzerauthentifizierung über den angepassten Guard und UserProvider abschließen konnte. Wir haben die Methode zum Anpassen der Benutzerauthentifizierung im Kapitel zur Einführung in die Benutzerauthentifizierung vorgestellt. Leser können diesen Artikel lesen.
Der Zweck der Definition von Vertragsschnittstellen für alle Kernfunktionen durch Laravel besteht also darin, Entwicklern zu ermöglichen, ihre eigenen Implementierungsklassen entsprechend den Anforderungen ihrer eigenen Projekte zu definieren, und für Verbraucher dieser Schnittstellen (z. B. Controller oder Der Kernel stellt AuthManager usw. bereit.) Sie müssen sich nicht darum kümmern, wie die von der Schnittstelle bereitgestellten Methoden implementiert werden. Sie kümmern sich nur darum, welche Funktionen die Schnittstellenmethoden bereitstellen können, und können diese Funktionen dann ändern Schnittstelle bei Bedarf entsprechend den Anforderungen anpassen. Auf der Verbraucherseite sind keine Änderungen erforderlich.
Verträge definieren und verwenden
Was wir oben erwähnt haben, sind alle vom Laravel-Kernel bereitgestellten Verträge. Bei der Entwicklung großer Projekte können wir die Verträge auch selbst im Projekt definieren Sie haben möglicherweise das Gefühl, dass die integrierten Controller- und Modellebenen für das Schreiben von Code ausreichen. Das Hinzufügen zusätzlicher Verträge und Implementierungsklassen macht die Entwicklung umständlich. Beginnen wir mit einem einfachen Beispiel und überlegen, was mit dem folgenden Code nicht stimmt:
class OrderController extends Controller { public function getUserOrders() { $orders= Order::where('user_id', '=', \Auth::user()->id)->get(); return View::make('order.index', compact('orders')); } }
Dieser Code ist sehr einfach, aber wenn wir diesen Code testen möchten, müssen wir uns an die tatsächliche Datenbank wenden. Mit anderen Worten: Der ORM und dieser Controller sind eng miteinander verbunden. Wir haben keine Möglichkeit, diesen Code auszuführen oder zu testen, ohne das Eloquent ORM zu verwenden und eine Verbindung zu einer tatsächlichen Datenbank herzustellen. Dieser Code verstößt auch gegen das Software-Designprinzip der „Separation of Concerns“. Einfach ausgedrückt: Dieser Controller weiß zu viel. Der Verantwortliche muss nicht wissen, woher die Daten kommen, sondern nur, wie er darauf zugreifen kann. Der Controller muss nicht wissen, woher die Daten von MySQL kommen, er muss lediglich wissen, dass die Daten aktuell verfügbar sind.
Trennung der BelangeJede Klasse sollte eine einzige Verantwortung haben, und diese Verantwortung sollte vollständig von der Klasse gekapselt sein.
Jede Klasse sollte nur eine einzige Verantwortung haben. und alles in den Verantwortlichkeiten sollte von dieser Klasse gekapselt werden
Als nächstes definieren wir eine Schnittstelle und implementieren dann die Schnittstelle
interface OrderRepositoryInterface { public function userOrders(User $user); } class OrderRepository implements OrderRepositoryInterface { public function userOrders(User $user) { Order::where('user_id', '=', $user->id)->get(); } }
Binden Sie die Implementierung der Schnittstelle an den Service-Container von Laravel
App::singleton('OrderRepositoryInterface', 'OrderRespository');
Dann injizieren wir die Implementierung dieser Schnittstelle in unseren Controller
class UserController extends Controller { public function __construct(OrderRepositoryInterface $orderRepository) { $this->orders = $orderRespository; } public function getUserOrders() { $orders = $this->orders->userOrders(); return View::make('order.index', compact('orders')); } }
Jetzt ist unser Controller völlig unabhängig von der Datenschicht. Dabei können unsere Daten von MySQL, MongoDB oder Redis stammen. Unser Controller kennt den Unterschied nicht und muss ihn auch nicht kennen. Auf diese Weise können wir die Webschicht unabhängig von der Datenschicht testen und es wird in Zukunft einfach sein, die Speicherimplementierung zu wechseln.
Schnittstellen- und Teamentwicklung
Wenn Ihr Team eine große Anwendung entwickelt, haben verschiedene Teile unterschiedliche Entwicklungsgeschwindigkeiten. Beispielsweise entwickelt ein Entwickler die Datenschicht und ein anderer Entwickler arbeitet an der Controller-Schicht. Der Entwickler, der den Controller geschrieben hat, möchte seinen Controller testen, aber die Entwicklung der Datenschicht ist langsam und kann nicht gleichzeitig getestet werden. Wenn sich zwei Entwickler zunächst in Form einer Schnittstelle einigen können, folgen verschiedene im Hintergrund entwickelte Klassen dieser Vereinbarung. Sobald ein Vertrag erstellt wurde, können Entwickler eine „gefälschte“ Implementierung für diese Schnittstelle schreiben, auch wenn der Vertrag noch nicht implementiert wurde
class DummyOrderRepository implements OrderRepositoryInterface { public function userOrders(User $user) { return collect(['Order 1', 'Order 2', 'Order 3']); } }
Sobald die gefälschte Implementierung geschrieben ist, kann sie an den IoC-Container gebunden werden
App::singleton('OrderRepositoryInterface', 'DummyOrderRepository');
Dann können die Ansichten der App mit gefälschten Daten gefüllt werden. Sobald der Backend-Entwickler mit dem Schreiben des eigentlichen Implementierungscodes fertig ist, beispielsweise mit dem Namen RedisOrderRepository. Mithilfe der IoC-Container-Switching-Schnittstellenimplementierung kann die Anwendung dann problemlos zur tatsächlichen Implementierung wechseln und die gesamte Anwendung verwendet die von Redis gelesenen Daten.
Schnittstelle und Tests
Nachdem wir die Schnittstellenvereinbarung festgelegt haben, ist es für uns bequemer, während des Tests zu verspotten
public function testIndexActionBindsUsersFromRepository() { // Arrange... $repository = Mockery::mock('OrderRepositoryInterface'); $repository->shouldReceive('userOrders')->once()->andReturn(['order1', 'order2]); App::instance('OrderRepositoryInterface', $repository); // Act... $response = $this->action('GET', 'OrderController@getUserOrders'); // Assert... $this->assertResponseOk(); $this->assertViewHas('order', ['order1', 'order2']); }
Zusammenfassung
Schnittstellen sind in der Programmierphase sehr nützlich. Besprechen Sie in der Entwurfsphase mit dem Team, welche Schnittstellen entwickelt werden müssen, um die Funktion zu vervollständigen, und entwerfen Sie dann die spezifischen Methoden, die für jede Schnittstelle implementiert werden sollen. Die Eingabeparameter und Rückgabewerte der Methoden usw. Sie können Ihr eigenes Modul gemäß der Schnittstellenvereinbarung entwickeln. Wenn Sie auf eine Schnittstelle stoßen, die noch nicht implementiert wurde, können Sie zunächst eine gefälschte Implementierung der Schnittstelle definieren und warten Sie, bis die eigentliche Implementierungsentwicklung abgeschlossen ist, bevor Sie wechseln. Dadurch wird nicht nur der Einfluss der oberen Schicht auf die untere Schicht in der Softwareprogrammstruktur verringert, sondern es wird auch sichergestellt, dass der Entwicklungsfortschritt der einzelnen Teile nicht übermäßig von der Fertigstellung abhängt andere Teile.
Das obige ist der detaillierte Inhalt vonAnalyse von Verträgen im Rahmen des Larave-Frameworks. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!