Nette Documentation Preview

syntax
Definizioni del servizio
************************

.[perex]
La configurazione è il luogo in cui si istruisce il contenitore DI su come assemblare i singoli servizi e come collegarli con altre dipendenze. Nette fornisce un modo molto chiaro ed elegante per raggiungere questo obiettivo.

La sezione `services` del file di configurazione di NEON è il luogo in cui si definiscono i servizi personalizzati e le loro configurazioni. Vediamo un semplice esempio di definizione di un servizio chiamato `database`, che rappresenta un'istanza della classe `PDO`:

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

Questa configurazione dà luogo al seguente metodo factory nel [contenitore DI |container]:

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

I nomi dei servizi consentono di fare riferimento ad essi in altre parti del file di configurazione, utilizzando il formato `@serviceName`. Se non è necessario dare un nome al servizio, si può usare semplicemente un punto:

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

Per recuperare un servizio dal contenitore DI, si può usare il metodo `getService()` con il nome del servizio come parametro, oppure il metodo `getByType()` con il tipo di servizio:

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


Creazione di servizi .[#toc-service-creation]
=============================================

Più comunemente, si crea un servizio semplicemente istanziando una classe specifica. Ad esempio:

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

Se abbiamo bisogno di espandere la configurazione con ulteriori chiavi, la definizione può essere espansa in più righe:

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

La chiave `create` ha un alias `factory`, entrambe le versioni sono comuni nella pratica. Tuttavia, si consiglia di utilizzare `create`.

Gli argomenti del costruttore o il metodo di creazione possono essere scritti in alternativa nella chiave `arguments`:

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

I servizi non devono essere creati solo tramite la semplice istanziazione di una classe; possono anche derivare dalla chiamata di metodi statici o di altri servizi:

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

Si noti che per semplicità, al posto di `->`, si usa `::`, vedi [espressione significa |#expression means]. Questi metodi di fabbrica sono generati:

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

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

Il contenitore DI deve conoscere il tipo del servizio creato. Se si crea un servizio usando un metodo che non ha un tipo di ritorno specificato, si deve menzionare esplicitamente questo tipo nella configurazione:

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


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

Passiamo gli argomenti ai costruttori e ai metodi in modo molto simile al normale PHP:

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

Per una migliore leggibilità, possiamo elencare gli argomenti su righe separate. In questo formato, l'uso delle virgole è facoltativo:

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

È possibile anche dare un nome agli argomenti, in modo da non preoccuparsi del loro ordine:

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

Se si desidera omettere alcuni argomenti e utilizzare i loro valori predefiniti o inserire un servizio tramite [autocablaggio |autowiring], utilizzare un trattino basso:

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

Gli argomenti possono essere servizi, parametri e molto altro, vedere i [mezzi di espressione |#expression means].


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

Nella sezione `setup`, si definiscono i metodi che devono essere richiamati durante la creazione del servizio.

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

In PHP, questo sarebbe simile a:

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

Oltre alle chiamate di metodo, è possibile passare valori alle proprietà. È supportata anche l'aggiunta di un elemento a un array, ma è necessario racchiuderlo tra virgolette per evitare di scontrarsi con la sintassi NEON:

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

In PHP, questo si tradurrebbe in:

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

Nella configurazione, si possono anche chiamare metodi statici o metodi di altri servizi. Se è necessario passare il servizio corrente come argomento, utilizzare `@self`:

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

Si noti che per semplicità, al posto di `->`, si usa `::`, vedi [espressione significa |#expression means]. Questo genera il seguente metodo di fabbrica:

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


Mezzi di espressione .[#toc-expression-means]
=============================================

Nette DI ci fornisce capacità di espressione eccezionalmente ricche, che ci permettono di articolare quasi tutto. Nei file di configurazione, possiamo usare dei [parametri |configuration#parameters]:

```neon
# parametro
%wwwDir%

# valore sotto una chiave di parametro
%mailer.user%

# parametro all'interno di una stringa
'%wwwDir%/images'
```

Possiamo anche creare oggetti, chiamare metodi e funzioni:

```neon
# creare un oggetto
DateTime()

# chiamare un metodo statico
Collator::create(%locale%)

# chiamare una funzione PHP
::getenv(DB_USER)
```

Fare riferimento ai servizi con il loro nome o con il loro tipo:

```neon
# servizio per nome
@database

# servizio per tipo
@Nette\Database\Connection
```

Usare la sintassi dei callable di prima classe: .{data-version:3.2.0}

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

Utilizzare le costanti:

```neon
# costante di classe
FilesystemIterator::SKIP_DOTS

# costante globale ottenuta con la funzione PHP constant()
::constant(PHP_VERSION)
```

Le chiamate ai metodi possono essere concatenate, proprio come in PHP. Per semplicità, invece di `->`, usiamo `::`:

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

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

Queste espressioni possono essere utilizzate ovunque durante la [creazione di servizi |#Service Creation], nei [parametri |#Arguments], nella sezione di [impostazione |#setup] o nei [parametri |configuration#parameters]:

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

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


Funzioni speciali .[#toc-special-functions]
-------------------------------------------

All'interno dei file di configurazione è possibile utilizzare queste funzioni speciali:

- `not()` per la negazione dei valori
- `bool()`, `int()`, `float()`, `string()` per la fusione dei tipi senza perdita di informazioni
- `typed()` per generare un array di tutti i servizi di un tipo specificato
- `tagged()` per creare un array di tutti i servizi con un determinato tag

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

Rispetto al typecasting convenzionale in PHP, come `(int)`, il type casting lossless lancia un'eccezione per i valori non numerici.

La funzione `typed()` crea un array di tutti i servizi di un particolare tipo (classe o interfaccia). Esclude i servizi con il cablaggio automatico disattivato. È possibile specificare più tipi, separati da virgole.

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

È anche possibile passare automaticamente un array di servizi di un tipo specifico come argomento utilizzando l'[autowiring |autowiring#Collection of Services].

La funzione `tagged()` crea un array di tutti i servizi con un tag specificato. È possibile elencare più tag, separati da virgole.

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


Cablaggio auto .[#toc-autowiring]
=================================

Il tasto `autowired` consente di modificare il comportamento del cablaggio automatico per un particolare servizio. Per maggiori dettagli, vedere [il capitolo sul cablaggio automatico |autowiring].

```neon
services:
	foo:
		create: Foo
		autowired: false     # il servizio pippo è escluso dal cablaggio automatico
```


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

I tag sono utilizzati per aggiungere informazioni supplementari ai servizi. È possibile assegnare uno o più tag a un servizio:

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

I tag possono anche contenere dei valori:

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

Per recuperare tutti i servizi con tag specifici, è possibile utilizzare la funzione `tagged()`:

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

Nel contenitore DI, è possibile ottenere i nomi di tutti i servizi con un tag specifico utilizzando il metodo `findByTag()`:

```php
$names = $container->findByTag('logger');
// $names è un array contenente il nome del servizio e il valore del tag
// ad esempio ['foo' => 'monolog.logger.event', ...]
```


Modalità di iniezione .[#toc-inject-mode]
=========================================

L'uso del flag `inject: true` attiva il passaggio delle dipendenze tramite variabili pubbliche con l'annotazione [inject |best-practices:inject-method-attribute#Inject Attributes] e i metodi [inject*() |best-practices:inject-method-attribute#inject Methods].

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

Per impostazione predefinita, `inject` è attivato solo per i presentatori.


Modifiche del servizio .[#toc-service-modifications]
====================================================

Il contenitore DI contiene molti servizi aggiunti da [estensioni |#extensions] integrate o dall'[utente |#extensions]. È possibile modificare le definizioni di questi servizi direttamente nella configurazione. Per esempio, si può cambiare la classe del servizio `application.application`, che è convenzionalmente `Nette\Application\Application`, in un'altra:

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

Il flag `alteration` è informativo e indica che stiamo semplicemente modificando un servizio esistente.

Possiamo anche completare la configurazione:

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

Quando si sovrascrive un servizio, si potrebbe voler rimuovere gli argomenti originali, gli elementi di configurazione o i tag, ed è qui che `reset` si rivela utile:

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

Se si desidera rimuovere un servizio aggiunto da un'estensione, è possibile farlo in questo modo:

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

Definizioni del servizio

La configurazione è il luogo in cui si istruisce il contenitore DI su come assemblare i singoli servizi e come collegarli con altre dipendenze. Nette fornisce un modo molto chiaro ed elegante per raggiungere questo obiettivo.

La sezione services del file di configurazione di NEON è il luogo in cui si definiscono i servizi personalizzati e le loro configurazioni. Vediamo un semplice esempio di definizione di un servizio chiamato database, che rappresenta un'istanza della classe PDO:

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

Questa configurazione dà luogo al seguente metodo factory nel contenitore DI:

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

I nomi dei servizi consentono di fare riferimento ad essi in altre parti del file di configurazione, utilizzando il formato @serviceName. Se non è necessario dare un nome al servizio, si può usare semplicemente un punto:

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

Per recuperare un servizio dal contenitore DI, si può usare il metodo getService() con il nome del servizio come parametro, oppure il metodo getByType() con il tipo di servizio:

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

Creazione di servizi

Più comunemente, si crea un servizio semplicemente istanziando una classe specifica. Ad esempio:

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

Se abbiamo bisogno di espandere la configurazione con ulteriori chiavi, la definizione può essere espansa in più righe:

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

La chiave create ha un alias factory, entrambe le versioni sono comuni nella pratica. Tuttavia, si consiglia di utilizzare create.

Gli argomenti del costruttore o il metodo di creazione possono essere scritti in alternativa nella chiave arguments:

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

I servizi non devono essere creati solo tramite la semplice istanziazione di una classe; possono anche derivare dalla chiamata di metodi statici o di altri servizi:

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

Si noti che per semplicità, al posto di ->, si usa ::, vedi espressione significa. Questi metodi di fabbrica sono generati:

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

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

Il contenitore DI deve conoscere il tipo del servizio creato. Se si crea un servizio usando un metodo che non ha un tipo di ritorno specificato, si deve menzionare esplicitamente questo tipo nella configurazione:

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

Argomenti

Passiamo gli argomenti ai costruttori e ai metodi in modo molto simile al normale PHP:

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

Per una migliore leggibilità, possiamo elencare gli argomenti su righe separate. In questo formato, l'uso delle virgole è facoltativo:

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

È possibile anche dare un nome agli argomenti, in modo da non preoccuparsi del loro ordine:

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

Se si desidera omettere alcuni argomenti e utilizzare i loro valori predefiniti o inserire un servizio tramite autocablaggio, utilizzare un trattino basso:

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

Gli argomenti possono essere servizi, parametri e molto altro, vedere i mezzi di espressione.

Impostazione

Nella sezione setup, si definiscono i metodi che devono essere richiamati durante la creazione del servizio.

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

In PHP, questo sarebbe simile a:

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

Oltre alle chiamate di metodo, è possibile passare valori alle proprietà. È supportata anche l'aggiunta di un elemento a un array, ma è necessario racchiuderlo tra virgolette per evitare di scontrarsi con la sintassi NEON:

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

In PHP, questo si tradurrebbe in:

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

Nella configurazione, si possono anche chiamare metodi statici o metodi di altri servizi. Se è necessario passare il servizio corrente come argomento, utilizzare @self:

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

Si noti che per semplicità, al posto di ->, si usa ::, vedi espressione significa. Questo genera il seguente metodo di fabbrica:

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

Mezzi di espressione

Nette DI ci fornisce capacità di espressione eccezionalmente ricche, che ci permettono di articolare quasi tutto. Nei file di configurazione, possiamo usare dei parametri:

# parametro
%wwwDir%

# valore sotto una chiave di parametro
%mailer.user%

# parametro all'interno di una stringa
'%wwwDir%/images'

Possiamo anche creare oggetti, chiamare metodi e funzioni:

# creare un oggetto
DateTime()

# chiamare un metodo statico
Collator::create(%locale%)

# chiamare una funzione PHP
::getenv(DB_USER)

Fare riferimento ai servizi con il loro nome o con il loro tipo:

# servizio per nome
@database

# servizio per tipo
@Nette\Database\Connection

Usare la sintassi dei callable di prima classe:

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

Utilizzare le costanti:

# costante di classe
FilesystemIterator::SKIP_DOTS

# costante globale ottenuta con la funzione PHP constant()
::constant(PHP_VERSION)

Le chiamate ai metodi possono essere concatenate, proprio come in PHP. Per semplicità, invece di ->, usiamo :::

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

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

Queste espressioni possono essere utilizzate ovunque durante la creazione di servizi, nei parametri, nella sezione di impostazione o nei parametri:

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

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

Funzioni speciali

All'interno dei file di configurazione è possibile utilizzare queste funzioni speciali:

  • not() per la negazione dei valori
  • bool(), int(), float(), string() per la fusione dei tipi senza perdita di informazioni
  • typed() per generare un array di tutti i servizi di un tipo specificato
  • tagged() per creare un array di tutti i servizi con un determinato tag
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Rispetto al typecasting convenzionale in PHP, come (int), il type casting lossless lancia un'eccezione per i valori non numerici.

La funzione typed() crea un array di tutti i servizi di un particolare tipo (classe o interfaccia). Esclude i servizi con il cablaggio automatico disattivato. È possibile specificare più tipi, separati da virgole.

services:
	- BarsDependent( typed(Bar) )

È anche possibile passare automaticamente un array di servizi di un tipo specifico come argomento utilizzando l'autowiring.

La funzione tagged() crea un array di tutti i servizi con un tag specificato. È possibile elencare più tag, separati da virgole.

services:
	- LoggersDependent( tagged(logger) )

Cablaggio auto

Il tasto autowired consente di modificare il comportamento del cablaggio automatico per un particolare servizio. Per maggiori dettagli, vedere il capitolo sul cablaggio automatico.

services:
	foo:
		create: Foo
		autowired: false     # il servizio pippo è escluso dal cablaggio automatico

Tag

I tag sono utilizzati per aggiungere informazioni supplementari ai servizi. È possibile assegnare uno o più tag a un servizio:

services:
	foo:
		create: Foo
		tags:
			- cached

I tag possono anche contenere dei valori:

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

Per recuperare tutti i servizi con tag specifici, è possibile utilizzare la funzione tagged():

services:
	- LoggersDependent( tagged(logger) )

Nel contenitore DI, è possibile ottenere i nomi di tutti i servizi con un tag specifico utilizzando il metodo findByTag():

$names = $container->findByTag('logger');
// $names è un array contenente il nome del servizio e il valore del tag
// ad esempio ['foo' => 'monolog.logger.event', ...]

Modalità di iniezione

L'uso del flag inject: true attiva il passaggio delle dipendenze tramite variabili pubbliche con l'annotazione inject e i metodi inject*().

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

Per impostazione predefinita, inject è attivato solo per i presentatori.

Modifiche del servizio

Il contenitore DI contiene molti servizi aggiunti da estensioni integrate o dall'utente. È possibile modificare le definizioni di questi servizi direttamente nella configurazione. Per esempio, si può cambiare la classe del servizio application.application, che è convenzionalmente Nette\Application\Application, in un'altra:

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

Il flag alteration è informativo e indica che stiamo semplicemente modificando un servizio esistente.

Possiamo anche completare la configurazione:

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

Quando si sovrascrive un servizio, si potrebbe voler rimuovere gli argomenti originali, gli elementi di configurazione o i tag, ed è qui che reset si rivela utile:

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

Se si desidera rimuovere un servizio aggiunto da un'estensione, è possibile farlo in questo modo:

services:
	cache.journal: false