Generált gyárak
A Nette DI képes automatikusan gyárkódot generálni a felület alapján, ami megkíméli Önt a kód írásától.
A gyár egy olyan osztály, amely objektumokat hoz létre és konfigurál. Ezért a függőségeiket is átadja nekik. Kérjük, ne keverjük össze a factory method tervezési mintával, amely a gyárak használatának egy speciális módját írja le, és nem kapcsolódik ehhez a témához.
A bevezető fejezetben megmutattuk, hogyan néz ki egy ilyen gyár:
class ArticleFactory
{
public function __construct(
private Nette\Database\Connection $db,
) {
}
public function create(): Article
{
return new Article($this->db);
}
}
A Nette DI képes automatikusan gyárkódot generálni. Csak egy interfészt kell létrehozni, és a Nette DI generál egy
implementációt. Az interfésznek pontosan egy create
nevű metódussal kell rendelkeznie, és deklarálnia kell egy
visszatérési típust:
interface ArticleFactory
{
function create(): Article;
}
Tehát a ArticleFactory
gyárnak van egy create
metódusa, amely létrehozza a Article
objektumokat. A Article
osztály például a következőképpen nézhet ki:
class Article
{
public function __construct(
private Nette\Database\Connection $db,
) {
}
}
Adja hozzá a gyárat a konfigurációs fájlhoz:
services:
- ArticleFactory
A Nette DI létrehozza a megfelelő gyár implementációját.
Így a gyárat használó kódban az objektumot interfész szerint kérjük, és a Nette DI a generált implementációt használja:
class UserController
{
public function __construct(
private ArticleFactory $articleFactory,
) {
}
public function foo()
{
// hagyjuk, hogy a gyár létrehozzon egy objektumot
$article = $this->articleFactory->create();
}
}
Paraméteres gyár
A create
gyári metódus paramétereket fogadhat el, amelyeket aztán átad a konstruktornak. Adjunk például egy
cikk szerzői azonosítót a Article
osztályhoz:
class Article
{
public function __construct(
private Nette\Database\Connection $db,
private int $authorId,
) {
}
}
A paramétert is hozzáadjuk a gyárhoz:
interface ArticleFactory
{
function create(int $authorId): Article;
}
Mivel a konstruktorban lévő paraméter és a gyárban lévő paraméter neve megegyezik, a Nette DI automatikusan átadja őket.
Speciális definíció
A definíciót többsoros formában is meg lehet írni a implement
billentyűvel:
services:
articleFactory:
implement: ArticleFactory
Ha ilyen hosszabb formában írjuk, a arguments
kulcsban további argumentumokat adhatunk meg a konstruktor
számára, és a setup
segítségével további konfigurációkat adhatunk meg, ugyanúgy, mint a normál
szolgáltatások esetében.
Példa: ha a create()
metódus nem fogadná el a $authorId
paramétert, akkor a konfigurációban
megadhatnánk egy fix értéket, amelyet a Article
konstruktornak adnánk át:
services:
articleFactory:
implement: ArticleFactory
arguments:
authorId: 123
Vagy fordítva, ha a create()
elfogadja a $authorId
paramétert, de az nem része a konstruktornak,
hanem a Article::setAuthorId()
módszer adja át, akkor a setup
szakaszban hivatkoznánk rá:
services:
articleFactory:
implement: ArticleFactory
setup:
- setAuthorId($authorId)
Accessor
A gyárak mellett a Nette képes úgynevezett accessorokat is generálni. Az accessor egy olyan objektum, amely a
get()
metódussal rendelkezik, és egy adott szolgáltatást ad vissza a DI konténerből. Több get()
hívás mindig ugyanazt a példányt adja vissza.
Az accessorok a lazy-loadingot hozzák a függőségekbe. Legyen egy osztályunk, amely a hibákat egy speciális adatbázisba
naplózza. Ha az adatbázis-kapcsolatot függőségként adnánk át a konstruktorában, a kapcsolatot mindig létre kellene
hozni, bár csak ritkán, hiba esetén használnánk, így a kapcsolat többnyire kihasználatlan maradna. Ehelyett az osztály
átadhat egy accessort, és amikor annak get()
metódusa meghívásra kerül, csak ekkor jön létre az
adatbázis-objektum:
Hogyan hozzunk létre egy accessort? Írjunk csak egy interfészt, és a Nette DI legenerálja az implementációt. Az
interfésznek pontosan egy get
nevű metódussal kell rendelkeznie, és deklarálnia kell a visszatérési
típust:
interface PDOAccessor
{
function get(): PDO;
}
Adja hozzá az elérőt a konfigurációs fájlhoz annak a szolgáltatásnak a definíciójával együtt, amelyet az elérő visszaad:
services:
- PDOAccessor
- PDO(%dsn%, %user%, %password%)
Az accessor egy PDO
típusú szolgáltatást ad vissza, és mivel csak egy ilyen szolgáltatás van a
konfigurációban, az accessor azt fogja visszaadni. Több ilyen típusú konfigurált szolgáltatás esetén a névvel
megadhatja, hogy melyik legyen a visszaadandó szolgáltatás, például - PDOAccessor(@db1)
.
Multifactory/Accessor
Eddig a factories és accessorok csak egy objektumot tudtak létrehozni vagy visszaadni. Létrehozható egy multifactory egy
accessorral kombinálva is. Az ilyen multifactory osztály interfésze több metódusból állhat, amelyek neve
create<name>()
és get<name>()
például:
interface MultiFactory
{
function createArticle(): Article;
function getDb(): PDO;
}
Ahelyett, hogy több generált gyárat és accessort adna át, csak egy összetett multifactory-t adhat át.
Alternatívaként használhatja a get()
címet is egy paraméterrel, több metódus helyett:
interface MultiFactoryAlt
{
function get($name): PDO;
}
Ebben az esetben a MultiFactory::getArticle()
ugyanazt teszi, mint a MultiFactoryAlt::get('article')
.
Az alternatív szintaxisnak azonban van néhány hátránya. Nem egyértelmű, hogy mely $name
értékek
támogatottak, és a visszatérési típus nem adható meg az interfészben, ha több különböző $name
értéket
használunk.
Definíció listával
Így több gyárat lehet definiálni a konfigurációban:
services:
- MultiFactory(
article: Article # defines createArticle()
db: PDO(%dsn%, %user%, %password%) # defines getDb()
)
Vagy a gyár definíciójában hivatkozással hivatkozhatunk meglévő szolgáltatásokra:
services:
article: Article
- PDO(%dsn%, %user%, %password%)
- MultiFactory(
article: @article # defines createArticle()
db: @\PDO # defines getDb()
)
Meghatározás címkékkel
Egy másik lehetőség a multifactory definiálására a címkék használata:
services:
- App\Core\RouterFactory::createRouter
- App\Model\DatabaseAccessor(
db1: @database.db1.explorer
)