Generirane tovarne
Nette DI lahko na podlagi vmesnika samodejno ustvari kodo tovarne, kar vam prihrani pisanje kode.
Tovarna je razred, ki ustvarja in konfigurira predmete. Zato jim posreduje tudi njihove odvisnosti. Ne zamenjujte z oblikovnim vzorcem tovarovna metoda, ki opisuje poseben način uporabe tovarn in ni povezan s to temo.
V uvodnem poglavju smo pokazali, kako je videti takšna tovarna:
class ArticleFactory
{
public function __construct(
private Nette\Database\Connection $db,
) {
}
public function create(): Article
{
return new Article($this->db);
}
}
Nette DI lahko samodejno ustvari tovarniško kodo. Vse, kar morate storiti, je, da ustvarite vmesnik in Nette DI bo ustvaril
implementacijo. Vmesnik mora imeti natančno eno metodo z imenom create
in deklarirati tip vrnitve:
interface ArticleFactory
{
function create(): Article;
}
Tako ima tovarna ArticleFactory
metodo create
, ki ustvari predmete Article
. Razred
Article
je lahko na primer videti takole:
class Article
{
public function __construct(
private Nette\Database\Connection $db,
) {
}
}
Dodajte tovarno v konfiguracijsko datoteko:
services:
- ArticleFactory
Nette DI bo ustvaril ustrezno implementacijo tovarne.
Tako v kodi, ki uporablja tovarno, zahtevamo objekt po vmesniku, Nette DI pa uporabi generirano implementacijo:
class UserController
{
public function __construct(
private ArticleFactory $articleFactory,
) {
}
public function foo()
{
// naj tovarna ustvari predmet
$article = $this->articleFactory->create();
}
}
Parametrizirana tovarna
Tovarniška metoda create
lahko sprejme parametre, ki jih nato posreduje konstruktorju. Na primer, dodajmo ID
avtorja članka v razred Article
:
class Article
{
public function __construct(
private Nette\Database\Connection $db,
private int $authorId,
) {
}
}
Parameter bomo dodali tudi tovarni:
interface ArticleFactory
{
function create(int $authorId): Article;
}
Ker imata parameter v konstruktorju in parameter v tovarni enako ime, ju bo Nette DI samodejno posredoval.
Napredna definicija
Definicijo lahko zapišete tudi v večvrstični obliki z uporabo tipke implement
:
services:
articleFactory:
implement: ArticleFactory
Pri tem daljšem zapisu je mogoče navesti dodatne argumente za konstruktor v ključu arguments
in dodatno
konfiguracijo s ključem setup
, tako kot pri običajnih storitvah.
Primer: če metoda create()
ne bi sprejela parametra $authorId
, bi lahko v konfiguraciji določili
fiksno vrednost, ki bi se posredovala konstruktorju Article
:
services:
articleFactory:
implement: ArticleFactory
arguments:
authorId: 123
Ali obratno, če bi create()
sprejel parameter $authorId
, vendar ta ne bi bil del konstruktorja in bi
ga posredovala metoda Article::setAuthorId()
, bi se nanj sklicevali v razdelku setup
:
services:
articleFactory:
implement: ArticleFactory
setup:
- setAuthorId($authorId)
Accessor
Poleg tovarn lahko Nette ustvari tudi tako imenovane dostopnike. Accessor je objekt z metodo get()
, ki vrača
določeno storitev iz vsebnika DI. Več klicev get()
bo vedno vrnilo isto instanco.
Dostopi prinašajo lenobno nalaganje v odvisnosti. Imejmo razred, ki beleži napake v posebno podatkovno zbirko. Če bi bila
povezava s podatkovno bazo posredovana kot odvisnost v njegovem konstruktorju, bi bilo treba povezavo vedno ustvariti, čeprav
bi jo uporabili le redko, ko se pojavi napaka, zato bi povezava ostala večinoma neuporabljena. Namesto tega lahko razred
posreduje dostopnik in ko se pokliče njegova metoda get()
, se šele takrat ustvari objekt podatkovne zbirke:
Kako ustvariti accessor? Napišite samo vmesnik in Nette DI bo ustvaril implementacijo. Vmesnik mora imeti natanko eno metodo
z imenom get
in mora deklarirati tip vrnitve:
interface PDOAccessor
{
function get(): PDO;
}
Dostopnik dodajte v konfiguracijsko datoteko skupaj z definicijo storitve, ki jo bo dostopnik vrnil:
services:
- PDOAccessor
- PDO(%dsn%, %user%, %password%)
PDO
Ker je v konfiguraciji samo ena takšna storitev, jo bo vrnil. Pri več konfiguriranih storitvah te vrste
lahko določite, katera naj se vrne, z uporabo njenega imena, na primer - PDOAccessor(@db1)
.
Multifactory/Accessor
Do zdaj so lahko tovarne in dostopniki ustvarili ali vrnili samo en predmet. Ustvarimo lahko tudi večfazo v kombinaciji
z dostopnikom. Vmesnik takega razreda multifactory je lahko sestavljen iz več metod, imenovanih
create<name>()
in get<name>()
na primer:
interface MultiFactory
{
function createArticle(): Article;
function getDb(): PDO;
}
Namesto več ustvarjenih tovarn in dostopov lahko posredujete samo eno kompleksno večfazno tovarno.
Namesto več metod lahko uporabite tudi get()
s parametrom:
interface MultiFactoryAlt
{
function get($name): PDO;
}
V tem primeru MultiFactory::getArticle()
naredi isto kot MultiFactoryAlt::get('article')
. Vendar ima
alternativna sintaksa nekaj pomanjkljivosti. Ni jasno, katere vrednosti $name
so podprte, v vmesniku pa ni mogoče
določiti tipa vrnitve pri uporabi več različnih vrednosti $name
.
Opredelitev s seznamom
Na ta način lahko v konfiguraciji določite več tovarn:
services:
- MultiFactory(
article: Article # defines createArticle()
db: PDO(%dsn%, %user%, %password%) # defines getDb()
)
Lahko pa se v definiciji tovarne sklicujemo na obstoječe storitve s pomočjo reference:
services:
article: Article
- PDO(%dsn%, %user%, %password%)
- MultiFactory(
article: @article # defines createArticle()
db: @\PDO # defines getDb()
)
Opredelitev z oznakami
Druga možnost, kako opredeliti večpredstavnostno zbirko, je uporaba oznak:
services:
- App\Core\RouterFactory::createRouter
- App\Model\DatabaseAccessor(
db1: @database.db1.explorer
)