Конфигурация 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
версия: 3.x