Генерирани фабрики
Nette DI може автоматично да генерира фабричен код въз основа на интерфейса, като ви спестява писането на код.
Фабриката е клас, който създава и конфигурира обекти. Следователно той предава на тях и техните зависимости. Моля, не бъркайте с шаблона за проектиране фабричен метод, който описва специфичен начин за използване на фабрики и не е свързан с тази тема.
Показахме как изглежда една такава фабрика в уводната глава:
Всичко, което трябва да направите, е да създадете интерфейс и Nette DI ще
генерира неговата реализация. Интерфейсът трябва да има точно един
метод с име create
и да декларира тип на връщане:
И така, фабриката ArticleFactory
има метод create
, който създава
обекти Article
. Един клас Article
може да изглежда по следния
начин, например
Добавете фабриката към конфигурационния файл:
Nette DI ще създаде подходяща фабрична реализация.
По този начин в кода, използващ фабриката, правим запитване към обекта по интерфейс, а Nette DI използва генерираната имплементация:
Параметризирана фабрика
Фабричният метод create
може да приема параметри, които след това
предава на конструктора. Например нека добавим идентификатор на автор
на статия към класа Article
:
Ще добавим и параметър към фабриката:
Тъй като параметърът в конструктора и параметърът във фабриката имат едно и също име, Nette DI ще ги предаде автоматично.
Разширено определение
Дефиницията може да бъде записана и в многоредова форма с помощта на
клавиша implement
:
Когато е написан по този удължен начин, е възможно да се предоставят
допълнителни аргументи за конструктора в ключа arguments
и
допълнителна конфигурация с setup
, точно както при нормалните
услуги.
Пример: Ако методът create()
не приема параметъра $authorId
,
бихме могли да посочим фиксирана стойност в конфигурацията, която ще
бъде предадена на конструктора Article
:
Или обратното, ако create()
приеме параметъра $authorId
, но той
не е част от конструктора и е предаден на метода Article::setAuthorId()
, ще
го посочим в раздела setup
:
Accessor
В допълнение към фабриките Nette може да генерира и така наречените
аксесори. Това са обекти с метода get()
, който връща конкретна
услуга от DI-контейнера. Многократните извиквания на get()
все още
връщат една и съща инстанция.
Този аксесоар осигурява лениво зареждане на зависимостите. Да
предположим, че имаме клас, който записва грешки в специална база
данни. Ако този клас предаде на конструктора връзка към база данни като
зависимост, тя винаги ще трябва да бъде създадена, въпреки че на
практика много рядко ще възникне грешка и затова връзката обикновено
ще остане неизползвана. Вместо това класът предава метод за достъп и
само когато той бъде извикан get()
, се създава обект на
базата данни:
Как да създадем аксесоар? Просто напишете интерфейс и Nette DI ще
генерира реализация. Интерфейсът трябва да има точно един метод с име
get
и да декларира тип на връщане:
Ще добавим аксесоара към конфигурационния файл, който съдържа и дефиниция на услугата, която той ще връща:
Тъй като методът за достъп връща услугата PDO
, а в
конфигурацията има само една такава услуга, той ще я върне. Ако има
повече услуги от този тип, определяме върнатата услуга с име, например
- PDOAccessor(@db1)
.
Множество фабрики/оценители
Досега нашите фабрики и аксесори винаги можеха да произвеждат или
връщат само един обект. Въпреки това е много лесно да се създадат
множество фабрики в комбинация с аксесори. Интерфейсът на такъв клас
ще съдържа произволен брой методи, наречени create<name>()
и
get<name>()
, напр:
Така че вместо да предадем няколко генерирани фабрики и аксесори, ще предадем друга сложна фабрика, която може да прави повече.
Вместо това можете да използвате get()
с параметър вместо
няколко метода:
В този случай MultiFactory::getArticle()
прави същото, което и
MultiFactoryAlt::get('article')
. Алтернативният синтаксис обаче има няколко
недостатъка. Не е ясно кои стойности на $name
се поддържат, а типът
на връщане не може да бъде посочен в интерфейса, когато се използват
няколко различни стойности на $name
.
Определение за списък
Този начин може да се използва за дефиниране на множество фабрики в конфигурацията:
Или в дефиницията на фабриката можем да се позовем на съществуващи услуги с помощта на референция:
Дефиниции с помощта на етикети
Вторият вариант е да използвате тагове за дефиниции: