Modell
Ahogy alkalmazásunk növekszik, hamarosan rájövünk, hogy hasonló adatbázisműveleteket kell végrehajtanunk különböző helyeken és különböző prezenterekben, például a legújabb megjelent cikkek megszerzéséhez. Ha úgy fejlesztjük az alkalmazásunkat, hogy a cikkekhez hozzáadunk egy flaget, amely a folyamatban lévő cikkek állapotát jelzi, akkor is végig kell mennünk az alkalmazásunk összes helyszínén, és hozzá kell adnunk egy where záradékot, hogy csak a kész cikkek legyenek kiválasztva.
Ezen a ponton az adatbázissal való közvetlen munka elégtelenné válik, és okosabb lesz egy új függvénnyel segíteni magunkat, amely visszaadja a megjelent cikkeket. Ha pedig később újabb záradékot adunk hozzá (például, hogy ne jelenítsünk meg jövőbeni dátumú cikkeket), akkor csak egy helyen szerkesztjük a kódunkat.
A függvényt a PostFacade
osztályba helyezzük, és getPublicArticles()
névre kereszteljük.
Létrehozzuk a PostFacade
modellosztályunkat a app/Model/
könyvtárban, hogy gondoskodjon a
cikkeinkről:
<?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');
}
}
Az osztályban átadjuk az adatbázis Explorer-t. Ezzel kihasználjuk a DI konténer erejét.
Átváltunk a HomePresenter
-ra, amelyet úgy szerkesztünk, hogy megszabadulunk a
Nette\Database\Explorer
függőségtől, és azt az új osztályunk függőségével helyettesítjük.
<?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);
}
}
A használati szakaszban a App\Model\PostFacade
címet használjuk, így a PHP-kódot lerövidíthetjük a
PostFacade
címre. Ezt az objektumot a konstruktorban kérjük, a $facade
tulajdonságba írjuk, és a
renderDefault metódusban használjuk.
Az utolsó hátralévő lépés az, hogy megtanítjuk a DI konténert, hogy ezt az objektumot előállítsa. Ez általában
úgy történik, hogy a config/services.neon
fájlban a services
szakaszban egy bullet pointot adunk
hozzá a fájlhoz, megadva a teljes osztálynevet és a konstruktor paramétereit. Ezzel úgymond regisztráljuk, és az
objektumot ezután service-nek hívjuk. Az autowiring nevű varázslatnak köszönhetően általában nem
kell megadnunk a konstruktor paramétereit, mert a DI felismeri és automatikusan átadja őket. Így elegendő lenne csak az
osztály nevét megadni:
...
services:
- App\Model\PostFacade
Azonban ezt a sort sem kell hozzáadni. A search
szakaszban, a services.neon
elején van definiálva,
hogy a -Facade
vagy -Factory
végződésű osztályokat a DI automatikusan megkeresi, ami a
PostFacade
esetében is így van.
Összefoglaló
A PostFacade
osztály egy konstruktorban kéri a Nette\Database\Explorer
címet, és mivel ez az
osztály regisztrálva van a DI konténerben, a konténer létrehozza ezt a példányt és átadja. A DI így létrehoz nekünk
egy PostFacade
példányt, és egy konstruktorban átadja azt a HomePresenter osztálynak, amelyik ezt kérte.
Afféle Matrjoska baba kód :) Minden komponens csak azt kéri, amire szüksége van, és nem érdekli őket, hogy hol és hogyan
jön létre. A létrehozást a DI konténer kezeli.
Itt olvashatsz többet a függőségi injektálásról, és a konfigurációról.