Definizioni del servizio

La configurazione è il punto in cui si inseriscono le definizioni dei servizi personalizzati. Questo viene fatto nella sezione services.

Per esempio, ecco come si crea un servizio chiamato database, che sarà un'istanza della classe PDO:

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

La denominazione dei servizi serve a consentirci di fare riferimento a essi. Se un servizio non è referenziato, non c'è bisogno di dargli un nome. Per questo motivo, al posto del nome si usa un punto elenco:

services:
	- PDO('sqlite::memory:') # servizio anonimo

Una voce di una riga può essere suddivisa in più righe per consentire l'aggiunta di altre chiavi, come setup. L'alias della chiave create: è factory:.

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

Si recupera quindi il servizio dal contenitore DI usando il metodo getService() per nome o, meglio ancora, il metodo getByType() per tipo:

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

Creare un servizio

Il più delle volte, per creare un servizio basta creare un'istanza di una classe:

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

Il che genererà un metodo factory nel contenitore DI:

public function createServiceDatabase(): PDO
{
	return new PDO('mysql:host=127.0.0.1;dbname=test', 'root', 'secret');
}

In alternativa, si può usare una chiave arguments per passare gli argomenti:

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

Un metodo statico può anche creare un servizio:

services:
	database: My\Database::create(root, secret)

Corrisponde al codice PHP:

public function createServiceDatabase(): PDO
{
	return My\Database::create('root', 'secret');
}

Si presume che un metodo statico My\Database::create() abbia un valore di ritorno definito che il contenitore DI deve conoscere. Se non ce l'ha, si scrive il tipo nella configurazione:

services:
	database:
		create: My\Database::create(root, secret)
		type: PDO

Nette DI offre strumenti di espressione estremamente potenti per scrivere quasi tutto. Ad esempio, per fare riferimento a un altro servizio e chiamare il suo metodo. Per semplicità, si usa :: invece di ->.

services:
	routerFactory: App\Router\Factory
	router: @routerFactory::create()

Corrisponde al codice PHP:

public function createServiceRouterFactory(): App\Router\Factory
{
	return new App\Router\Factory;
}

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

Le chiamate ai metodi possono essere concatenate come in PHP:

services:
	foo: FooFactory::build()::get()

Corrisponde al codice PHP:

public function createServiceFoo()
{
	return FooFactory::build()->get();
}

Argomenti

I parametri denominati possono essere usati anche per passare argomenti:

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

L'uso delle virgole è facoltativo quando si suddividono gli argomenti in più righe.

Naturalmente, è possibile utilizzare altri serviziparametri come argomenti:

services:
	- Foo(@anotherService, %appDir%)

Corrisponde al codice PHP:

public function createService01(): Foo
{
	return new Foo($this->getService('anotherService'), '...');
}

Se il primo argomento è autocablato e si vuole specificare il secondo, omettere il primo con _ character, for example Foo(_, %appDir%). O meglio ancora, passare solo il secondo argomento come parametro con nome, ad esempio Foo(path: %appDir%).

Nette DI e il formato NEON offrono strumenti espressivi estremamente potenti per scrivere praticamente qualsiasi cosa. Un argomento può essere un oggetto appena creato, si possono chiamare metodi statici, metodi di altri servizi o persino funzioni globali, utilizzando una notazione speciale:

services:
	analyser: My\Analyser(
		FilesystemIterator(%appDir%)             # creare l'oggetto
		DateTime::createFromFormat('Y-m-d')      # chiama un metodo statico
		@anotherService                          # passare un altro servizio
		@http.request::getRemoteAddress()        # chiamare un altro metodo del servizio
		::getenv(NetteMode)                      # chiama una funzione globale
	)

Corrisponde al codice PHP:

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')
	);
}

Funzioni speciali

È inoltre possibile utilizzare funzioni speciali negli argomenti per eseguire il cast o la negazione dei valori:

  • not(%arg%) negazione
  • bool(%arg%) cast senza perdite a bool
  • int(%arg%) cast senza perdite in int
  • float(%arg%) cast senza perdite a float
  • string(%arg%) cast senza perdite a stringa
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

La riscrittura lossless differisce dalla normale riscrittura PHP, ad esempio utilizzando (int), in quanto lancia un'eccezione per i valori non numerici.

È possibile passare più servizi come argomenti. Un array di tutti i servizi di un particolare tipo (cioè, classe o interfaccia) viene creato dalla funzione typed(). La funzione ometterà i servizi che hanno il cablaggio automatico disabilitato e si possono specificare più tipi separati da una virgola.

services:
	- BarsDependent( typed(Bar) )

È anche possibile passare automaticamente un array di servizi utilizzando l'autowiring.

Un array di tutti i servizi con un determinato tag viene creato dalla funzione tagged(). È possibile specificare più tag separati da una virgola.

services:
	- LoggersDependent( tagged(logger) )

Servizi di riferimento

I singoli servizi sono referenziati utilizzando il carattere @ and name, so for example @database:

services:
	- create: Foo(@database)
	  setup:
			- setCacheStorage(@cache.storage)

Corrisponde al codice PHP:

public function createService01(): Foo
{
	$service = new Foo($this->getService('database'));
	$service->setCacheStorage($this->getService('cache.storage'));
	return $service;
}

Anche i servizi anonimi possono essere referenziati usando un callback, basta specificare il loro tipo (classe o interfaccia) invece del loro nome. Tuttavia, di solito non è necessario, a causa del cablaggio automatico.

services:
	- create: Foo(@Nette\Database\Connection)  # or @\PDO
	  setup:
			- setCacheStorage(@cache.storage)

Configurazione

Nella sezione di configurazione vengono elencati i metodi da richiamare durante la creazione del servizio:

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

Corrisponde al codice PHP:

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

È possibile impostare anche le proprietà. È supportata anche l'aggiunta di un elemento a un array, che deve essere scritto tra virgolette per non entrare in conflitto con la sintassi NEON:

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

Corrisponde al codice PHP:

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

Tuttavia, anche i metodi statici o i metodi di altri servizi possono essere chiamati nel setup. Si passa il servizio effettivo a loro come @self:

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

Corrisponde al codice PHP:

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

Cablaggio automatico

La chiave autowiring può essere usata per escludere un servizio dall'autowiring o per influenzarne il comportamento. Per ulteriori informazioni, vedere il capitolo sull'autowiring.

services:
	foo:
		create: Foo
		autowired: false # foo è rimosso dall'autowiring

Tag

Le informazioni sugli utenti possono essere aggiunte ai singoli servizi sotto forma di tag:

services:
	foo:
		create: Foo
		tags:
			- cached

I tag possono anche avere un valore:

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

Un array di servizi con determinati tag può essere passato come argomento utilizzando la funzione tagged(). Si possono anche specificare più tag separati da una virgola.

services:
	- LoggersDependent( tagged(logger) )

I nomi dei servizi possono essere ottenuti dal contenitore DI con 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à Inject

Il flag inject: true è usato per attivare il passaggio di 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.

Modifica dei servizi

Nel contenitore DI sono presenti diversi servizi aggiunti da un'estensione incorporata o dall'utente. Le definizioni di questi servizi possono essere modificate nella configurazione. Ad esempio, per il servizio application.application, che per impostazione predefinita è un oggetto Nette\Application\Application, si può cambiare la classe:

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

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

Possiamo anche aggiungere una configurazione:

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

Quando si riscrive un servizio, si possono rimuovere gli argomenti originali, gli elementi di configurazione o i tag, a questo serve reset:

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

Un servizio aggiunto per estensione può anche essere rimosso dal contenitore:

services:
	cache.journal: false
versione: 3.x