Конфігурація 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
Як масово змінити всі сервіси певного типу? Наприклад, викликати певний метод у всіх presenter'ів, які успадковують від конкретного спільного предка? Для цього існує decorator.
decorator:
# для всіх сервісів, що є екземплярами цього класу або інтерфейсу
App\Presentation\BasePresenter:
setup:
- setProjectId(10) # виклич цей метод
- $absoluteUrls = true # і встанови змінну
Decorator можна також використовувати для налаштування тегів або ввімкнення режиму inject.
decorator:
InjectableInterface:
tags: [mytag: 1]
inject: true
DI
Технічні налаштування DI-контейнера.
di:
# показати DI-контейнер у Tracy Bar?
debugger: ... # (bool) за замовчуванням true
# типи параметрів, які ніколи не підключати автоматично
excluded: ... # (string[])
# дозволити ліниве створення сервісів?
lazy: ... # (bool) за замовчуванням false
# клас, від якого успадковується DI-контейнер
parentClass: ... # (string) за замовчуванням Nette\DI\Container
Lazy-сервіси
Налаштування lazy: true
активує ліниве (відкладене) створення
сервісів. Це означає, що сервіси не створюються насправді в момент,
коли ми їх запитуємо з DI-контейнера, а лише в момент їх першого
використання. Це може прискорити запуск програми та зменшити
споживання пам'яті, оскільки створюються лише ті сервіси, які дійсно
потрібні в даному запиті.
Для конкретного сервісу ліниве створення можна змінити.
Ліниві об'єкти можна використовувати лише для користувацьких класів, а не для внутрішніх класів PHP. Потребує PHP 8.4 або новішої версії.
Експорт метаданих
Клас DI-контейнера містить також багато метаданих. Ви можете зменшити його розмір, скоротивши експорт метаданих.
di:
export:
# експортувати параметри?
parameters: false # (bool) за замовчуванням true
# експортувати теги і які?
tags: # (string[]|bool) за замовчуванням всі
- event.subscriber
# експортувати дані для автопідключення і які?
types: # (string[]|bool) за замовчуванням всі
- Nette\Database\Connection
- Symfony\Component\Console\Application
Якщо ви не використовуєте масив $container->getParameters()
, ви можете
вимкнути експорт параметрів. Далі, ви можете експортувати лише ті теги,
через які ви отримуєте сервіси методом $container->findByTag(...)
. Якщо ви
взагалі не викликаєте цей метод, ви можете повністю вимкнути експорт
тегів за допомогою false
.
Ви можете значно скоротити метадані для автоматичного підключення,
вказавши класи, які ви використовуєте як параметр методу
$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 автоматично додає до контейнера presenter'и, але можна легко додавати й будь-які інші класи.
Достатньо вказати, у яких каталогах (та підкаталогах) слід шукати класи:
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 | результат |
---|---|---|
|
|
|