Nette Documentation Preview

syntax
Définitions des services
************************

.[perex]
La configuration est l'endroit où nous indiquons au conteneur DI comment assembler des services individuels et comment les relier à d'autres dépendances. Nette fournit une méthode très claire et élégante pour y parvenir.

La section `services` du fichier de configuration NEON est l'endroit où nous définissons nos services personnalisés et leurs configurations. Examinons un exemple simple de définition d'un service nommé `database`, qui représente une instance de la classe `PDO`:

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

Cette configuration se traduit par la méthode d'usine suivante dans le [conteneur DI |container]:

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

Les noms des services nous permettent de les référencer dans d'autres parties du fichier de configuration, en utilisant le format `@serviceName`. S'il n'est pas nécessaire de nommer le service, nous pouvons simplement utiliser un point :

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

Pour récupérer un service dans le conteneur DI, nous pouvons utiliser la méthode `getService()` avec le nom du service comme paramètre, ou la méthode `getByType()` avec le type de service :

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


Création de services .[#toc-service-creation]
=============================================

Le plus souvent, nous créons un service en instanciant simplement une classe spécifique. Par exemple, nous pouvons créer un service en instanciant une classe spécifique :

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

Si nous avons besoin d'étendre la configuration avec des clés supplémentaires, la définition peut être développée en plusieurs lignes :

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

La clé `create` a un alias `factory`, les deux versions sont courantes dans la pratique. Cependant, nous recommandons d'utiliser `create`.

Les arguments du constructeur ou la méthode de création peuvent également être écrits dans la clé `arguments`:

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

Les services ne doivent pas nécessairement être créés par la simple instanciation d'une classe ; ils peuvent également résulter de l'appel de méthodes statiques ou de méthodes d'autres services :

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

Notez que pour plus de simplicité, au lieu de `->`, nous utilisons `::`, voir [les moyens d'expression. |#expression means] Ces méthodes d'usine sont générées :

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

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

Le conteneur DI doit connaître le type du service créé. Si nous créons un service en utilisant une méthode qui n'a pas de type de retour spécifié, nous devons explicitement mentionner ce type dans la configuration :

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


Arguments .[#toc-arguments]
===========================

Nous passons des arguments aux constructeurs et aux méthodes d'une manière très similaire à celle de PHP :

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

Pour une meilleure lisibilité, nous pouvons lister les arguments sur des lignes séparées. Dans ce format, l'utilisation des virgules est optionnelle :

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

Vous pouvez également nommer les arguments, ce qui vous permet de ne pas vous soucier de leur ordre :

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

Si vous souhaitez omettre certains arguments et utiliser leurs valeurs par défaut ou insérer un service par [câblage automatique |autowiring], utilisez un trait de soulignement :

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

Les arguments peuvent être des services, des paramètres et bien d'autres choses encore, voir les [moyens d'expression |#expression means].


Configuration .[#toc-setup]
===========================

Dans la section `setup`, nous définissons les méthodes qui doivent être appelées lors de la création du service.

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

En PHP, cela ressemblerait à

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

En plus des appels de méthodes, vous pouvez également passer des valeurs aux propriétés. L'ajout d'un élément à un tableau est également possible, mais vous devez le mettre entre guillemets pour éviter toute collision avec la syntaxe NEON :

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

En PHP, cela se traduirait par :

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

Dans la configuration, vous pouvez également appeler des méthodes statiques ou des méthodes d'autres services. Si vous devez passer le service courant comme argument, utilisez `@self`:

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

Notez que pour plus de simplicité, au lieu de `->`, nous utilisons `::`, voir [les moyens d'expression |#expression means]. Cela génère la méthode d'usine suivante :

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


Moyens d'expression .[#toc-expression-means]
============================================

Nette DI nous offre des capacités d'expression exceptionnellement riches, nous permettant d'articuler presque n'importe quoi. Dans les fichiers de configuration, nous pouvons utiliser des [paramètres |configuration#parameters]:

```neon
# paramètre
%wwwDir%

# valeur sous une clé de paramètre
%mailer.user%

# paramètre dans une chaîne de caractères
'%wwwDir%/images'
```

Nous pouvons également créer des objets, appeler des méthodes et des fonctions :

```neon
# créer un objet
DateTime()

# appeler une méthode statique
Collator::create(%locale%)

# appeler une fonction PHP
::getenv(DB_USER)
```

Faire référence aux services soit par leur nom, soit par leur type :

```neon
# service par nom
@database

# service par type
@Nette\Database\Connection
```

Utiliser une syntaxe d'appel de première classe : .{data-version:3.2.0}

```neon
# creating a callback, equivalent to [@user, logout]
@user::logout(...)
```

Utiliser des constantes :

```neon
# constante de classe
FilesystemIterator::SKIP_DOTS

# constante globale obtenue par la fonction PHP constant()
::constant(PHP_VERSION)
```

Les appels de méthodes peuvent être enchaînés, comme en PHP. Pour simplifier, au lieu de `->`, nous utilisons `::`:

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

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

Ces expressions peuvent être utilisées n'importe où lors de la [création de services |#Service Creation], dans les [arguments |#Arguments], dans la section de [configuration |#setup] ou dans les [paramètres |configuration#parameters]:

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

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


Fonctions spéciales .[#toc-special-functions]
---------------------------------------------

Dans les fichiers de configuration, vous pouvez utiliser ces fonctions spéciales :

- `not()` pour la négation des valeurs
- `bool()`, `int()`, `float()`, `string()` pour le moulage de type sans perte
- `typed()` pour générer un tableau de tous les services d'un type spécifié
- `tagged()` pour créer un tableau de tous les services avec une étiquette donnée

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

Par rapport au typage conventionnel en PHP, comme `(int)`, le typage sans perte lèvera une exception pour les valeurs non numériques.

La fonction `typed()` crée un tableau de tous les services d'un type particulier (classe ou interface). Elle exclut les services dont le câblage automatique est désactivé. Plusieurs types peuvent être spécifiés, séparés par des virgules.

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

Vous pouvez également passer automatiquement un tableau de services d'un type spécifique comme argument en utilisant le [câblage automatique |autowiring#Collection of Services].

La fonction `tagged()` crée un tableau de tous les services ayant une balise spécifiée. Plusieurs balises peuvent être listées, séparées par des virgules.

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


Câblage automobile .[#toc-autowiring]
=====================================

La clé `autowired` permet de modifier le comportement de l'autocâblage pour un service particulier. Pour plus de détails, voir [le chapitre sur |autowiring] l'autocâblage.

```neon
services:
	foo:
		create: Foo
		autowired: false     # le service foo est exclu de l'autocâblage
```


Tags .[#toc-tags]
=================

Les balises sont utilisées pour ajouter des informations supplémentaires aux services. Vous pouvez attribuer une ou plusieurs balises à un service :

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

Les balises peuvent également comporter des valeurs :

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

Pour retrouver tous les services ayant des étiquettes spécifiques, vous pouvez utiliser la fonction `tagged()`:

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

Dans le conteneur DI, vous pouvez obtenir les noms de tous les services avec une étiquette spécifique en utilisant la méthode `findByTag()`:

```php
$names = $container->findByTag('logger');
// $names est un tableau contenant le nom du service et la valeur du tag
// par exemple ['foo' => 'monolog.logger.event', ...]
```


Mode d'injection .[#toc-inject-mode]
====================================

L'utilisation du drapeau `inject: true` active le passage de dépendances via des variables publiques avec l'annotation [inject |best-practices:inject-method-attribute#Inject Attributes] et les méthodes [inject*() |best-practices:inject-method-attribute#inject Methods].

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

Par défaut, `inject` n'est activé que pour les présentateurs.


Modifications du service .[#toc-service-modifications]
======================================================

Le conteneur DI contient de nombreux services ajoutés soit par des [extensions |#extensions] intégrées, soit par des [extensions utilisateur |#extensions]. Vous pouvez modifier les définitions de ces services directement dans la configuration. Par exemple, vous pouvez changer la classe du service `application.application`, qui est conventionnellement `Nette\Application\Application`, en quelque chose d'autre :

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

Le drapeau `alteration` est informatif, indiquant que nous modifions simplement un service existant.

Nous pouvons également compléter la configuration :

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

Lors de l'écrasement d'un service, il se peut que vous souhaitiez supprimer les arguments, les éléments de configuration ou les balises d'origine, et c'est là que `reset` s'avère utile :

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

Si vous souhaitez supprimer un service ajouté par une extension, vous pouvez procéder comme suit :

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

Définitions des services

La configuration est l'endroit où nous indiquons au conteneur DI comment assembler des services individuels et comment les relier à d'autres dépendances. Nette fournit une méthode très claire et élégante pour y parvenir.

La section services du fichier de configuration NEON est l'endroit où nous définissons nos services personnalisés et leurs configurations. Examinons un exemple simple de définition d'un service nommé database, qui représente une instance de la classe PDO:

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

Cette configuration se traduit par la méthode d'usine suivante dans le conteneur DI:

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

Les noms des services nous permettent de les référencer dans d'autres parties du fichier de configuration, en utilisant le format @serviceName. S'il n'est pas nécessaire de nommer le service, nous pouvons simplement utiliser un point :

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

Pour récupérer un service dans le conteneur DI, nous pouvons utiliser la méthode getService() avec le nom du service comme paramètre, ou la méthode getByType() avec le type de service :

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

Création de services

Le plus souvent, nous créons un service en instanciant simplement une classe spécifique. Par exemple, nous pouvons créer un service en instanciant une classe spécifique :

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

Si nous avons besoin d'étendre la configuration avec des clés supplémentaires, la définition peut être développée en plusieurs lignes :

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

La clé create a un alias factory, les deux versions sont courantes dans la pratique. Cependant, nous recommandons d'utiliser create.

Les arguments du constructeur ou la méthode de création peuvent également être écrits dans la clé arguments:

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

Les services ne doivent pas nécessairement être créés par la simple instanciation d'une classe ; ils peuvent également résulter de l'appel de méthodes statiques ou de méthodes d'autres services :

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

Notez que pour plus de simplicité, au lieu de ->, nous utilisons ::, voir les moyens d'expression. Ces méthodes d'usine sont générées :

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

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

Le conteneur DI doit connaître le type du service créé. Si nous créons un service en utilisant une méthode qui n'a pas de type de retour spécifié, nous devons explicitement mentionner ce type dans la configuration :

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

Arguments

Nous passons des arguments aux constructeurs et aux méthodes d'une manière très similaire à celle de PHP :

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

Pour une meilleure lisibilité, nous pouvons lister les arguments sur des lignes séparées. Dans ce format, l'utilisation des virgules est optionnelle :

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

Vous pouvez également nommer les arguments, ce qui vous permet de ne pas vous soucier de leur ordre :

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

Si vous souhaitez omettre certains arguments et utiliser leurs valeurs par défaut ou insérer un service par câblage automatique, utilisez un trait de soulignement :

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

Les arguments peuvent être des services, des paramètres et bien d'autres choses encore, voir les moyens d'expression.

Configuration

Dans la section setup, nous définissons les méthodes qui doivent être appelées lors de la création du service.

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

En PHP, cela ressemblerait à

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

En plus des appels de méthodes, vous pouvez également passer des valeurs aux propriétés. L'ajout d'un élément à un tableau est également possible, mais vous devez le mettre entre guillemets pour éviter toute collision avec la syntaxe NEON :

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

En PHP, cela se traduirait par :

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

Dans la configuration, vous pouvez également appeler des méthodes statiques ou des méthodes d'autres services. Si vous devez passer le service courant comme argument, utilisez @self:

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

Notez que pour plus de simplicité, au lieu de ->, nous utilisons ::, voir les moyens d'expression. Cela génère la méthode d'usine suivante :

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

Moyens d'expression

Nette DI nous offre des capacités d'expression exceptionnellement riches, nous permettant d'articuler presque n'importe quoi. Dans les fichiers de configuration, nous pouvons utiliser des paramètres:

# paramètre
%wwwDir%

# valeur sous une clé de paramètre
%mailer.user%

# paramètre dans une chaîne de caractères
'%wwwDir%/images'

Nous pouvons également créer des objets, appeler des méthodes et des fonctions :

# créer un objet
DateTime()

# appeler une méthode statique
Collator::create(%locale%)

# appeler une fonction PHP
::getenv(DB_USER)

Faire référence aux services soit par leur nom, soit par leur type :

# service par nom
@database

# service par type
@Nette\Database\Connection

Utiliser une syntaxe d'appel de première classe :

# creating a callback, equivalent to [@user, logout]
@user::logout(...)

Utiliser des constantes :

# constante de classe
FilesystemIterator::SKIP_DOTS

# constante globale obtenue par la fonction PHP constant()
::constant(PHP_VERSION)

Les appels de méthodes peuvent être enchaînés, comme en PHP. Pour simplifier, au lieu de ->, nous utilisons :::

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

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

Ces expressions peuvent être utilisées n'importe où lors de la création de services, dans les arguments, dans la section de configuration ou dans les paramètres:

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

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

Fonctions spéciales

Dans les fichiers de configuration, vous pouvez utiliser ces fonctions spéciales :

  • not() pour la négation des valeurs
  • bool(), int(), float(), string() pour le moulage de type sans perte
  • typed() pour générer un tableau de tous les services d'un type spécifié
  • tagged() pour créer un tableau de tous les services avec une étiquette donnée
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Par rapport au typage conventionnel en PHP, comme (int), le typage sans perte lèvera une exception pour les valeurs non numériques.

La fonction typed() crée un tableau de tous les services d'un type particulier (classe ou interface). Elle exclut les services dont le câblage automatique est désactivé. Plusieurs types peuvent être spécifiés, séparés par des virgules.

services:
	- BarsDependent( typed(Bar) )

Vous pouvez également passer automatiquement un tableau de services d'un type spécifique comme argument en utilisant le câblage automatique.

La fonction tagged() crée un tableau de tous les services ayant une balise spécifiée. Plusieurs balises peuvent être listées, séparées par des virgules.

services:
	- LoggersDependent( tagged(logger) )

Câblage automobile

La clé autowired permet de modifier le comportement de l'autocâblage pour un service particulier. Pour plus de détails, voir le chapitre sur l'autocâblage.

services:
	foo:
		create: Foo
		autowired: false     # le service foo est exclu de l'autocâblage

Tags

Les balises sont utilisées pour ajouter des informations supplémentaires aux services. Vous pouvez attribuer une ou plusieurs balises à un service :

services:
	foo:
		create: Foo
		tags:
			- cached

Les balises peuvent également comporter des valeurs :

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

Pour retrouver tous les services ayant des étiquettes spécifiques, vous pouvez utiliser la fonction tagged():

services:
	- LoggersDependent( tagged(logger) )

Dans le conteneur DI, vous pouvez obtenir les noms de tous les services avec une étiquette spécifique en utilisant la méthode findByTag():

$names = $container->findByTag('logger');
// $names est un tableau contenant le nom du service et la valeur du tag
// par exemple ['foo' => 'monolog.logger.event', ...]

Mode d'injection

L'utilisation du drapeau inject: true active le passage de dépendances via des variables publiques avec l'annotation inject et les méthodes inject*().

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

Par défaut, inject n'est activé que pour les présentateurs.

Modifications du service

Le conteneur DI contient de nombreux services ajoutés soit par des extensions intégrées, soit par des extensions utilisateur. Vous pouvez modifier les définitions de ces services directement dans la configuration. Par exemple, vous pouvez changer la classe du service application.application, qui est conventionnellement Nette\Application\Application, en quelque chose d'autre :

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

Le drapeau alteration est informatif, indiquant que nous modifions simplement un service existant.

Nous pouvons également compléter la configuration :

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

Lors de l'écrasement d'un service, il se peut que vous souhaitiez supprimer les arguments, les éléments de configuration ou les balises d'origine, et c'est là que reset s'avère utile :

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

Si vous souhaitez supprimer un service ajouté par une extension, vous pouvez procéder comme suit :

services:
	cache.journal: false