Настройка DI-контейнера

Обзор вариантов конфигурации контейнера Nette DI.

Контейнером Nette DI легко управлять с помощью конфигурационных файлов. Обычно они записываются в формате NEON format. Мы рекомендуем использовать редактирования таких файлов редакторы с поддержкой этого формата.

 decorator: 	Decorator
di: DI Container
extensions: Install additional DI extensions
includes: Including files
parameters: Parameters
search: Automatic service registration
services: Services

Чтобы записать строку, содержащую символ %, вы должны экранировать его удвоением до %%.

Параметры

Можно задать параметры, которые затем могут быть использованы в качестве части определения сервиса. Это может помочь разделить значения, которые вы хотите изменять более регулярно:

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

В любом конфигурационном файле можно ссылаться на параметр foo через %foo% в другом месте. Они также могут использоваться внутри строк, таких как '%wwwDir%/images'.

Параметры не должны быть только строками, они могут быть также значениями массива:

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

Можно ссылаться на отдельный ключ так: %mailer.user%.

Если вам нужно получить значение любого параметра в вашем коде, например, в классе, то передайте его этому классу. Например, в конструкторе. Не существует глобального объекта конфигурации, который мог бы запрашивать значения параметров. Это противоречит принципу внедрения зависимостей.

Сервисы

См. отдельную главу.

Декоратор

Как массово редактировать все сервисы определенного типа? Нужно вызвать определенный метод для всех презентеров, наследующих от определенного общего предка? Вот откуда берется декоратор:

decorator:
	# Для всех сервисов, являющихся экземплярами этого класса или интерфейса
	App\Presenters\BasePresenter:
		setup:
			- setProjectId(10)       # вызываем этот метод
			- $absoluteUrls = true   # и задаем переменную

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

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

DI

Технические настройки контейнера DI:

di:
	# отображать DIC в панели отладки Tracy?
	debugger: ...        # (bool) по умолчанию true

	# типы параметров, которые не нужно монтировать автоматически
	excluded: ...        # (string[])

	# класс, от которого наследуется контейнер DI
	parentClass: ...     # (string) по умолчанию Nette\DI\Container

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

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

di:
	export:
		# экспортировать параметры
		parameters: false   # (bool) по умолчанию true

		# экспортировать теги
		tags:               # (string[]|bool) по умолчанию все
			- event.subscriber

		# экспортировать данные для автоматического подключения
		types:              # (string[]|bool) по умолчанию все
			- Nette\Database\Connection
			- Symfony\Component\Console\Application

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

Просто укажите, в каких каталогах (и подкаталогах) следует искать классы:

search:
	# вы сами выбираете названия секций
	myForms:
		in: %appDir%/Forms

	model:
		in: %appDir%/Model

Обычно, однако, мы не хотим добавлять все классы и интерфейсы, поэтому мы можем отфильтровать их:

search:
	myForms:
		in: %appDir%/Forms

		# фильтрация по имени файла (string|string[])
		files:
			- *Factory.php

		# фильтрация по имени класса (string|string[])
		classes:
			- *Factory

Или мы можем выбрать классы, которые наследуют или реализуют хотя бы один из следующих классов:

search:
	myForms:
		extends:
			- App\*Form
		implements:
			- App\*FormInterface

Вы также можете определить негативные правила, т. е. маски имён классов или предков, и если они соответствуют требованиям, сервис не будет добавлен в контейнер DI:

search:
	myForms:
		exclude:
			classes: ...
			extends: ...
			implements: ...

Для дополнительных сервисов можно определить теги:

search:
	myForms:
		tags: ...

Объединение

Если элементы с одинаковыми ключами появляются в нескольких конфигурационных файлах, они будут перезаписаны или объединены в случае массивов. Более поздний включенный файл имеет более высокий приоритет.

config1.neon config2.neon result
items:
	- 1
	- 2
items:
	- 3
items:
	- 1
	- 2
	- 3

Чтобы предотвратить объединение определенного массива, используйте восклицательный знак сразу после имени массива:

config1.neon config2.neon result
items:
	- 1
	- 2
items!:
	- 3
items:
	- 3