Nette Documentation Preview

syntax
Définition des services
***********************

.[perex]
La configuration est l'endroit où nous apprenons au conteneur DI comment assembler les différents services et comment les connecter à d'autres dépendances. Nette fournit une manière très claire et élégante d'y parvenir.

La section `services` dans le fichier de configuration au format NEON est l'endroit où nous définissons nos propres services et leurs configurations. Voyons 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:')
```

La configuration indiquée aboutira à la méthode factory suivante dans le [conteneur DI|container] :

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

Les noms des services nous permettent d'y faire référence dans d'autres parties du fichier de configuration, sous la forme `@nomDuService`. S'il n'est pas nécessaire de nommer le service, nous pouvons simplement utiliser un tiret :

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

Pour obtenir un service du 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 du service :

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


Création de service
===================

La plupart du temps, nous créons un service simplement en créant une instance d'une certaine classe. Par exemple :

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

Si nous devons étendre la configuration avec d'autres clés, la définition peut être répartie sur plusieurs lignes :

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

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

Les arguments du constructeur ou de la méthode de création peuvent alternativement ê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 simple instanciation d'une classe, ils peuvent aussi être le résultat d'appels de méthodes statiques ou de méthodes d'autres services :

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

Notez que pour la simplicité, `::` est utilisé à la place de `->`, voir [##expressions]. Ces méthodes factory seront générées :

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

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

Le conteneur DI a besoin de connaître le type du service créé. Si nous créons un service à l'aide d'une méthode qui n'a pas de type de retour spécifié, nous devons explicitement indiquer ce type dans la configuration :

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


Arguments
=========

Nous passons les arguments au constructeur et aux méthodes d'une manière très similaire à PHP lui-même :

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

Pour une meilleure lisibilité, nous pouvons répartir les arguments sur des lignes séparées. Dans ce cas, l'utilisation de virgules est facultative :

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

Vous pouvez également nommer les arguments et 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 leur valeur par défaut ou injecter un service via l'[autowiring|autowiring], utilisez le trait de soulignement :

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

Comme arguments, on peut passer des services, utiliser des paramètres et bien plus encore, voir [##expressions].


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)
```

Cela ressemblerait à ceci en PHP :

```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, il est également possible de passer des valeurs aux propriétés. L'ajout d'un élément à un tableau est également pris en charge, ce qui doit être écrit entre guillemets pour ne pas entrer en conflit avec la syntaxe NEON :

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

Ce qui ressemblerait au code PHP suivant :

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

Dans le setup, on peut cependant aussi appeler des méthodes statiques ou des méthodes d'autres services. Si vous avez besoin de passer le service actuel comme argument, indiquez-le comme `@self` :

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

Notez que pour la simplicité, `::` est utilisé à la place de `->`, voir [##expressions]. Une telle méthode factory sera générée :

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


Expressions
===========

Nette DI nous offre des moyens d'expression extraordinairement riches, grâce auxquels nous pouvons écrire presque n'importe quoi. Dans les fichiers de configuration, nous pouvons ainsi utiliser des [paramètres |configuration#Paramètres] :

```neon
# paramètre
%wwwDir%

# valeur du paramètre sous la clé
%mailer.user%

# paramètre à l'intérieur d'une chaîne
'%wwwDir%/images'
```

De plus, créer des objets, appeler des méthodes et des fonctions :

```neon
# création d'objet
DateTime()

# appel de méthode statique
Collator::create(%locale%)

# appel de fonction PHP
::getenv(DB_USER)
```

Se référer aux services soit par leur nom, soit par leur type :

```neon
# service par nom
@database

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

Utiliser la syntaxe first-class callable : .{data-version:3.2.0}

```neon
# création d'un callback, équivalent à [@user, logout]
@user::logout(...)
```

Utiliser des constantes :

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

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

Les appels de méthodes peuvent être chaînés comme en PHP. Seulement pour la simplicité, `::` est utilisé à la place de `->` :

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

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

Vous pouvez utiliser ces expressions n'importe où, lors de la [création de services |#Création de service], dans les [#arguments], dans la section [#setup] ou les [paramètres |configuration#Paramètres] :

```neon
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()` négation de la valeur
- `bool()`, `int()`, `float()`, `string()` conversion sans perte vers le type donné
- `typed()` crée un tableau de tous les services du type spécifié
- `tagged()` crée un tableau de tous les services avec le tag donné

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

Contrairement à la conversion de type classique en PHP, comme par exemple `(int)`, la conversion sans perte lèvera une exception pour les valeurs non numériques.

La fonction `typed()` crée un tableau de tous les services du type donné (classe ou interface). Elle omet les services dont l'autowiring est désactivé. Il est possible d'indiquer plusieurs types séparés par une virgule.

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

Vous pouvez également passer un tableau de services d'un certain type comme argument automatiquement via l'[autowiring |autowiring#Tableau de services].

La fonction `tagged()` crée ensuite un tableau de tous les services avec un certain tag. Ici aussi, vous pouvez spécifier plusieurs tags séparés par une virgule.

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


Autowiring
==========

La clé `autowired` permet d'influencer le comportement de l'autowiring pour un service spécifique. Pour plus de détails, voir le [chapitre sur l'autowiring|autowiring].

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


Services Lazy .{data-version:3.2.4}
===================================

Le chargement paresseux (lazy loading) est une technique qui reporte la création d'un service jusqu'au moment où il est réellement nécessaire. Dans la configuration globale, il est possible d'[activer la création lazy |configuration#Services paresseux] pour tous les services en même temps. Pour des services individuels, vous pouvez ensuite surcharger ce comportement :

```neon
services:
	foo:
		create: Foo
		lazy: false
```

Lorsqu'un service est défini comme lazy, lors de sa demande depuis le conteneur DI, nous recevons un objet placeholder spécial. Celui-ci ressemble et se comporte comme le service réel, mais l'initialisation réelle (appel du constructeur et du setup) n'a lieu qu'au premier appel de l'une de ses méthodes ou propriétés.

.[note]
Le chargement paresseux ne peut être utilisé que pour les classes utilisateur, pas pour les classes internes de PHP. Nécessite PHP 8.4 ou plus récent.


Tags
====

Les tags servent à ajouter des informations supplémentaires aux services. Vous pouvez ajouter un ou plusieurs tags à un service :

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

Les tags peuvent également porter des valeurs :

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

Pour obtenir tous les services avec certains tags, 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 un certain tag 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 ex. ['foo' => 'monolog.logger.event', ...]
```


Mode Inject
===========

À l'aide de l'indicateur `inject: true`, le passage des dépendances via les variables publiques avec l'annotation [inject |best-practices:inject-method-attribute#Attributs Inject] et les méthodes [inject*() |best-practices:inject-method-attribute#Méthodes inject] est activé.

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

Par défaut, `inject` est activé uniquement pour les presenters.


Modification des services
=========================

Le conteneur DI contient de nombreux services qui ont été ajoutés via une extension intégrée ou [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 par défaut `Nette\Application\Application`, en une autre :

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

L'indicateur `alteration` est informatif et indique que nous modifions simplement un service existant.

Nous pouvons également compléter le setup :

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

Lors de la réécriture d'un service, nous pouvons vouloir supprimer les arguments d'origine, les éléments de setup ou les tags, ce à quoi sert `reset` :

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

Si vous souhaitez supprimer un service ajouté par une extension, vous pouvez le faire comme ceci :

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

Définition des services

La configuration est l'endroit où nous apprenons au conteneur DI comment assembler les différents services et comment les connecter à d'autres dépendances. Nette fournit une manière très claire et élégante d'y parvenir.

La section services dans le fichier de configuration au format NEON est l'endroit où nous définissons nos propres services et leurs configurations. Voyons 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:')

La configuration indiquée aboutira à la méthode factory suivante dans le conteneur DI :

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

Les noms des services nous permettent d'y faire référence dans d'autres parties du fichier de configuration, sous la forme @nomDuService. S'il n'est pas nécessaire de nommer le service, nous pouvons simplement utiliser un tiret :

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

Pour obtenir un service du 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 du service :

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

Création de service

La plupart du temps, nous créons un service simplement en créant une instance d'une certaine classe. Par exemple :

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

Si nous devons étendre la configuration avec d'autres clés, la définition peut être répartie sur plusieurs lignes :

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

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

Les arguments du constructeur ou de la méthode de création peuvent alternativement ê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 simple instanciation d'une classe, ils peuvent aussi être le résultat d'appels de méthodes statiques ou de méthodes d'autres services :

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

Notez que pour la simplicité, :: est utilisé à la place de ->, voir expressions. Ces méthodes factory seront générées :

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

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

Le conteneur DI a besoin de connaître le type du service créé. Si nous créons un service à l'aide d'une méthode qui n'a pas de type de retour spécifié, nous devons explicitement indiquer ce type dans la configuration :

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

Arguments

Nous passons les arguments au constructeur et aux méthodes d'une manière très similaire à PHP lui-même :

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

Pour une meilleure lisibilité, nous pouvons répartir les arguments sur des lignes séparées. Dans ce cas, l'utilisation de virgules est facultative :

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

Vous pouvez également nommer les arguments et 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 leur valeur par défaut ou injecter un service via l'autowiring, utilisez le trait de soulignement :

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

Comme arguments, on peut passer des services, utiliser des paramètres et bien plus encore, voir expressions.

Setup

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)

Cela ressemblerait à ceci en 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, il est également possible de passer des valeurs aux propriétés. L'ajout d'un élément à un tableau est également pris en charge, ce qui doit être écrit entre guillemets pour ne pas entrer en conflit avec la syntaxe NEON :

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

Ce qui ressemblerait au code PHP suivant :

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

Dans le setup, on peut cependant aussi appeler des méthodes statiques ou des méthodes d'autres services. Si vous avez besoin de passer le service actuel comme argument, indiquez-le comme @self :

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

Notez que pour la simplicité, :: est utilisé à la place de ->, voir expressions. Une telle méthode factory sera générée :

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

Expressions

Nette DI nous offre des moyens d'expression extraordinairement riches, grâce auxquels nous pouvons écrire presque n'importe quoi. Dans les fichiers de configuration, nous pouvons ainsi utiliser des paramètres :

# paramètre
%wwwDir%

# valeur du paramètre sous la clé
%mailer.user%

# paramètre à l'intérieur d'une chaîne
'%wwwDir%/images'

De plus, créer des objets, appeler des méthodes et des fonctions :

# création d'objet
DateTime()

# appel de méthode statique
Collator::create(%locale%)

# appel de fonction PHP
::getenv(DB_USER)

Se référer aux services soit par leur nom, soit par leur type :

# service par nom
@database

# service par type
@Nette\Database\Connection

Utiliser la syntaxe first-class callable :

# création d'un callback, équivalent à [@user, logout]
@user::logout(...)

Utiliser des constantes :

# constante de classe
FilesystemIterator::SKIP_DOTS

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

Les appels de méthodes peuvent être chaînés comme en PHP. Seulement pour la simplicité, :: est utilisé à la place de -> :

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

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

Vous pouvez utiliser ces expressions n'importe où, lors de la création de services, dans les arguments, dans la section setup ou 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() négation de la valeur
  • bool(), int(), float(), string() conversion sans perte vers le type donné
  • typed() crée un tableau de tous les services du type spécifié
  • tagged() crée un tableau de tous les services avec le tag donné
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Contrairement à la conversion de type classique en PHP, comme par exemple (int), la conversion sans perte lèvera une exception pour les valeurs non numériques.

La fonction typed() crée un tableau de tous les services du type donné (classe ou interface). Elle omet les services dont l'autowiring est désactivé. Il est possible d'indiquer plusieurs types séparés par une virgule.

services:
	- BarsDependent( typed(Bar) )

Vous pouvez également passer un tableau de services d'un certain type comme argument automatiquement via l'autowiring.

La fonction tagged() crée ensuite un tableau de tous les services avec un certain tag. Ici aussi, vous pouvez spécifier plusieurs tags séparés par une virgule.

services:
	- LoggersDependent( tagged(logger) )

Autowiring

La clé autowired permet d'influencer le comportement de l'autowiring pour un service spécifique. Pour plus de détails, voir le chapitre sur l'autowiring.

services:
	foo:
		create: Foo
		autowired: false     # le service foo est exclu de l'autowiring

Services Lazy

Le chargement paresseux (lazy loading) est une technique qui reporte la création d'un service jusqu'au moment où il est réellement nécessaire. Dans la configuration globale, il est possible d'activer la création lazy pour tous les services en même temps. Pour des services individuels, vous pouvez ensuite surcharger ce comportement :

services:
	foo:
		create: Foo
		lazy: false

Lorsqu'un service est défini comme lazy, lors de sa demande depuis le conteneur DI, nous recevons un objet placeholder spécial. Celui-ci ressemble et se comporte comme le service réel, mais l'initialisation réelle (appel du constructeur et du setup) n'a lieu qu'au premier appel de l'une de ses méthodes ou propriétés.

Le chargement paresseux ne peut être utilisé que pour les classes utilisateur, pas pour les classes internes de PHP. Nécessite PHP 8.4 ou plus récent.

Tags

Les tags servent à ajouter des informations supplémentaires aux services. Vous pouvez ajouter un ou plusieurs tags à un service :

services:
	foo:
		create: Foo
		tags:
			- cached

Les tags peuvent également porter des valeurs :

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

Pour obtenir tous les services avec certains tags, vous pouvez utiliser la fonction tagged() :

services:
	- LoggersDependent( tagged(logger) )

Dans le conteneur DI, vous pouvez obtenir les noms de tous les services avec un certain tag 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 ex. ['foo' => 'monolog.logger.event', ...]

Mode Inject

À l'aide de l'indicateur inject: true, le passage des dépendances via les variables publiques avec l'annotation inject et les méthodes inject*() est activé.

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

Par défaut, inject est activé uniquement pour les presenters.

Modification des services

Le conteneur DI contient de nombreux services qui ont été ajoutés via une extension intégrée ou 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 par défaut Nette\Application\Application, en une autre :

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

L'indicateur alteration est informatif et indique que nous modifions simplement un service existant.

Nous pouvons également compléter le setup :

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

Lors de la réécriture d'un service, nous pouvons vouloir supprimer les arguments d'origine, les éléments de setup ou les tags, ce à quoi sert reset :

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

Si vous souhaitez supprimer un service ajouté par une extension, vous pouvez le faire comme ceci :

services:
	cache.journal: false