Dienst-Definitionen

In der Konfiguration werden die Definitionen der benutzerdefinierten Dienste abgelegt. Dies geschieht im Abschnitt services.

So erstellen wir zum Beispiel einen Dienst namens database, der eine Instanz der Klasse PDO sein wird:

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

Die Benennung von Diensten dient dazu, dass wir auf sie verweisen können. Wenn ein Dienst nicht referenziert wird, ist es nicht notwendig, ihn zu benennen. Wir verwenden also einfach einen Aufzählungspunkt anstelle eines Namens:

services:
	- PDO('sqlite::memory:') # anonymer Dienst

Ein einzeiliger Eintrag kann in mehrere Zeilen aufgeteilt werden, um weitere Schlüssel hinzuzufügen, wie z. B. setup. Der Alias für die Taste create: lautet factory:.

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

Anschließend rufen wir den Dienst aus dem DI-Container mit der Methode getService() nach dem Namen oder besser noch mit der Methode getByType() nach dem Typ ab:

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

Erstellen eines Dienstes

Meistens erstellen wir einen Dienst, indem wir einfach eine Instanz einer Klasse erstellen:

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

Dadurch wird eine Fabrikmethode im DI-Container erzeugt:

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

Alternativ kann auch ein Schlüssel arguments verwendet werden, um Argumente zu übergeben:

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

Eine statische Methode kann auch einen Dienst erstellen:

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

Entspricht dem PHP-Code:

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

Bei einer statischen Methode My\Database::create() wird davon ausgegangen, dass sie einen definierten Rückgabewert hat, den der DI-Container kennen muss. Ist dies nicht der Fall, schreiben wir den Typ in die Konfiguration:

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

Nette DI gibt Ihnen extrem leistungsfähige Ausdrucksmöglichkeiten, um fast alles zu schreiben. Zum Beispiel, um auf einen anderen Dienst zu verweisen und seine Methode aufzurufen. Der Einfachheit halber wird :: anstelle von -> verwendet.

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

Entspricht dem PHP-Code:

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

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

Methodenaufrufe können wie in PHP aneinandergereiht werden:

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

Entspricht dem PHP-Code:

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

Argumente

Benannte Parameter können auch zur Übergabe von Argumenten verwendet werden:

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

Die Verwendung von Kommas ist optional, wenn Argumente in mehrere Zeilen aufgeteilt werden.

Natürlich können wir auch andere Dienste oder Parameter als Argumente verwenden:

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

Entspricht dem PHP-Code:

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

Wenn das erste Argument autowired ist und Sie das zweite angeben wollen, lassen Sie das erste mit _ character, for example Foo(_, %appDir%) weg. Oder noch besser, übergeben Sie nur das zweite Argument als benannten Parameter, z. B. Foo(path: %appDir%).

Nette DI und das NEON-Format geben Ihnen extrem leistungsfähige Ausdrucksmöglichkeiten, um fast alles zu schreiben. So kann ein Argument ein neu erstelltes Objekt sein, Sie können statische Methoden, Methoden anderer Dienste oder sogar globale Funktionen unter Verwendung einer speziellen Notation aufrufen:

services:
	analyser: My\Analyser(
		FilesystemIterator(%appDir%)        # Objekt erstellen
		DateTime::createFromFormat('Y-m-d') # statische Methode aufrufen
		@anotherService                     # Übergabe eines anderen Dienstes
		@http.request::getRemoteAddress()   # Aufruf einer anderen Dienstmethode
		::getenv(NetteMode)                 # Aufruf einer globalen Funktion
	)

Entspricht dem PHP-Code:

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')
	);
}

Spezielle Funktionen

Sie können auch spezielle Funktionen in Argumenten verwenden, um Werte zu casten oder zu negieren:

  • not(%arg%) negation
  • bool(%arg%) verlustfreie Umwandlung in bool
  • int(%arg%) verlustfreie Umwandlung in int
  • float(%arg%) verlustfreie Umwandlung in float
  • string(%arg%) lossless cast to string
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Verlustfreies Rewriting unterscheidet sich von normalem PHP Rewriting, z.B. mit (int), dadurch, dass es eine Ausnahme für nicht-numerische Werte auslöst.

Es können mehrere Dienste als Argumente übergeben werden. Ein Array mit allen Diensten eines bestimmten Typs (d.h. Klasse oder Schnittstelle) wird von der Funktion typed() erstellt. Die Funktion lässt Dienste aus, bei denen die automatische Verdrahtung deaktiviert ist, und es können mehrere Typen durch ein Komma getrennt angegeben werden.

services:
	- BarsDependent( typed(Bar) )

Sie können ein Array von Diensten auch automatisch mit Autowiring übergeben.

Ein Array mit allen Diensten mit einem bestimmten Tag wird mit der Funktion tagged() erstellt. Es können mehrere Tags durch ein Komma getrennt angegeben werden.

services:
	- LoggersDependent( tagged(logger) )

Referenzierungsdienste

Die einzelnen Dienste werden mit dem Zeichen @ and name, so for example @database referenziert:

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

Entspricht dem PHP-Code:

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

Auch anonyme Dienste können über einen Callback referenziert werden, man muss nur ihren Typ (Klasse oder Schnittstelle) anstelle ihres Namens angeben. Dies ist jedoch aufgrund der automatischen Verdrahtung normalerweise nicht erforderlich.

services:
	-	create: Foo(@Nette\Database\Connection)
		setup:
			- setCacheStorage(@cache.storage)

Einrichtung

Im Abschnitt “Setup” werden die Methoden aufgeführt, die bei der Erstellung des Dienstes aufgerufen werden müssen:

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

Entspricht dem PHP-Code:

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

Properites können auch gesetzt werden. Das Hinzufügen eines Elements zu einem Array wird ebenfalls unterstützt und sollte in Anführungszeichen geschrieben werden, um nicht mit der NEON-Syntax in Konflikt zu geraten:

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

Entspricht dem PHP-Code:

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

Es können aber auch statische Methoden oder Methoden anderer Dienste im Setup aufgerufen werden. Wir übergeben ihnen den eigentlichen Dienst als @self:

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

Entspricht dem PHP-Code:

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

Autowiring

Der Autowiring-Schlüssel kann verwendet werden, um einen Dienst vom Autowiring auszuschließen oder um sein Verhalten zu beeinflussen. Weitere Informationen finden Sie im Kapitel über Autowiring.

services:
	foo:
		create: Foo
		autowired: false # foo wird aus der automatischen Verdrahtung entfernt

Tags

Benutzerinformationen können den einzelnen Diensten in Form von Tags hinzugefügt werden:

services:
	foo:
		create: Foo
		tags:
			- cached

Tags können auch einen Wert haben:

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

Ein Array von Diensten mit bestimmten Tags kann mit der Funktion tagged() als Argument übergeben werden. Es können auch mehrere Tags durch ein Komma getrennt angegeben werden.

services:
	- LoggersDependent( tagged(logger) )

Dienstnamen können mit der Methode findByTag() aus dem DI-Container bezogen werden:

$names = $container->findByTag('logger');
// $names ist ein Array, das den Dienstnamen und den Tag-Wert enthält
// d.h. ['foo' => 'monolog.logger.event', ...]

Injektionsmodus

Das Flag inject: true wird verwendet, um die Übergabe von Abhängigkeiten über öffentliche Variablen mit der inject-Annotation und den inject*() -Methoden zu aktivieren.

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

Standardmäßig ist inject nur für Präsentatoren aktiviert.

Modifikation der Dienste

Es gibt eine Reihe von Diensten im DI-Container, die durch eine eingebaute oder Ihre Erweiterung hinzugefügt wurden. Die Definitionen dieser Dienste können in der Konfiguration geändert werden. Zum Beispiel kann für den Dienst application.application, der standardmäßig ein Objekt Nette\Application\Application ist, die Klasse geändert werden:

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

Das Kennzeichen alteration ist informativ und besagt, dass wir nur einen bestehenden Dienst ändern.

Wir können auch eine Einrichtung hinzufügen:

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

Wenn wir einen Dienst neu schreiben, möchten wir vielleicht die ursprünglichen Argumente, Setup-Elemente oder Tags entfernen. Dafür ist reset gedacht:

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

Ein durch eine Erweiterung hinzugefügter Dienst kann auch aus dem Container entfernt werden:

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