Nette Documentation Preview

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

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


Файл конфигурации
=================

DI-контейнер Nette легко управляется с помощью файлов конфигурации. Они обычно записываются в [формате 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
=========

Как массово изменить все сервисы определенного типа? Например, вызвать определенный метод у всех презентеров, которые наследуются от конкретного общего предка? Для этого существует 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
```


Ленивые сервисы .{data-version:3.2.4}
-------------------------------------

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

Для конкретного сервиса ленивое создание можно [изменить |services#Ленивые сервисы].

.[note]
Ленивые объекты можно использовать только для пользовательских классов, а не для внутренних классов PHP. Требуется PHP 8.4 или новее.


Экспорт метаданных
------------------

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

```neon
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 |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 автоматически добавляет в контейнер презентеры, но можно легко добавлять и любые другие классы.

Достаточно указать, в каких каталогах (и подкаталогах) следует искать классы:

```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-контейнера

Обзор опций конфигурации для DI-контейнера Nette.

Файл конфигурации

DI-контейнер Nette легко управляется с помощью файлов конфигурации. Они обычно записываются в формате 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.

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: true активирует ленивое (отложенное) создание сервисов. Это означает, что сервисы не создаются в момент, когда мы запрашиваем их из DI-контейнера, а только в момент их первого использования. Это может ускорить запуск приложения и снизить потребление памяти, поскольку создаются только те сервисы, которые действительно необходимы в данном запросе.

Для конкретного сервиса ленивое создание можно изменить.

Ленивые объекты можно использовать только для пользовательских классов, а не для внутренних классов 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, имеет более высокий приоритет, чем включенные в нем файлы.

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

Для массивов можно предотвратить слияние, указав восклицательный знак после имени ключа:

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