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%)
negationbool(%arg%)
verlustfreie Umwandlung in boolint(%arg%)
verlustfreie Umwandlung in intfloat(%arg%)
verlustfreie Umwandlung in floatstring(%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