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 servizi o parametri 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%)
negazionebool(%arg%)
cast senza perdite a boolint(%arg%)
cast senza perdite in intfloat(%arg%)
cast senza perdite a floatstring(%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