Nette Documentation Preview

syntax
Конфігурація DI-контейнера
**************************

.[perex]
Огляд конфігураційних опцій для Nette DI-контейнера.


Конфігураційний файл
====================

Nette DI-контейнер легко керується за допомогою конфігураційних файлів. Вони зазвичай записуються у [форматі NEON|neon:format]. Для редагування рекомендуємо [редактори з підтримкою |best-practices:editors-and-tools#IDE редактор] цього формату.

<pre>
"decorator .[prism-token prism-atrule]":[#decorator]: 	"Декоратор .[prism-token prism-comment]"<br>
"di .[prism-token prism-atrule]":[#DI]: 			"DI-контейнер .[prism-token prism-comment]"<br>
"extensions .[prism-token prism-atrule]":[#Розширення]: 	"Встановлення додаткових DI-розширень .[prism-token prism-comment]"<br>
"includes .[prism-token prism-atrule]":[#Включення файлів]: 	"Включення файлів .[prism-token prism-comment]"<br>
"parameters .[prism-token prism-atrule]":[#Параметри]: 	"Параметри .[prism-token prism-comment]"<br>
"search .[prism-token prism-atrule]":[#Search]: 		"Автоматична реєстрація сервісів .[prism-token prism-comment]"<br>
"services .[prism-token prism-atrule]":[services]: 		"Сервіси .[prism-token prism-comment]"
</pre>

.[note]
Щоб записати рядок, що містить символ `%`, потрібно його екранувати, подвоївши до `%%`.


Параметри
=========

У конфігурації можна визначити параметри, які потім можна використовувати як частину визначень сервісів. Це може зробити конфігурацію більш зрозумілою або об'єднати та виділити значення, які будуть змінюватися.

```neon
parameters:
	dsn: 'mysql:host=127.0.0.1;dbname=test'
	user: root
	password: secret
```

На параметр `dsn` можна посилатися будь-де в конфігурації записом `%dsn%`. Параметри можна використовувати і всередині рядків, як `'%wwwDir%/images'`.

Параметри не обов'язково мають бути лише рядками або числами, вони також можуть містити масиви:

```neon
parameters:
	mailer:
		host: smtp.example.com
		secure: ssl
		user: franta@gmail.com
	languages: [cs, en, de]
```

На конкретний ключ можна посилатися як `%mailer.user%`.

Якщо вам потрібно у вашому коді, наприклад, у класі, дізнатися значення будь-якого параметра, передайте його до цього класу. Наприклад, у конструкторі. Не існує жодного глобального об'єкта, що представляє конфігурацію, до якого класи могли б звертатися за значеннями параметрів. Це було б порушенням принципу dependency injection.


Сервіси
=======

Див. [окремий розділ|services].


Decorator
=========

Як масово змінити всі сервіси певного типу? Наприклад, викликати певний метод у всіх presenter'ів, які успадковують від конкретного спільного предка? Для цього існує decorator.

```neon
decorator:
	# для всіх сервісів, що є екземплярами цього класу або інтерфейсу
	App\Presentation\BasePresenter:
		setup:
			- setProjectId(10)       # виклич цей метод
			- $absoluteUrls = true   # і встанови змінну
```

Decorator можна також використовувати для налаштування [тегів |services#Теги] або ввімкнення режиму [inject |services#Режим Inject].

```neon
decorator:
	InjectableInterface:
		tags: [mytag: 1]
		inject: true
```


DI
===

Технічні налаштування DI-контейнера.

```neon
di:
	# показати DI-контейнер у Tracy Bar?
	debugger: ...        # (bool) за замовчуванням true

	# типи параметрів, які ніколи не підключати автоматично
	excluded: ...        # (string[])

	# дозволити ліниве створення сервісів?
	lazy: ...            # (bool) за замовчуванням false

	# клас, від якого успадковується DI-контейнер
	parentClass: ...     # (string) за замовчуванням Nette\DI\Container
```


Lazy-сервіси .{data-version:3.2.4}
----------------------------------

Налаштування `lazy: true` активує ліниве (відкладене) створення сервісів. Це означає, що сервіси не створюються насправді в момент, коли ми їх запитуємо з DI-контейнера, а лише в момент їх першого використання. Це може прискорити запуск програми та зменшити споживання пам'яті, оскільки створюються лише ті сервіси, які дійсно потрібні в даному запиті.

Для конкретного сервісу ліниве створення можна [змінити |services#Lazy-сервіси].

.[note]
Ліниві об'єкти можна використовувати лише для користувацьких класів, а не для внутрішніх класів PHP. Потребує PHP 8.4 або новішої версії.


Експорт метаданих
-----------------

Клас DI-контейнера містить також багато метаданих. Ви можете зменшити його розмір, скоротивши експорт метаданих.

```neon
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`.

Ви можете значно скоротити метадані для [автоматичного підключення|autowiring], вказавши класи, які ви використовуєте як параметр методу `$container->getByType()`. І знову ж таки, якщо ви взагалі не викликаєте цей метод (або лише в [bootstrap|application:bootstrapping] для отримання `Nette\Application\Application`), ви можете повністю вимкнути експорт за допомогою `false`.


Розширення
==========

Реєстрація додаткових DI-розширень. Таким чином додамо, наприклад, DI-розширення `Dibi\Bridges\Nette\DibiExtension22` під назвою `dibi`.

```neon
extensions:
	dibi: Dibi\Bridges\Nette\DibiExtension22
```

Потім ми конфігуруємо його в секції `dibi`:

```neon
dibi:
	host: localhost
```

Як розширення можна додати і клас, який має параметри:

```neon
extensions:
	application: Nette\Bridges\ApplicationDI\ApplicationExtension(%debugMode%, %appDir%, %tempDir%/cache)
```


Включення файлів
================

Додаткові конфігураційні файли можна включити в секції `includes`:

```neon
includes:
	- parameters.php
	- services.neon
	- presenters.neon
```

Назва `parameters.php` не є помилкою, конфігурація може бути записана також у PHP-файлі, який поверне її як масив:

```php
<?php
return [
	'database' => [
		'main' => [
			'dsn' => 'sqlite::memory:',
		],
	],
];
```

Якщо в конфігураційних файлах з'являться елементи з однаковими ключами, вони будуть перезаписані, або у випадку [масивів об'єднані |#Об єднання]. Файл, що включається пізніше, має вищий пріоритет, ніж попередній. Файл, у якому вказана секція `includes`, має вищий пріоритет, ніж файли, що включаються в ньому.


Search
======

Автоматичне додавання сервісів до DI-контейнера надзвичайно полегшує роботу. Nette автоматично додає до контейнера presenter'и, але можна легко додавати й будь-які інші класи.

Достатньо вказати, у яких каталогах (та підкаталогах) слід шукати класи:

```neon
search:
	-	in: %appDir%/Forms
	-	in: %appDir%/Model
```

Зазвичай, однак, ми не хочемо додавати абсолютно всі класи та інтерфейси, тому їх можна фільтрувати:

```neon
search:
	-	in: %appDir%/Forms

		# фільтрація за назвою файлу (string|string[])
		files:
			- *Factory.php

		# фільтрація за назвою класу (string|string[])
		classes:
			- *Factory
```

Або ми можемо вибирати класи, які успадковують або реалізують принаймні один із зазначених класів:


```neon
search:
	-	in: %appDir%
		extends:
			- App\*Form
		implements:
			- App\*FormInterface
```

Можна визначити і правила виключення, тобто маски назви класу або предків, які, якщо відповідають, сервіс не додається до DI-контейнера:

```neon
search:
	-	in: %appDir%
		exclude:
			files: ...
			classes: ...
			extends: ...
			implements: ...
```

Усім сервісам можна встановити теги:

```neon
search:
	-	in: %appDir%
		tags: ...
```


Об'єднання
==========

Якщо у кількох конфігураційних файлах з'являться елементи з однаковими ключами, вони будуть перезаписані, або у випадку масивів об'єднані. Файл, що включається пізніше, має вищий пріоритет, ніж попередній.

<table class=table>
<tr>
	<th width=33%>config1.neon</th>
	<th width=33%>config2.neon</th>
	<th>результат</th>
</tr>
<tr>
	<td>
```neon
items:
	- 1
	- 2
```
	</td>
	<td>
```neon
items:
	- 3
```
	</td>
	<td>
```neon
items:
	- 1
	- 2
	- 3
```
	</td>
</tr>
</table>

Для масивів можна запобігти об'єднанню, вказавши знак оклику після назви ключа:

<table class=table>
<tr>
	<th width=33%>config1.neon</th>
	<th width=33%>config2.neon</th>
	<th>результат</th>
</tr>
<tr>
	<td>
```neon
items:
	- 1
	- 2
```
	</td>
	<td>
```neon
items!:
	- 3
```
	</td>
	<td>
```neon
items:
	- 3
```
	</td>
</tr>
</table>

{{maintitle: Конфігурація Dependency Injection}}

Конфігурація 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, має вищий пріоритет, ніж файли, що включаються в ньому.

Автоматичне додавання сервісів до 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 результат
items:
	- 1
	- 2
items:
	- 3
items:
	- 1
	- 2
	- 3

Для масивів можна запобігти об'єднанню, вказавши знак оклику після назви ключа:

config1.neon config2.neon результат
items:
	- 1
	- 2
items!:
	- 3
items:
	- 3