Конфигурация на DI контейнера
Преглед на опциите за конфигурация на Nette DI контейнера.
Конфигурационен файл
Nette DI контейнерът се управлява лесно с помощта на конфигурационни файлове. Те обикновено се записват във формат NEON. За редактиране препоръчваме редактори с поддръжка на този формат.
decorator: Декоратор
di: DI контейнер
extensions: Инсталиране на други DI разширения
includes: Включване на файлове
parameters: Параметри
search: Автоматично регистриране на сървиси
services: Сървиси
Ако искате да напишете низ, съдържащ знака %
, трябва да
го екранирате, като го удвоите на %%
.
Параметри
В конфигурацията можете да дефинирате параметри, които след това могат да се използват като част от дефинициите на сървисите. Това може да направи конфигурацията по-ясна или да обедини и изолира стойности, които ще се променят.
parameters:
dsn: 'mysql:host=127.0.0.1;dbname=test'
user: root
password: secret
Към параметъра dsn
се обръщаме навсякъде в конфигурацията, като
напишем %dsn%
. Параметрите могат да се използват и в низове като
'%wwwDir%/images'
.
Параметрите не трябва да бъдат само низове или числа, те могат да съдържат и масиви:
parameters:
mailer:
host: smtp.example.com
secure: ssl
user: franta@gmail.com
languages: [cs, en, de]
Към конкретен ключ се обръщаме като %mailer.user%
.
Ако трябва да разберете стойността на който и да е параметър във вашия код, например в клас, предайте го на този клас. Например в конструктора. Няма глобален обект, представляващ конфигурацията, към който класовете да се обръщат за стойности на параметри. Това би било нарушение на принципа на dependency injection.
Сървиси
Вижте отделна глава.
Decorator
Как да модифицирате масово всички сървиси от определен тип? Например, да извикате определен метод за всички презентери, които наследяват от конкретен общ предшественик? За това служи декораторът.
decorator:
# за всички сървиси, които са инстанции на този клас или интерфейс
App\Presentation\BasePresenter:
setup:
- setProjectId(10) # извикайте този метод
- $absoluteUrls = true # и задайте променливата
Decorator може да се използва и за задаване на тагове или за активиране на режим inject.
decorator:
InjectableInterface:
tags: [mytag: 1]
inject: true
DI
Технически настройки на DI контейнера.
di:
# показва ли се DIC в Tracy Bar?
debugger: ... # (bool) по подразбиране е true
# типове параметри, които никога да не се autowire-ват
excluded: ... # (string[])
# разрешава ли се lazy създаване на сървиси?
lazy: ... # (bool) по подразбиране е false
# клас, от който наследява DI контейнерът
parentClass: ... # (string) по подразбиране е Nette\DI\Container
Lazy сървиси
Настройката lazy: true
активира lazy (отложено) създаване на сървиси.
Това означава, че сървисите не се създават реално в момента, в който ги
поискаме от DI контейнера, а едва в момента на първото им използване.
Това може да ускори стартирането на приложението и да намали
изискванията за памет, тъй като се създават само тези сървиси, които са
действително необходими в дадена заявка.
За конкретен сървис lazy създаването може да бъде променено.
Lazy обектите могат да се използват само за потребителски класове, а не за вътрешни PHP класове. Изисква PHP 8.4 или по-нова версия.
Експортиране на метаданни
Класът на DI контейнера съдържа и много метаданни. Можете да го намалите, като редуцирате експорта на метаданни.
di:
export:
# експортиране на параметри?
parameters: false # (bool) по подразбиране е true
# експортиране на тагове и кои?
tags: # (string[]|bool) по подразбиране са всички
- event.subscriber
# експортиране на данни за autowiring и кои?
types: # (string[]|bool) по подразбиране са всички
- Nette\Database\Connection
- Symfony\Component\Console\Application
Ако не използвате масива $container->getParameters()
, можете да изключите
експорта на параметри. Освен това можете да експортирате само тези
тагове, чрез които получавате сървиси с метода $container->findByTag(...)
.
Ако изобщо не извиквате метода, можете напълно да изключите експорта
на тагове с false
.
Можете значително да намалите метаданните за autowiring , като посочите класовете,
които използвате като параметър на метода $container->getByType()
. И
отново, ако изобщо не извиквате метода (или само в bootstrap, за да получите
Nette\Application\Application
), можете напълно да изключите експорта с
false
.
Разширения
Регистриране на други DI разширения. По този начин добавяме например DI
разширението Dibi\Bridges\Nette\DibiExtension22
под името dibi
extensions:
dibi: Dibi\Bridges\Nette\DibiExtension22
След това го конфигурираме в секцията dibi
:
dibi:
host: localhost
Като разширение може да се добави и клас, който има параметри:
extensions:
application: Nette\Bridges\ApplicationDI\ApplicationExtension(%debugMode%, %appDir%, %tempDir%/cache)
Включване на файлове
Можем да включим други конфигурационни файлове в секцията
includes
:
includes:
- parameters.php
- services.neon
- presenters.neon
Името parameters.php
не е печатна грешка, конфигурацията може да бъде
записана и в PHP файл, който я връща като масив:
<?php
return [
'database' => [
'main' => [
'dsn' => 'sqlite::memory:',
],
],
];
Ако в конфигурационните файлове се появят елементи с еднакви
ключове, те ще бъдат презаписани или, в случай на масиви,
слети. Файлът, включен по-късно, има по-висок приоритет от предишния.
Файлът, в който е посочена секцията includes
, има по-висок приоритет
от файловете, включени в него.
Search
Автоматичното добавяне на сървиси към DI контейнера прави работата изключително приятна. Nette автоматично добавя презентери към контейнера, но можете лесно да добавяте и всякакви други класове.
Достатъчно е да посочите в кои директории (и поддиректории) да търси класове:
search:
- in: %appDir%/Forms
- in: %appDir%/Model
Обикновено обаче не искаме да добавяме абсолютно всички класове и интерфейси, така че можем да ги филтрираме:
search:
- in: %appDir%/Forms
# филтриране по име на файл (string|string[])
files:
- *Factory.php
# филтриране по име на клас (string|string[])
classes:
- *Factory
Или можем да изберем класове, които наследяват или имплементират поне един от изброените класове:
search:
- in: %appDir%
extends:
- App\*Form
implements:
- App\*FormInterface
Могат да се дефинират и изключващи правила, т.е. маски на имена на класове или наследствени предци, които, ако съвпадат, сървисът няма да бъде добавен към DI контейнера:
search:
- in: %appDir%
exclude:
files: ...
classes: ...
extends: ...
implements: ...
На всички сървиси могат да се зададат тагове:
search:
- in: %appDir%
tags: ...
Сливане
Ако в няколко конфигурационни файла се появят елементи с еднакви ключове, те ще бъдат презаписани или, в случай на масиви, слети. Файлът, включен по-късно, има по-висок приоритет от предишния.
config1.neon | config2.neon | резултат |
---|---|---|
|
|
|
При масивите сливането може да бъде предотвратено чрез добавяне на удивителен знак след името на ключа:
config1.neon | config2.neon | резултат |
---|---|---|
|
|
|