Modell
Wenn unsere Anwendung wächst, werden wir bald feststellen, dass wir ähnliche Datenbankoperationen an verschiedenen Stellen und in verschiedenen Präsentatoren durchführen müssen, um beispielsweise die neuesten veröffentlichten Artikel zu erfassen. Wenn wir unsere Anwendung verbessern, indem wir den Artikeln eine Markierung hinzufügen, die den Status “in Arbeit” anzeigt, müssen wir auch alle Standorte in unserer Anwendung durchgehen und eine Where-Klausel hinzufügen, um sicherzustellen, dass nur fertige Artikel ausgewählt werden.
An diesem Punkt wird die direkte Arbeit mit der Datenbank unzureichend, und es wird klüger sein, uns mit einer neuen Funktion zu helfen, die veröffentlichte Artikel zurückgibt. Und wenn wir später eine weitere Klausel hinzufügen (z. B. um keine Artikel mit einem zukünftigen Datum anzuzeigen), müssen wir unseren Code nur an einer Stelle bearbeiten.
Wir platzieren die Funktion in der Klasse PostFacade
und nennen sie getPublicArticles()
.
Wir erstellen unsere Modellklasse PostFacade
im Verzeichnis app/Model/
, die sich um unsere Artikel
kümmert:
<?php
namespace App\Model;
use Nette;
final class PostFacade
{
public function __construct(
private Nette\Database\Explorer $database,
) {
}
public function getPublicArticles()
{
return $this->database
->table('posts')
->where('created_at < ', new \DateTime)
->order('created_at DESC');
}
}
In der Klasse übergeben wir die Datenbank Explorer. Damit nutzen wir die Leistungsfähigkeit des DI-Containers.
Wir werden zu HomePresenter
wechseln, das wir so bearbeiten, dass wir die Abhängigkeit von
Nette\Database\Explorer
loswerden und durch eine neue Abhängigkeit von unserer neuen Klasse ersetzen.
<?php
namespace App\UI\Home;
use App\Model\PostFacade;
use Nette;
final class HomePresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private PostFacade $facade,
) {
}
public function renderDefault(): void
{
$this->template->posts = $this->facade
->getPublicArticles()
->limit(5);
}
}
Im Abschnitt use verwenden wir App\Model\PostFacade
, so dass wir den PHP-Code auf PostFacade
verkürzen können. Wir fordern dieses Objekt im Konstruktor an, schreiben es in die Eigenschaft $facade
und
verwenden es in der Methode renderDefault.
Der letzte verbleibende Schritt besteht darin, dem DI-Container beizubringen, dieses Objekt zu erzeugen. Dies geschieht in der
Regel durch Hinzufügen eines Aufzählungspunkts in der Datei config/services.neon
im Abschnitt
services
, in dem der vollständige Klassenname und die Konstruktorparameter angegeben werden. Dadurch wird es
sozusagen registriert, und das Objekt wird dann service genannt. Dank eines Zaubers namens Autowiring müssen wir die Konstruktorparameter normalerweise
nicht angeben, da DI sie erkennt und automatisch übergibt. Es würde also ausreichen, nur den Namen der Klasse anzugeben:
...
services:
- App\Model\PostFacade
Sie brauchen diese Zeile jedoch auch nicht hinzuzufügen. Im Abschnitt search
am Anfang von
services.neon
ist festgelegt, dass alle Klassen, die auf -Facade
oder -Factory
enden,
automatisch von DI nachgeschlagen werden, was auch für PostFacade
gilt.
Zusammenfassung
Die Klasse PostFacade
fragt in einem Konstruktor nach Nette\Database\Explorer
und da diese Klasse im
DI-Container registriert ist, erzeugt der Container diese Instanz und übergibt sie. DI erzeugt auf diese Weise eine
PostFacade
Instanz für uns und übergibt sie in einem Konstruktor an die HomePresenter Klasse, die danach gefragt
hat. Eine Art Matrjoschka-Puppe des Codes :) Alle Komponenten fordern nur an, was sie brauchen, und es ist ihnen egal, wo und wie
es erstellt wird. Die Erstellung wird vom DI-Container übernommen.
Hier können Sie mehr über Dependency Injection und über die Konfiguration lesen.