Definiowanie usług

Konfiguracja to miejsce, w którym umieszczamy nasze niestandardowe definicje usług. Służy do tego sekcja services.

Na przykład w ten sposób tworzymy serwis o nazwie database, który będzie instancją klasy PDO:

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

Nazewnictwo usług służy do odwoływania się do nich. Jeśli usługa nie jest przywoływana, nie musi być nazwana. Więc po prostu używamy wypunktowania zamiast nazwy:

services:
	- PDO('sqlite::memory:') # anonimowa usługa

Wpis jednowierszowy może być rozbity na wiele wierszy, aby umożliwić dodanie innych klawiszy, takich jak konfiguracja. Alias dla klucza create: to factory:.

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

Usługa jest następnie pobierana z kontenera DI za pomocą metody getService() by name lub lepiej getByType() by type:

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

Tworzenie usługi

Najczęściej tworzymy usługę, tworząc po prostu instancję klasy:

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

Co generuje metodę fabryczną w kontenerze DI:

public function createServiceDatabase(): PDO
{
	return new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'secret');
}

Alternatywnie, klucz arguments może być użyty do przekazania argumentów:

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

Metoda statyczna może również tworzyć usługę:

services:
	database: My\Database::create(root, secret)

Odpowiada kodowi PHP:

public function createServiceDatabase(): PDO
{
	return My\Database::create('root', 'secret');
}

Zakłada się, że metoda statyczna My\Database::create() ma zdefiniowaną wartość zwrotną, którą kontener DI musi znać. Jeśli go nie ma, zapisz typ do konfiguracji:

services:
	database:
		create: My\Database::create(root, secret)
		type: PDO

Nette DI daje nam niezwykle potężne środki wyrazu, które możesz wykorzystać do napisania niemal wszystkiego. Na przykład, aby odwołać się do innej usługi i wywołać jej metodę. Dla uproszczenia, zamiast ->, używamy ::

services:
	routerFactory: App\Router\Factory
	router: @routerFactory::create()

Odpowiada kodowi PHP:

public function createServiceRouterFactory(): App\Router\Factory
{
	return new App\Router\Factory;
}

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

Wywołania metod mogą być łączone łańcuchowo, tak jak w PHP:

services:
	foo: FooFactory::build()::get()

Odpowiada kodowi PHP:

public function createServiceFoo()
{
	return FooFactory::build()->get();
}

Argumenty

Parametry nazwane mogą być również używane do przekazywania argumentów:

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

Przy dzieleniu argumentów na wiele linii, użycie przecinków jest opcjonalne.

Oczywiście jako argumenty mogą być użyte inne usługi lub parametry:

services:
	- Foo(@anotherService, %appDir%)

Odpowiada kodowi PHP:

public function createService01(): Foo
{
	return new Foo($this->getService('anotherService'), '...');
}

Jeśli pierwszy argument ma być autowpisywany, a chcemy dołączyć drugi argument, to pomijamy pierwszy argument za pomocą _, tedy např. Foo(_, %appDir%). Albo jeszcze lepiej, po prostu przekaż drugi argument jako nazwany parametr, np. Foo(path: %appDir%).

Nette DI i format NEON dają nam niezwykle potężne zasoby ekspresyjne, które można wykorzystać do napisania niemal wszystkiego. Tak więc argumentem może być nowo utworzony obiekt, można wywoływać metody statyczne, metody innych serwisów, a nawet funkcje globalne przy użyciu specjalnej notacji:

services:
	analyser: My\Analyser(
		FilesystemIterator(%appDir%)         # vytvoření objektu
		DateTime::createFromFormat('Y-m-d')  # volání statické metody
		@anotherService		                 # předání jiné služby
		@http.request::getRemoteAddress()    # volání metody jiné služby
		::getenv(NetteMode)                  # volání globální funkce
	)

Odpowiada on kodowi PHP:

public function createServiceAnalyser(): My\Analyser
{
	return new My\Analyser(
		new FilesystemIterator('...'),
		DateTime::createFromFormat('Y-m-d'),
		$this->getService('anotherService'),
		$this->getService('http.request')->getRemoteAddress(),
		getenv('NetteMode')
	);
}

Funkcje specjalne

Możesz również użyć specjalnych funkcji w argumentach, aby zastąpić lub zanegować wartości:

  • not(%arg%) negacja
  • bool(%arg%) lossless override to bool
  • int(%arg%) bezstratne przepisywanie na int
  • float(%arg%) bezstratny reflow do float
  • string(%arg%) bezstratne przepisywanie na ciąg znaków
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Bezstratne repartycjonowanie różni się od normalnego repartycjonowania PHP, np. przy użyciu (int), tym, że rzuca wyjątek dla wartości nienumerycznych.

Jako argumenty można przekazać wiele usług. Tablicę wszystkich usług danego typu (tj. klasy lub interfejsu) tworzy funkcja typed(). Funkcja pomija usługi, które mają wyłączone autowiring, można podać wiele typów oddzielonych przecinkami.

services:
	- BarsDependent( typed(Bar) )

Możesz również przekazać tablicę usług automatycznie za pomocą autowiring.

Funkcja tagged() tworzy tablicę wszystkich usług z określonym tagiem. Można również podać wiele tagów oddzielonych przecinkiem.

services:
	- LoggersDependent( tagged(logger) )

Usługi odsyłania

Do usług odwołujemy się za pomocą nazwy usługi i nazwy serwisu, więc na przykład @database:

services:
	- create: Foo(@database)
	  setup:
			- setCacheStorage(@cache.storage)

Odpowiada kodowi PHP:

public function createService01(): Foo
{
	$service = new Foo($this->getService('database'));
	$service->setCacheStorage($this->getService('cache.storage'));
	return $service;
}

Nawet anonimowe usługi mogą być przywoływane poprzez alias, wystarczy podać typ (klasa lub interfejs) zamiast nazwy. Zwykle jednak nie jest to konieczne ze względu na autowiring.

services:
	- create: Foo(@Nette\Database\Connection)  # nebo třeba @PDO.
	  setup:
			- setCacheStorage(@cache.storage)

Ustawienie

W sekcji setup znajduje się lista metod, które należy wywołać podczas tworzenia usługi:

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

Odpowiada kodowi PHP:

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

Można również ustawić wartości zmienne. Dodawanie elementu do tablicy jest również obsługiwane, ale musi być napisane w cudzysłowie, aby uniknąć konfliktu ze składnią NEON:

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

Odpowiada kodowi PHP:

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

Jednak metody statyczne lub metody innych usług mogą być wywoływane w konfiguracji. Rzeczywista usługa jest przekazywana do nich jako @self:

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

Odpowiada kodowi PHP:

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

Autowiring

Możesz użyć klucza autowired, aby wykluczyć usługę z autowiring lub wpłynąć na jej zachowanie. Więcej informacji można znaleźć w rozdziale dotyczącym autowiring.

services:
	foo:
		create: Foo
		autowired: false # service foo jest wyłączony z autowiring

Tagi

Informacje o użytkownikach mogą być dodawane do poszczególnych serwisów w postaci tagów:

services:
	foo:
		create: Foo
		tags:
			- cached

Tagi mogą mieć również wartość:

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

Możesz przekazać tablicę usług z określonymi tagami jako argument za pomocą funkcji tagged(). Możesz określić wiele tagów oddzielonych przecinkami.

services:
	- LoggersDependent( tagged(logger) )

Nazwy usług można pobrać z kontenera DI za pomocą metody findByTag():

$names = $container->findByTag('logger');
// $names jest tablicą zawierającą nazwę serwisu i wartość tagu
// np. ['foo' => 'monolog.logger.event', ...]

Tryb wtrysku

Flaga inject: true służy do aktywowania przekazywania zależności poprzez zmienne publiczne z adnotacją inject i metodami inject*().

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

Domyślnie strona inject jest aktywowana tylko dla prezenterów.

Modyfikacja usług

Istnieje wiele usług w kontenerze DI, które dodały wbudowane lub twoje rozszerzenia. Definicje tych usług mogą być modyfikowane w konfiguracji. Na przykład dla serwisu application.application, który domyślnie jest obiektem Nette\Application\Application, możemy zmienić klasę:

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

Flaga alteration ma charakter informacyjny i mówi, że właśnie modyfikujemy istniejącą usługę.

Możemy również dodać ustawienie:

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

Podczas przepisywania usługi możemy chcieć usunąć oryginalne argumenty, elementy ustawień lub tagi, do czego służy reset:

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

Usługa dodana przez rozszerzenie może być również usunięta z kontenera:

services:
	cache.journal: false
wersja: 3.x