Nette Documentation Preview

syntax
Definiowanie usług
******************

.[perex]
W konfiguracji instruujemy kontener DI, jak ma tworzyć poszczególne usługi i jak łączyć je z ich zależnościami. Nette oferuje na to bardzo przejrzysty i elegancki sposób.

Sekcja `services` w pliku konfiguracyjnym NEON to miejsce, w którym definiujemy własne usługi i ich konfigurację. Spójrzmy na prosty przykład definiujący usługę o nazwie `database`, reprezentującą instancję klasy `PDO`:

```neon
services:
	database: PDO('sqlite::memory:')
```

Powyższa konfiguracja daje w [kontenerze DI|container] następującą metodę fabryczną:

```php
public function createServiceDatabase(): PDO
{
	return new PDO('sqlite::memory:');
}
```

Nazwy usług pozwalają odwoływać się do nich w innych częściach pliku konfiguracyjnego, w formacie `@nazwaUsługi`. Jeśli nie ma potrzeby nadawania usłudze nazwy, możemy po prostu użyć myślnika (`-`):

```neon
services:
	- PDO('sqlite::memory:')
```

Aby pobrać usługę z kontenera DI, możemy użyć metody `getService()` z nazwą usługi jako parametrem albo metody `getByType()` z typem usługi:

```php
$database = $container->getService('database');
$database = $container->getByType(PDO::class);
```


Tworzenie usługi
================

Zwykle tworzymy usługę po prostu przez utworzenie instancji konkretnej klasy. Na przykład:

```neon
services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
```

Jeśli potrzebujemy rozbudować konfigurację o kolejne klucze, definicję można rozbić na wiele wierszy:

```neon
services:
	database:
		create: PDO('sqlite::memory:')
		setup: ...
```

Klucz `create` ma alias `factory`; oba warianty są powszechnie używane. Zalecamy jednak `create`.

Argumenty konstruktora albo metody fabrycznej można alternatywnie podać kluczem `arguments`:

```neon
services:
	database:
		create: PDO
		arguments: ['mysql:host=127.0.0.1;dbname=test', root, secret]
```

Usługi nie muszą powstawać przez zwykłe utworzenie instancji klasy; mogą też być wynikiem wywołania metod statycznych albo metod innych usług:

```neon
services:
	database: DatabaseFactory::create()
	router: @routerFactory::create()
```

Zwróć uwagę, że dla uproszczenia zamiast `->` używa się `::`, zobacz [#Język wyrażeń]. Wygenerowane zostaną takie metody fabryczne:

```php
public function createServiceDatabase(): PDO
{
	return DatabaseFactory::create();
}

public function createServiceRouter(): RouteList
{
	return $this->getService('routerFactory')->create();
}
```

Kontener DI musi znać typ tworzonej usługi. Jeśli tworzymy usługę metodą, która nie ma podanego typu zwracanego, musimy podać ten typ jawnie w konfiguracji:

```neon
services:
	database:
		create: DatabaseFactory::create()
		type: PDO
```


Argumenty
=========

Argumenty do konstruktorów i metod przekazujemy bardzo podobnie jak w samym PHP:

```neon
services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
```

Dla lepszej czytelności możemy wypisać argumenty w osobnych wierszach. W takim przypadku używanie przecinków staje się opcjonalne:

```neon
services:
	database: PDO(
		'mysql:host=127.0.0.1;dbname=test'
		root
		secret
	)
```

Argumenty możesz też nazwać, dzięki czemu nie musisz przejmować się ich kolejnością:

```neon
services:
	database: PDO(
		username: root
		password: secret
		dsn: 'mysql:host=127.0.0.1;dbname=test'
	)
```

Jeśli chcesz pominąć niektóre argumenty i użyć ich wartości domyślnych albo pozwolić, aby usługa została wstrzyknięta przez [autowiring|autowiring], użyj podkreślenia (`_`):

```neon
services:
	foo: Foo(_, %appDir%)
```

Argumenty mogą zawierać usługi, parametry i wiele więcej, zobacz [#Język wyrażeń].


Setup
=====

W sekcji `setup` definiujemy metody, które mają zostać wywołane przy tworzeniu usługi.

```neon
services:
	database:
		create: PDO(%dsn%, %user%, %password%)
		setup:
			- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
```

W PHP wyglądałoby to tak:

```php
public function createServiceDatabase(): PDO
{
	$service = new PDO('...', '...', '...');
	$service->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	return $service;
}
```

Poza wywołaniami metod można też przypisywać wartości do właściwości. Obsługiwane jest również dodawanie elementów do tablic, co wymaga ujęcia dostępu do tablicy w cudzysłowy, aby uniknąć konfliktu ze składnią NEON:

```neon
services:
	foo:
		create: Foo
		setup:
			- $value = 123
			- '$onClick[]' = [@bar, clickHandler]
```

W kodzie PHP wyglądałoby to następująco:

```php
public function createServiceFoo(): Foo
{
	$service = new Foo;
	$service->value = 123;
	$service->onClick[] = [$this->getService('bar'), 'clickHandler'];
	return $service;
}
```

W setupie możesz jednak wywoływać również metody statyczne albo metody innych usług. Jeśli potrzebujesz przekazać jako argument samą bieżącą usługę, odwołaj się do niej przez `@self`:

```neon
services:
	foo:
		create: Foo
		setup:
			- My\Helpers::initializeFoo(@self)
			- @anotherService::setFoo(@self)
```

Zwróć uwagę, że dla uproszczenia zamiast `->` używa się `::`, zobacz [#Język wyrażeń]. Wygenerowana zostanie taka metoda fabryczna:

```php
public function createServiceFoo(): Foo
{
	$service = new Foo;
	My\Helpers::initializeFoo($service);
	$this->getService('anotherService')->setFoo($service);
	return $service;
}
```


Język wyrażeń
=============

Nette DI udostępnia wyjątkowo bogaty język wyrażeń, którym możemy zdefiniować niemal wszystko. W plikach konfiguracyjnych możemy więc używać [parametrów |configuration#Parametry]:

```neon
# parametr
%wwwDir%

# wartość parametru pod kluczem
%mailer.user%

# parametr wewnątrz stringa
'%wwwDir%/images'
```

Ponadto tworzyć obiekty, wywoływać metody i funkcje:

```neon
# utworzenie obiektu
DateTime()

# wywołanie metody statycznej
Collator::create(%locale%)

# wywołanie funkcji PHP
::getenv(DB_USER)
```

Odwoływać się do usług po nazwie albo po typie:

```neon
# usługa po nazwie
@database

# usługa po typie
@Nette\Database\Connection
```

Używać składni first-class callable: .{data-version:3.2.0}

```neon
# utworzenie callbacku, odpowiednik [@user, logout]
@user::logout(...)
```

Używać stałych:

```neon
# stała klasowa
FilesystemIterator::SKIP_DOTS

# pobranie stałej globalnej funkcją PHP constant()
::constant(\PHP_VERSION)
```

Sięgać po publiczne właściwości i stałe usługi przez `@service::member`. O tym, czy nazwa oznacza właściwość, czy stałą, decyduje jej pierwsza litera - mała oznacza właściwość publiczną, wielka oznacza stałą:

```neon
# właściwość publiczna usługi (zaczyna się małą literą)
@settings::apiUrl

# stała klasowa usługi (zaczyna się wielką literą)
@settings::Version
```

Wywołania metod można łączyć w łańcuch, tak jak w PHP. Dla uproszczenia zamiast `->` używa się `::`:

```neon
DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')

@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()
```

Wyrażeń tych możesz używać wszędzie: przy [tworzeniu usług |#Tworzenie usługi], w [argumentach |#Argumenty], w sekcji [setup |#Setup] albo w [parametrach |configuration#Parametry]:

```neon
parameters:
	ipAddress: @http.request::getRemoteAddress()

services:
	database:
		create: DatabaseFactory::create( @anotherService::getDsn() )
		setup:
			- initialize( ::getenv('DB_USER') )
```


Funkcje specjalne
-----------------

W plikach konfiguracyjnych możesz używać następujących funkcji specjalnych:

- `not()` neguje wartość
- `bool()`, `int()`, `float()`, `string()` bezstratne rzutowanie na podany typ .{data-version:3.0.5}
- `typed()` tworzy tablicę wszystkich usług podanego typu
- `tagged()` tworzy tablicę wszystkich usług z danym tagiem

```neon
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)
```

W odróżnieniu od standardowego rzutowania PHP, jak `(int)`, rzutowanie bezstratne zgłasza wyjątek dla wartości nieliczbowych.

Funkcja `typed()` tworzy tablicę wszystkich usług podanego typu (klasy albo interfejsu). Pomija usługi z wyłączonym autowiringiem. Można podać również kilka typów, oddzielonych przecinkami.

```neon
services:
	- BarsDependent( typed(Bar) )
```

Tablicę usług określonego typu można też przekazać jako argument automatycznie, za pomocą [autowiringu |autowiring#Kolekcja usług].

Funkcja `tagged()` tworzy z kolei tablicę wszystkich usług z określonym tagiem. Również tutaj możesz podać kilka tagów oddzielonych przecinkami.

```neon
services:
	- LoggersDependent( tagged(logger) )
```


Autowiring
==========

Klucz `autowired` pozwala wpłynąć na zachowanie autowiringu dla konkretnej usługi. Szczegóły znajdziesz w [rozdziale o autowiringu|autowiring].

```neon
services:
	foo:
		create: Foo
		autowired: false     # usługa foo jest wyłączona z autowiringu
```


Usługi leniwe .{data-version:3.2.4}
===================================

Leniwe ładowanie to technika odraczająca utworzenie usługi do chwili, gdy jest ona faktycznie potrzebna. W konfiguracji globalnej możesz [włączyć leniwe tworzenie |configuration#Usługi leniwe] dla wszystkich usług naraz. Dla poszczególnych usług możesz potem to zachowanie nadpisać:

```neon
services:
	foo:
		create: Foo
		lazy: false
```

Gdy usługa jest zdefiniowana jako leniwa, przy prośbie o nią do kontenera DI otrzymujemy specjalny obiekt proxy. Proxy to wygląda i zachowuje się identycznie jak prawdziwa usługa, ale faktyczna inicjalizacja (wywołanie konstruktora i wywołania setupu) następuje dopiero przy pierwszym dostępie do którejkolwiek z jej metod albo właściwości.

Pamiętaj, że skoro usługa tworzona jest później, również błędy w jej konfiguracji ujawniają się później. Na przykład nieprawidłowe poświadczenia bazy danych nie ujawnią się przy starcie aplikacji, lecz dopiero przy pierwszym zapytaniu.

Leniwe tworzenie łagodzi też zależności cykliczne, czyli sytuację, w której usługa A wymaga usługi B, a B jednocześnie wymaga A. Bez niego kontener zgłasza błąd `Circular reference detected`. Z leniwym proxy usługa A otrzymuje tylko proxy usługi B, które inicjalizuje się przy faktycznym użyciu, w momencie, gdy A już istnieje. Mimo to zależność cykliczna sygnalizuje wadliwy projekt i lepiej się jej pozbyć.

.[note]
Leniwe ładowanie wymaga PHP 8.4 lub nowszego i działa tylko dla usług tworzonych przez bezpośrednie utworzenie instancji klasy (np. `create: Foo`), a nie dla tych tworzonych metodą fabryczną. Nie da się go też użyć dla klas, które ostatecznie rozszerzają wewnętrzną klasę PHP. Gdy leniwego ładowania nie da się zastosować, flaga `lazy: true` jest po cichu ignorowana.


Tagi
====

Tagi służą do dodawania usługom dodatkowych informacji. Usłudze możesz przypisać jeden albo więcej tagów:

```neon
services:
	foo:
		create: Foo
		tags:
			- cached
```

Tagi mogą też przechowywać wartości:

```neon
services:
	foo:
		create: Foo
		tags:
			logger: monolog.logger.event
```

Aby pobrać wszystkie usługi powiązane z określonymi tagami, możesz użyć funkcji `tagged()`:

```neon
services:
	- LoggersDependent( tagged(logger) )
```

W kontenerze DI nazwy wszystkich usług z określonym tagiem pobierzesz metodą `findByTag()`:

```php
$names = $container->findByTag('logger');
// $names to tablica z nazwami usług jako kluczami i wartościami tagów jako wartościami
// np. ['foo' => 'monolog.logger.event', ...]
```


Tryb inject
===========

Flaga `inject: true` włącza wstrzykiwanie zależności przez właściwości publiczne z atrybutem [Inject |best-practices:inject-method-attribute#Atrybuty Inject] i metody [inject*() |best-practices:inject-method-attribute#Metody inject*()].

```neon
services:
	articles:
		create: App\Model\Articles
		inject: true
```

Domyślnie tryb `inject` włączony jest tylko dla presenterów.


Modyfikowanie usług
===================

Kontener DI zawiera liczne usługi dodane przez rozszerzenia wbudowane albo [użytkownika|extensions]. Definicje tych istniejących usług możesz modyfikować bezpośrednio w konfiguracji. Możesz na przykład zmienić klasę usługi `application.application`, którą domyślnie jest `Nette\Application\Application`, na inną:

```neon
services:
	application.application:
		create: MyApplication
		alteration: true
```

Flaga `alteration` wskazuje, że jedynie modyfikujemy istniejącą usługę. Działa też jako zabezpieczenie: jeśli modyfikowana usługa nie istnieje, kompilacja kończy się wyjątkiem.

Możemy też uzupełnić setup:

```neon
services:
	application.application:
		create: MyApplication
		alteration: true
		setup:
			- '$onStartup[]' = [@resource, init]
```

Usługi nie musisz identyfikować jej wewnętrzną nazwą - możesz odwołać się do niej przez typ. Poprzedni przykład można zapisać także tak:

```neon
services:
	@Nette\Application\Application:
		create: MyApplication
```

Modyfikując usługę, możemy chcieć usunąć pierwotne argumenty, elementy setupu albo tagi, używając klucza `reset`:

```neon
services:
	application.application:
		create: MyApplication
		alteration: true
		reset:
			arguments: true
			setup: true
			tags: true
```

Jeśli chcesz usunąć usługę dodaną przez rozszerzenie, możesz zrobić to tak:

```neon
services:
	cache.journal: false
```

Definiowanie usług

W konfiguracji instruujemy kontener DI, jak ma tworzyć poszczególne usługi i jak łączyć je z ich zależnościami. Nette oferuje na to bardzo przejrzysty i elegancki sposób.

Sekcja services w pliku konfiguracyjnym NEON to miejsce, w którym definiujemy własne usługi i ich konfigurację. Spójrzmy na prosty przykład definiujący usługę o nazwie database, reprezentującą instancję klasy PDO:

services:
	database: PDO('sqlite::memory:')

Powyższa konfiguracja daje w kontenerze DI następującą metodę fabryczną:

public function createServiceDatabase(): PDO
{
	return new PDO('sqlite::memory:');
}

Nazwy usług pozwalają odwoływać się do nich w innych częściach pliku konfiguracyjnego, w formacie @nazwaUsługi. Jeśli nie ma potrzeby nadawania usłudze nazwy, możemy po prostu użyć myślnika (-):

services:
	- PDO('sqlite::memory:')

Aby pobrać usługę z kontenera DI, możemy użyć metody getService() z nazwą usługi jako parametrem albo metody getByType() z typem usługi:

$database = $container->getService('database');
$database = $container->getByType(PDO::class);

Tworzenie usługi

Zwykle tworzymy usługę po prostu przez utworzenie instancji konkretnej klasy. Na przykład:

services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)

Jeśli potrzebujemy rozbudować konfigurację o kolejne klucze, definicję można rozbić na wiele wierszy:

services:
	database:
		create: PDO('sqlite::memory:')
		setup: ...

Klucz create ma alias factory; oba warianty są powszechnie używane. Zalecamy jednak create.

Argumenty konstruktora albo metody fabrycznej można alternatywnie podać kluczem arguments:

services:
	database:
		create: PDO
		arguments: ['mysql:host=127.0.0.1;dbname=test', root, secret]

Usługi nie muszą powstawać przez zwykłe utworzenie instancji klasy; mogą też być wynikiem wywołania metod statycznych albo metod innych usług:

services:
	database: DatabaseFactory::create()
	router: @routerFactory::create()

Zwróć uwagę, że dla uproszczenia zamiast -> używa się ::, zobacz Język wyrażeń. Wygenerowane zostaną takie metody fabryczne:

public function createServiceDatabase(): PDO
{
	return DatabaseFactory::create();
}

public function createServiceRouter(): RouteList
{
	return $this->getService('routerFactory')->create();
}

Kontener DI musi znać typ tworzonej usługi. Jeśli tworzymy usługę metodą, która nie ma podanego typu zwracanego, musimy podać ten typ jawnie w konfiguracji:

services:
	database:
		create: DatabaseFactory::create()
		type: PDO

Argumenty

Argumenty do konstruktorów i metod przekazujemy bardzo podobnie jak w samym PHP:

services:
	database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)

Dla lepszej czytelności możemy wypisać argumenty w osobnych wierszach. W takim przypadku używanie przecinków staje się opcjonalne:

services:
	database: PDO(
		'mysql:host=127.0.0.1;dbname=test'
		root
		secret
	)

Argumenty możesz też nazwać, dzięki czemu nie musisz przejmować się ich kolejnością:

services:
	database: PDO(
		username: root
		password: secret
		dsn: 'mysql:host=127.0.0.1;dbname=test'
	)

Jeśli chcesz pominąć niektóre argumenty i użyć ich wartości domyślnych albo pozwolić, aby usługa została wstrzyknięta przez autowiring, użyj podkreślenia (_):

services:
	foo: Foo(_, %appDir%)

Argumenty mogą zawierać usługi, parametry i wiele więcej, zobacz Język wyrażeń.

Setup

W sekcji setup definiujemy metody, które mają zostać wywołane przy tworzeniu usługi.

services:
	database:
		create: PDO(%dsn%, %user%, %password%)
		setup:
			- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)

W PHP wyglądałoby to tak:

public function createServiceDatabase(): PDO
{
	$service = new PDO('...', '...', '...');
	$service->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	return $service;
}

Poza wywołaniami metod można też przypisywać wartości do właściwości. Obsługiwane jest również dodawanie elementów do tablic, co wymaga ujęcia dostępu do tablicy w cudzysłowy, aby uniknąć konfliktu ze składnią NEON:

services:
	foo:
		create: Foo
		setup:
			- $value = 123
			- '$onClick[]' = [@bar, clickHandler]

W kodzie PHP wyglądałoby to następująco:

public function createServiceFoo(): Foo
{
	$service = new Foo;
	$service->value = 123;
	$service->onClick[] = [$this->getService('bar'), 'clickHandler'];
	return $service;
}

W setupie możesz jednak wywoływać również metody statyczne albo metody innych usług. Jeśli potrzebujesz przekazać jako argument samą bieżącą usługę, odwołaj się do niej przez @self:

services:
	foo:
		create: Foo
		setup:
			- My\Helpers::initializeFoo(@self)
			- @anotherService::setFoo(@self)

Zwróć uwagę, że dla uproszczenia zamiast -> używa się ::, zobacz Język wyrażeń. Wygenerowana zostanie taka metoda fabryczna:

public function createServiceFoo(): Foo
{
	$service = new Foo;
	My\Helpers::initializeFoo($service);
	$this->getService('anotherService')->setFoo($service);
	return $service;
}

Język wyrażeń

Nette DI udostępnia wyjątkowo bogaty język wyrażeń, którym możemy zdefiniować niemal wszystko. W plikach konfiguracyjnych możemy więc używać parametrów:

# parametr
%wwwDir%

# wartość parametru pod kluczem
%mailer.user%

# parametr wewnątrz stringa
'%wwwDir%/images'

Ponadto tworzyć obiekty, wywoływać metody i funkcje:

# utworzenie obiektu
DateTime()

# wywołanie metody statycznej
Collator::create(%locale%)

# wywołanie funkcji PHP
::getenv(DB_USER)

Odwoływać się do usług po nazwie albo po typie:

# usługa po nazwie
@database

# usługa po typie
@Nette\Database\Connection

Używać składni first-class callable:

# utworzenie callbacku, odpowiednik [@user, logout]
@user::logout(...)

Używać stałych:

# stała klasowa
FilesystemIterator::SKIP_DOTS

# pobranie stałej globalnej funkcją PHP constant()
::constant(\PHP_VERSION)

Sięgać po publiczne właściwości i stałe usługi przez @service::member. O tym, czy nazwa oznacza właściwość, czy stałą, decyduje jej pierwsza litera – mała oznacza właściwość publiczną, wielka oznacza stałą:

# właściwość publiczna usługi (zaczyna się małą literą)
@settings::apiUrl

# stała klasowa usługi (zaczyna się wielką literą)
@settings::Version

Wywołania metod można łączyć w łańcuch, tak jak w PHP. Dla uproszczenia zamiast -> używa się :::

DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')

@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()

Wyrażeń tych możesz używać wszędzie: przy tworzeniu usług, w argumentach, w sekcji setup albo w parametrach:

parameters:
	ipAddress: @http.request::getRemoteAddress()

services:
	database:
		create: DatabaseFactory::create( @anotherService::getDsn() )
		setup:
			- initialize( ::getenv('DB_USER') )

Funkcje specjalne

W plikach konfiguracyjnych możesz używać następujących funkcji specjalnych:

  • not() neguje wartość
  • bool(), int(), float(), string() bezstratne rzutowanie na podany typ
  • typed() tworzy tablicę wszystkich usług podanego typu
  • tagged() tworzy tablicę wszystkich usług z danym tagiem
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

W odróżnieniu od standardowego rzutowania PHP, jak (int), rzutowanie bezstratne zgłasza wyjątek dla wartości nieliczbowych.

Funkcja typed() tworzy tablicę wszystkich usług podanego typu (klasy albo interfejsu). Pomija usługi z wyłączonym autowiringiem. Można podać również kilka typów, oddzielonych przecinkami.

services:
	- BarsDependent( typed(Bar) )

Tablicę usług określonego typu można też przekazać jako argument automatycznie, za pomocą autowiringu.

Funkcja tagged() tworzy z kolei tablicę wszystkich usług z określonym tagiem. Również tutaj możesz podać kilka tagów oddzielonych przecinkami.

services:
	- LoggersDependent( tagged(logger) )

Autowiring

Klucz autowired pozwala wpłynąć na zachowanie autowiringu dla konkretnej usługi. Szczegóły znajdziesz w rozdziale o autowiringu.

services:
	foo:
		create: Foo
		autowired: false     # usługa foo jest wyłączona z autowiringu

Usługi leniwe

Leniwe ładowanie to technika odraczająca utworzenie usługi do chwili, gdy jest ona faktycznie potrzebna. W konfiguracji globalnej możesz włączyć leniwe tworzenie dla wszystkich usług naraz. Dla poszczególnych usług możesz potem to zachowanie nadpisać:

services:
	foo:
		create: Foo
		lazy: false

Gdy usługa jest zdefiniowana jako leniwa, przy prośbie o nią do kontenera DI otrzymujemy specjalny obiekt proxy. Proxy to wygląda i zachowuje się identycznie jak prawdziwa usługa, ale faktyczna inicjalizacja (wywołanie konstruktora i wywołania setupu) następuje dopiero przy pierwszym dostępie do którejkolwiek z jej metod albo właściwości.

Pamiętaj, że skoro usługa tworzona jest później, również błędy w jej konfiguracji ujawniają się później. Na przykład nieprawidłowe poświadczenia bazy danych nie ujawnią się przy starcie aplikacji, lecz dopiero przy pierwszym zapytaniu.

Leniwe tworzenie łagodzi też zależności cykliczne, czyli sytuację, w której usługa A wymaga usługi B, a B jednocześnie wymaga A. Bez niego kontener zgłasza błąd Circular reference detected. Z leniwym proxy usługa A otrzymuje tylko proxy usługi B, które inicjalizuje się przy faktycznym użyciu, w momencie, gdy A już istnieje. Mimo to zależność cykliczna sygnalizuje wadliwy projekt i lepiej się jej pozbyć.

Leniwe ładowanie wymaga PHP 8.4 lub nowszego i działa tylko dla usług tworzonych przez bezpośrednie utworzenie instancji klasy (np. create: Foo), a nie dla tych tworzonych metodą fabryczną. Nie da się go też użyć dla klas, które ostatecznie rozszerzają wewnętrzną klasę PHP. Gdy leniwego ładowania nie da się zastosować, flaga lazy: true jest po cichu ignorowana.

Tagi

Tagi służą do dodawania usługom dodatkowych informacji. Usłudze możesz przypisać jeden albo więcej tagów:

services:
	foo:
		create: Foo
		tags:
			- cached

Tagi mogą też przechowywać wartości:

services:
	foo:
		create: Foo
		tags:
			logger: monolog.logger.event

Aby pobrać wszystkie usługi powiązane z określonymi tagami, możesz użyć funkcji tagged():

services:
	- LoggersDependent( tagged(logger) )

W kontenerze DI nazwy wszystkich usług z określonym tagiem pobierzesz metodą findByTag():

$names = $container->findByTag('logger');
// $names to tablica z nazwami usług jako kluczami i wartościami tagów jako wartościami
// np. ['foo' => 'monolog.logger.event', ...]

Tryb inject

Flaga inject: true włącza wstrzykiwanie zależności przez właściwości publiczne z atrybutem Inject i metody inject*().

services:
	articles:
		create: App\Model\Articles
		inject: true

Domyślnie tryb inject włączony jest tylko dla presenterów.

Modyfikowanie usług

Kontener DI zawiera liczne usługi dodane przez rozszerzenia wbudowane albo użytkownika. Definicje tych istniejących usług możesz modyfikować bezpośrednio w konfiguracji. Możesz na przykład zmienić klasę usługi application.application, którą domyślnie jest Nette\Application\Application, na inną:

services:
	application.application:
		create: MyApplication
		alteration: true

Flaga alteration wskazuje, że jedynie modyfikujemy istniejącą usługę. Działa też jako zabezpieczenie: jeśli modyfikowana usługa nie istnieje, kompilacja kończy się wyjątkiem.

Możemy też uzupełnić setup:

services:
	application.application:
		create: MyApplication
		alteration: true
		setup:
			- '$onStartup[]' = [@resource, init]

Usługi nie musisz identyfikować jej wewnętrzną nazwą – możesz odwołać się do niej przez typ. Poprzedni przykład można zapisać także tak:

services:
	@Nette\Application\Application:
		create: MyApplication

Modyfikując usługę, możemy chcieć usunąć pierwotne argumenty, elementy setupu albo tagi, używając klucza reset:

services:
	application.application:
		create: MyApplication
		alteration: true
		reset:
			arguments: true
			setup: true
			tags: true

Jeśli chcesz usunąć usługę dodaną przez rozszerzenie, możesz zrobić to tak:

services:
	cache.journal: false