Konfiguration des DI-Containers

Übersicht der Konfigurationsmöglichkeiten für den Nette DI Container.

Konfigurationsdatei

Der Nette DI Container lässt sich bequem über Konfigurationsdateien steuern. Diese werden üblicherweise im Format NEON geschrieben. Wir empfehlen, Editoren mit Unterstützung für dieses Format zu verwenden.

 decorator: 	Decorator
di: DI-Container
extensions: Weitere DI-Extensions installieren
includes: Dateien einbinden
parameters: Parameter
search: Automatische Registrierung von Services
services: Services

Um einen String zu schreiben, der das Zeichen % enthält, müssen Sie es durch Verdoppeln zu %% escapen.

Parameter

In der Konfiguration können Sie Parameter definieren, die sich anschließend als Teil der Service-Definitionen verwenden lassen. So machen Sie die Konfiguration übersichtlicher oder führen Werte an einer Stelle zusammen, die sich ändern können.

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

Auf den Parameter dsn verweisen wir überall in der Konfiguration mit der Schreibweise %dsn%. Parameter lassen sich auch innerhalb von Strings verwenden, etwa '%wwwDir%/images'.

Parameter müssen nicht nur Strings oder Zahlen sein, sie können auch Arrays enthalten:

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

Auf einen bestimmten Schlüssel verweisen wir mit %mailer.user%.

Wenn Ihr Code (etwa eine Klasse) den Wert eines Parameters braucht, übergeben Sie ihn der Klasse. Zum Beispiel im Konstruktor. Es gibt kein globales Konfigurationsobjekt, das Klassen nach Werten von Parametern fragen könnten. Das wäre ein Verstoß gegen das Prinzip der Dependency Injection.

Services

Siehe eigenes Kapitel.

Decorator

Wie ändern Sie mehrere Services eines bestimmten Typs auf einmal? Wie rufen Sie zum Beispiel auf allen Presentern, die von einer bestimmten Basisklasse erben, eine bestimmte Methode auf? Dafür ist der Decorator da.

decorator:
	# für alle Services, die Instanzen dieser Klasse oder dieses Interfaces sind
	App\Presentation\BasePresenter:
		setup:
			- setProjectId(10)       # diese Methode aufrufen
			- $absoluteUrls = true   # und die Variable setzen

Der Decorator lässt sich auch verwenden, um Tags zu setzen oder den Inject-Modus einzuschalten.

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

DI

Technische Einstellungen des DI-Containers.

di:
	# den DIC in der Tracy Bar anzeigen?
	debugger: ...        # (bool) standardmäßig automatische Erkennung (eingeschaltet, wenn Tracy vorhanden ist)

	# Typen von Parametern, die Sie nie autowiren
	excluded: ...        # (string[])

	# das lazy Erzeugen von Services einschalten?
	lazy: ...            # (bool) Standard ist false

	# die Klasse, von der der DI-Container erbt
	parentClass: ...     # (string) standardmäßig Nette\DI\Container

Lazy Services

Die Einstellung lazy: true aktiviert das lazy (aufgeschobene) Erzeugen von Services. Das bedeutet, dass Services nicht in dem Moment tatsächlich erzeugt werden, in dem sie beim DI-Container angefordert werden, sondern erst bei ihrer ersten Verwendung. Das kann den Start der Anwendung beschleunigen und den Speicherverbrauch senken, weil nur die Services erzeugt werden, die für den jeweiligen Request wirklich nötig sind.

Für einen bestimmten Service lässt sich das lazy Erzeugen anpassen.

Lazy Objekte lassen sich nur für eigene Klassen verwenden, nicht für interne PHP-Klassen. Erfordert PHP 8.4 oder neuer.

Export der Metadaten

Die Klasse des DI-Containers enthält außerdem eine Menge Metadaten. Sie können ihre Größe verringern, indem Sie den Export der Metadaten einschränken.

di:
	export:
		# Parameter exportieren?
		parameters: false   # (bool) standardmäßig true

		# Tags exportieren, und welche?
		tags:               # (string[]|bool) standardmäßig alle
			- event.subscriber

		# Daten für das Autowiring exportieren, und welche?
		types:              # (string[]|bool) standardmäßig alle
			- Nette\Database\Connection
			- Symfony\Component\Console\Application

Wenn Sie $container->getParameters() nicht verwenden, können Sie den Export der Parameter abschalten. Außerdem können Sie nur die Tags exportieren, die Sie tatsächlich verwenden, um Services über $container->findByTag(...) zu holen. Wenn Sie diese Methode überhaupt nicht aufrufen, können Sie den Export der Tags mit false vollständig abschalten.

Die Metadaten für das Autowiring lassen sich erheblich verkleinern, indem Sie nur die Klassen aufführen, die Sie tatsächlich über $container->getByType() anfordern. Auch hier gilt: Wenn Sie diese Methode nicht aufrufen (oder sie nur in der Datei bootstrap aufrufen, etwa um Nette\Application\Application zu holen), können Sie den Export der Typen mit false vollständig abschalten.

Extensions

Registrierung weiterer DI-Extensions. So fügen Sie zum Beispiel die DI-Extension Dibi\Bridges\Nette\DibiExtension3 unter dem Namen dibi hinzu:

extensions:
	dibi: Dibi\Bridges\Nette\DibiExtension3

Konfiguriert wird sie anschließend im Abschnitt dibi:

dibi:
	host: localhost

Als Extension lässt sich auch eine Klasse mit Parametern hinzufügen:

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

Dateien einbinden

Weitere Konfigurationsdateien lassen sich im Abschnitt includes einbinden:

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

Der Name parameters.php ist kein Tippfehler; die Konfiguration lässt sich auch in eine PHP-Datei schreiben, die sie als Array zurückgibt:

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

Erscheinen Elemente mit denselben Schlüsseln in mehreren Konfigurationsdateien, werden sie überschrieben oder bei Arrays zusammengeführt. Eine später eingebundene Datei hat höhere Priorität als die vorherige. Die Datei, in der der Abschnitt includes steht, hat höhere Priorität als die darin eingebundenen Dateien.

Die automatische Registrierung von Services im DI-Container vereinfacht die Entwicklung erheblich. Nette fügt dem Container die Presenter automatisch hinzu, Sie können aber ebenso leicht beliebige weitere Klassen ergänzen.

Geben Sie einfach an, in welchen Verzeichnissen (und Unterverzeichnissen) nach den Klassen gesucht werden soll:

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

Wenn Sie nur eine einzige Suchregel brauchen, können Sie die Liste weglassen und ihre Schlüssel direkt unter search schreiben:

search:
	in: %appDir%

Üblicherweise wollen wir aber nicht absolut alle Klassen und Interfaces hinzufügen, also können wir sie filtern:

search:
	-	in: %appDir%/Forms

		# Filterung nach Dateiname (string|string[])
		files:
			- *Factory.php

		# Filterung nach Klassenname (string|string[])
		classes:
			- *Factory

Oder wir wählen die Klassen aus, die von mindestens einer der aufgeführten Klassen erben oder eines der Interfaces implementieren:

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

Sie können auch Ausschlussregeln über Masken von Klassennamen oder über Vorfahren definieren. Passt eine Klasse auf eine Ausschlussregel, wird sie dem DI-Container nicht hinzugefügt:

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

Allen automatisch registrierten Services lassen sich Tags zuweisen:

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

Neben Klassen registriert die Suche auch Interfaces, die eine einzige Methode create() oder get() haben – als generierte Factories oder Accessors. Klassen, für die im Container bereits ein Service desselben Typs registriert ist, werden übersprungen, es entstehen also keine Duplikate.

Zusammenführen

Erscheinen Elemente mit denselben Schlüsseln in mehreren Konfigurationsdateien, werden sie überschrieben oder bei Arrays zusammengeführt. Die später eingebundene Datei hat höhere Priorität als die vorherige.

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

Bei Arrays lässt sich das Zusammenführen verhindern, indem hinter den Namen des Schlüssels ein Ausrufezeichen gesetzt wird:

config1.neon config2.neon Ergebnis
items:
	- 1
	- 2
items!:
	- 3
items:
	- 3
Version: 3.x