Konfiguracja kontenera DI

Przegląd opcji konfiguracyjnych kontenera Nette DI.

Plik konfiguracyjny

Kontenerem Nette DI łatwo steruje się za pomocą plików konfiguracyjnych. Zapisywane są one zwykle w formacie NEON. Zalecamy używanie edytorów z jego obsługą.

 decorator: 	Dekorator
di: Kontener DI
extensions: Instalacja dodatkowych rozszerzeń DI
includes: Dołączanie plików
parameters: Parametry
search: Automatyczna rejestracja usług
services: Usługi

Aby zapisać string zawierający znak %, musisz go zescapować, podwajając na %%.

Parametry

W konfiguracji możesz zdefiniować parametry, których można potem używać jako części definicji usług. Pozwala to uczynić konfigurację czytelniejszą albo scentralizować wartości, które mogą się zmieniać.

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

Do parametru dsn odwołujemy się w dowolnym miejscu konfiguracji zapisem %dsn%. Parametrów można używać również wewnątrz stringów, jak '%wwwDir%/images'.

Parametry nie muszą być tylko stringami czy liczbami, mogą zawierać również tablice:

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

Do konkretnego klucza odwołujemy się jako %mailer.user%.

Jeśli Twój kod (np. klasa) potrzebuje wartości parametru, przekaż mu ją. Na przykład w konstruktorze. Nie istnieje globalny obiekt konfiguracji, którego klasy mogłyby pytać o wartości parametrów. Byłoby to złamanie zasady wstrzykiwania zależności.

Usługi

Zobacz osobny rozdział.

Dekorator

Jak zmodyfikować naraz wiele usług określonego typu? Na przykład jak wywołać konkretną metodę na wszystkich presenterach dziedziczących po określonej klasie bazowej? Od tego jest dekorator.

decorator:
	# dla wszystkich usług będących instancjami tej klasy albo interfejsu
	App\Presentation\BasePresenter:
		setup:
			- setProjectId(10)       # wywołaj tę metodę
			- $absoluteUrls = true   # i ustaw zmienną

Dekoratora można też używać do ustawiania tagów albo włączania trybu inject.

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

DI

Ustawienia techniczne kontenera DI.

di:
	# pokazywać DIC w pasku Tracy?
	debugger: ...        # (bool) domyślnie autodetekcja (włączone, gdy Tracy jest obecne)

	# typy parametrów, których nigdy nie autowirujesz
	excluded: ...        # (string[])

	# włączyć leniwe tworzenie usług?
	lazy: ...            # (bool) domyślnie false

	# klasa, po której dziedziczy kontener DI
	parentClass: ...     # (string) domyślnie Nette\DI\Container

Usługi leniwe

Ustawienie lazy: true aktywuje leniwe (odroczone) tworzenie usług. Oznacza to, że usługi nie są faktycznie tworzone w chwili, gdy prosisz o nie kontener DI, lecz dopiero przy ich pierwszym użyciu. Może to przyspieszyć start aplikacji i zmniejszyć zużycie pamięci, bo tworzone są tylko usługi faktycznie potrzebne dla danego żądania.

Dla konkretnej usługi leniwe tworzenie można dostosować.

Obiektów leniwych można używać tylko dla klas zdefiniowanych przez użytkownika, nie dla wewnętrznych klas PHP. Wymaga PHP 8.4 lub nowszego.

Eksport metadanych

Klasa kontenera DI zawiera również sporo metadanych. Możesz zmniejszyć jej rozmiar, ograniczając eksport metadanych.

di:
	export:
		# eksportować parametry?
		parameters: false   # (bool) domyślnie true

		# eksportować tagi i które?
		tags:               # (string[]|bool) domyślnie wszystkie
			- event.subscriber

		# eksportować dane do autowiringu i które?
		types:              # (string[]|bool) domyślnie wszystkie
			- Nette\Database\Connection
			- Symfony\Component\Console\Application

Jeśli nie używasz $container->getParameters(), możesz wyłączyć eksport parametrów. Ponadto możesz eksportować tylko te tagi, których faktycznie używasz do pobierania usług przez $container->findByTag(...). Jeśli w ogóle nie wywołujesz tej metody, możesz całkowicie wyłączyć eksport tagów przez false.

Możesz znacząco ograniczyć metadane dla autowiringu, wymieniając tylko te klasy, o które faktycznie prosisz przez $container->getByType(). Znów: jeśli nie wywołujesz tej metody (albo wywołujesz ją tylko w pliku bootstrap, np. aby uzyskać Nette\Application\Application), możesz całkowicie wyłączyć eksport typów przez false.

Rozszerzenia

Rejestracja dodatkowych rozszerzeń DI. Tak dodasz na przykład rozszerzenie DI Dibi\Bridges\Nette\DibiExtension3 pod nazwą dibi:

extensions:
	dibi: Dibi\Bridges\Nette\DibiExtension3

Konfigurujesz je potem w sekcji dibi:

dibi:
	host: localhost

Jako rozszerzenie możesz też dodać klasę z parametrami:

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

Dołączanie plików

Kolejne pliki konfiguracyjne można dołączyć w sekcji includes:

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

Nazwa parameters.php nie jest literówką; konfigurację można zapisać także w pliku PHP, który zwraca ją jako tablicę:

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

Jeśli elementy o tych samych kluczach pojawią się w kilku plikach konfiguracyjnych, zostaną nadpisane albo, w przypadku tablic, scalone. Plik dołączony później ma wyższy priorytet niż poprzedni. Plik, w którym wymieniona jest sekcja includes, ma wyższy priorytet niż pliki w nim dołączone.

Automatyczna rejestracja usług w kontenerze DI znacząco upraszcza pracę. Nette automatycznie dodaje do kontenera presentery, ale równie łatwo dodasz dowolne inne klasy.

Wystarczy podać, w których katalogach (i podkatalogach) mają być wyszukiwane klasy:

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

Jeśli potrzebujesz tylko jednej reguły wyszukiwania, możesz pominąć listę i zapisać jej klucze bezpośrednio pod search:

search:
	in: %appDir%

Zwykle jednak nie chcemy dodawać absolutnie wszystkich klas i interfejsów, więc możemy je filtrować:

search:
	-	in: %appDir%/Forms

		# filtrowanie po nazwie pliku (string|string[])
		files:
			- *Factory.php

		# filtrowanie po nazwie klasy (string|string[])
		classes:
			- *Factory

Albo możemy wybrać klasy, które dziedziczą po co najmniej jednej z wymienionych klas albo ją implementują:

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

Możesz też zdefiniować reguły wykluczające za pomocą masek nazw klas albo przodków. Jeśli klasa pasuje do reguły wykluczającej, nie zostanie dodana do kontenera DI:

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

Wszystkim automatycznie zarejestrowanym usługom można przypisać tagi:

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

Poza klasami search rejestruje również interfejsy mające jedną metodę create() albo get() – jako generowane fabryki albo akcesory. Klasy, dla których w kontenerze zarejestrowana jest już usługa tego samego typu, są pomijane, więc nie powstają duplikaty.

Scalanie

Jeśli elementy o tych samych kluczach pojawią się w kilku plikach konfiguracyjnych, zostaną nadpisane albo, w przypadku tablic, scalone. Plik dołączony później ma wyższy priorytet niż poprzedni.

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

Dla tablic scalaniu można zapobiec, dodając po nazwie klucza wykrzyknik:

config1.neon config2.neon wynik
items:
	- 1
	- 2
items!:
	- 3
items:
	- 3
wersja: 3.x