Nette Documentation Preview

syntax
Nette DI Container
******************

.[perex]
Nette DI è una delle librerie più interessanti di Nette. Sa generare e aggiornare automaticamente container DI compilati, estremamente veloci e straordinariamente facili da configurare.

La forma dei servizi che il container DI deve creare si definisce di norma con file di configurazione in [formato NEON|neon:format]. Il container che abbiamo creato manualmente nel [capitolo precedente|container] si scriverebbe così:

```neon
parameters:
	db:
		dsn: 'mysql:'
		user: root
		password: '***'

services:
	- Nette\Database\Connection(%db.dsn%, %db.user%, %db.password%)
	- ArticleFactory
	- EditController
```

La sintassi è molto concisa.

Tutte le dipendenze dichiarate nei costruttori delle classi `ArticleFactory` ed `EditController` vengono individuate e passate automaticamente da Nette DI grazie al cosiddetto [autowiring|autowiring], quindi non serve indicare nulla nel file di configurazione. Anche se i parametri cambiano, non dovete cambiare nulla nella configurazione. Durante lo sviluppo Nette rigenera automaticamente il container. Potete concentrarvi esclusivamente sullo sviluppo dell'applicazione.

Se vogliamo passare le dipendenze con i setter, usiamo a questo scopo la sezione [setup |services#Setup].

Nette DI genera direttamente il codice PHP del container. Il risultato è quindi un file `.php` che potete aprire ed esaminare. Questo vi permette di vedere esattamente come funziona il container. Potete anche eseguirne il debug nel vostro IDE e percorrerne l'esecuzione passo passo. E soprattutto: il codice PHP generato è estremamente veloce.

Nette DI sa generare anche il codice di una [factory|factory] a partire da un'interfaccia fornita. Al posto della classe `ArticleFactory` ci basta quindi creare nell'applicazione un'interfaccia:

```php
interface ArticleFactory
{
	function create(): Article;
}
```

Trovate l'esempio completo [su GitHub|https://github.com/nette-examples/di-example-doc].


Uso autonomo
------------

Integrare la libreria Nette DI in un'applicazione è molto semplice. Per prima cosa la installiamo con Composer (perché scaricare file zip è ormai superato):

```shell
composer require nette/di
```

Il codice seguente usa il [Compiler |api:Nette\DI\Compiler] per creare un'istanza del container DI secondo la configurazione salvata nel file `config.neon`:

```php
$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp');
$class = $loader->load(function ($compiler) {
	$compiler->loadConfig(__DIR__ . '/config.neon');
});
$container = new $class;
```

Il container viene generato una sola volta, il suo codice viene scritto nella cache (la directory `__DIR__ . '/temp'`) e alle richieste successive viene solo caricato da lì.

Da solo, il `Compiler` abilita nella configurazione soltanto le sezioni `services` e `parameters`. Per usare le altre, come `search`, `decorator`, `di` o `inject`, registratene prima le estensioni. E per poter registrare le estensioni dalla sezione `extensions` della configurazione, aggiungete la `ExtensionsExtension`:

```php
$compiler->addExtension('search', new Nette\DI\Extensions\SearchExtension($tempDir));
$compiler->addExtension('extensions', new Nette\DI\Extensions\ExtensionsExtension);
```

Il [Configurator |application:bootstrapping] usato nelle applicazioni Nette complete le registra tutte automaticamente.

Se tenete più container diversi nella stessa directory di cache, distingueteli con una chiave passata come secondo argomento a `load()`; essa entra a far parte del nome della classe generata:

```php
$class = $loader->load(
	fn($compiler) => $compiler->loadConfig(__DIR__ . '/config.neon'),
	'my-key',
);
```

Per creare e ottenere i servizi si usano i metodi `getService()` o `getByType()`. Ecco come creiamo l'oggetto `EditController`:

```php
$controller = $container->getByType(EditController::class);
$controller->someMethod();
```

Durante lo sviluppo è utile attivare la modalità di aggiornamento automatico, in cui il container si rigenera automaticamente se una classe o un file di configurazione vengono modificati. Basta passare `true` come secondo argomento del costruttore di [ContainerLoader |api:Nette\DI\ContainerLoader].

```php
$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true);
```


Lavorare con il container
-------------------------

Oltre a `getService()` e `getByType()`, l'oggetto container offre altri metodi utili:

- `getByType(string $type, bool $throw = true): ?object` restituisce il servizio del tipo indicato. Se passate `false` come secondo argomento, restituisce `null` invece di sollevare un'eccezione quando un servizio del genere non esiste.
- `hasService(string $name): bool` e `isCreated(string $name): bool` dicono se un servizio è definito e se è già stato istanziato.
- `getParameters(): array` restituisce tutti i parametri del container, `getParameter($key)` ne restituisce uno solo.
- `createInstance(string $class, array $args = []): object` crea una nuova istanza della classe indicata e ne passa le dipendenze del costruttore tramite autowiring.
- `callMethod(callable $function, array $args = []): mixed` chiama il callable indicato e ne passa gli argomenti tramite autowiring.
- `callInjects(object $service): void` chiama tutti i metodi `inject*()` dell'oggetto indicato e vi passa le dipendenze.

Il costruttore del container accetta anche un array di parametri, che integrano quelli definiti nella configurazione:

```php
$container = new $class(['host' => 'localhost']);
```


Uso con Nette Framework
-----------------------

Come abbiamo mostrato, l'uso di Nette DI non è limitato alle applicazioni costruite con Nette Framework: potete integrarlo ovunque con appena tre righe di codice. Se però sviluppate applicazioni con Nette Framework, della configurazione e della creazione del container si occupa [Bootstrap |application:bootstrapping#Configurazione del container DI].

Nette DI Container

Nette DI è una delle librerie più interessanti di Nette. Sa generare e aggiornare automaticamente container DI compilati, estremamente veloci e straordinariamente facili da configurare.

La forma dei servizi che il container DI deve creare si definisce di norma con file di configurazione in formato NEON. Il container che abbiamo creato manualmente nel capitolo precedente si scriverebbe così:

parameters:
	db:
		dsn: 'mysql:'
		user: root
		password: '***'

services:
	- Nette\Database\Connection(%db.dsn%, %db.user%, %db.password%)
	- ArticleFactory
	- EditController

La sintassi è molto concisa.

Tutte le dipendenze dichiarate nei costruttori delle classi ArticleFactory ed EditController vengono individuate e passate automaticamente da Nette DI grazie al cosiddetto autowiring, quindi non serve indicare nulla nel file di configurazione. Anche se i parametri cambiano, non dovete cambiare nulla nella configurazione. Durante lo sviluppo Nette rigenera automaticamente il container. Potete concentrarvi esclusivamente sullo sviluppo dell'applicazione.

Se vogliamo passare le dipendenze con i setter, usiamo a questo scopo la sezione setup.

Nette DI genera direttamente il codice PHP del container. Il risultato è quindi un file .php che potete aprire ed esaminare. Questo vi permette di vedere esattamente come funziona il container. Potete anche eseguirne il debug nel vostro IDE e percorrerne l'esecuzione passo passo. E soprattutto: il codice PHP generato è estremamente veloce.

Nette DI sa generare anche il codice di una factory a partire da un'interfaccia fornita. Al posto della classe ArticleFactory ci basta quindi creare nell'applicazione un'interfaccia:

interface ArticleFactory
{
	function create(): Article;
}

Trovate l'esempio completo su GitHub.

Uso autonomo

Integrare la libreria Nette DI in un'applicazione è molto semplice. Per prima cosa la installiamo con Composer (perché scaricare file zip è ormai superato):

composer require nette/di

Il codice seguente usa il Compiler per creare un'istanza del container DI secondo la configurazione salvata nel file config.neon:

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp');
$class = $loader->load(function ($compiler) {
	$compiler->loadConfig(__DIR__ . '/config.neon');
});
$container = new $class;

Il container viene generato una sola volta, il suo codice viene scritto nella cache (la directory __DIR__ . '/temp') e alle richieste successive viene solo caricato da lì.

Da solo, il Compiler abilita nella configurazione soltanto le sezioni services e parameters. Per usare le altre, come search, decorator, di o inject, registratene prima le estensioni. E per poter registrare le estensioni dalla sezione extensions della configurazione, aggiungete la ExtensionsExtension:

$compiler->addExtension('search', new Nette\DI\Extensions\SearchExtension($tempDir));
$compiler->addExtension('extensions', new Nette\DI\Extensions\ExtensionsExtension);

Il Configurator usato nelle applicazioni Nette complete le registra tutte automaticamente.

Se tenete più container diversi nella stessa directory di cache, distingueteli con una chiave passata come secondo argomento a load(); essa entra a far parte del nome della classe generata:

$class = $loader->load(
	fn($compiler) => $compiler->loadConfig(__DIR__ . '/config.neon'),
	'my-key',
);

Per creare e ottenere i servizi si usano i metodi getService() o getByType(). Ecco come creiamo l'oggetto EditController:

$controller = $container->getByType(EditController::class);
$controller->someMethod();

Durante lo sviluppo è utile attivare la modalità di aggiornamento automatico, in cui il container si rigenera automaticamente se una classe o un file di configurazione vengono modificati. Basta passare true come secondo argomento del costruttore di ContainerLoader.

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true);

Lavorare con il container

Oltre a getService() e getByType(), l'oggetto container offre altri metodi utili:

  • getByType(string $type, bool $throw = true): ?object restituisce il servizio del tipo indicato. Se passate false come secondo argomento, restituisce null invece di sollevare un'eccezione quando un servizio del genere non esiste.
  • hasService(string $name): bool e isCreated(string $name): bool dicono se un servizio è definito e se è già stato istanziato.
  • getParameters(): array restituisce tutti i parametri del container, getParameter($key) ne restituisce uno solo.
  • createInstance(string $class, array $args = []): object crea una nuova istanza della classe indicata e ne passa le dipendenze del costruttore tramite autowiring.
  • callMethod(callable $function, array $args = []): mixed chiama il callable indicato e ne passa gli argomenti tramite autowiring.
  • callInjects(object $service): void chiama tutti i metodi inject*() dell'oggetto indicato e vi passa le dipendenze.

Il costruttore del container accetta anche un array di parametri, che integrano quelli definiti nella configurazione:

$container = new $class(['host' => 'localhost']);

Uso con Nette Framework

Come abbiamo mostrato, l'uso di Nette DI non è limitato alle applicazioni costruite con Nette Framework: potete integrarlo ovunque con appena tre righe di codice. Se però sviluppate applicazioni con Nette Framework, della configurazione e della creazione del container si occupa Bootstrap.