Definiții ale serviciilor
Configurația este locul în care instruim containerul DI cu privire la modul de asamblare a serviciilor individuale și la modul de conectare a acestora cu alte dependențe. Nette oferă o modalitate foarte clară și elegantă de a realiza acest lucru.
Secțiunea services
din fișierul de configurare NEON este locul în care definim serviciile noastre personalizate
și configurațiile lor. Să analizăm un exemplu simplu de definire a unui serviciu numit database
, care reprezintă
o instanță a clasei PDO
:
services:
database: PDO('sqlite::memory:')
Această configurație are ca rezultat următoarea metodă factory în containerul DI:
public function createServiceDatabase(): PDO
{
return new PDO('sqlite::memory:');
}
Numele serviciilor ne permit să facem referire la acestea în alte părți ale fișierului de configurare, folosind formatul
@serviceName
. Dacă nu este nevoie să denumim serviciul, putem folosi pur și simplu un punct:
services:
- PDO('sqlite::memory:')
Pentru a prelua un serviciu din containerul DI, putem utiliza metoda getService()
cu numele serviciului ca
parametru sau metoda getByType()
cu tipul serviciului:
$database = $container->getService('database');
$database = $container->getByType(PDO::class);
Crearea de servicii
Cel mai adesea, creăm un serviciu prin simpla instanțiere a unei clase specifice. De exemplu:
services:
database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
Dacă trebuie să extindem configurația cu chei suplimentare, definiția poate fi extinsă în mai multe linii:
services:
database:
create: PDO('sqlite::memory:')
setup: ...
Cheia create
are un pseudonim factory
, ambele versiuni sunt comune în practică. Cu toate acestea,
recomandăm utilizarea create
.
Argumentele constructorului sau metoda de creare pot fi scrise alternativ în cheia arguments
:
services:
database:
create: PDO
arguments: ['mysql:host=127.0.0.1;dbname=test', root, secret]
Serviciile nu trebuie să fie create doar prin simpla instanțiere a unei clase; ele pot rezulta, de asemenea, din apelarea unor metode statice sau a unor metode ale altor servicii:
services:
database: DatabaseFactory::create()
router: @routerFactory::create()
Rețineți că, pentru simplificare, în loc de ->
, folosim ::
, a se vedea expresia înseamnă. Aceste metode fabrică sunt generate:
public function createServiceDatabase(): PDO
{
return DatabaseFactory::create();
}
public function createServiceRouter(): RouteList
{
return $this->getService('routerFactory')->create();
}
Containerul DI trebuie să cunoască tipul serviciului creat. Dacă creăm un serviciu folosind o metodă care nu are un tip de returnare specificat, trebuie să menționăm explicit acest tip în configurație:
services:
database:
create: DatabaseFactory::create()
type: PDO
Argumente
Trecem argumente către constructori și metode într-o manieră foarte asemănătoare cu cea din PHP obișnuit:
services:
database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
Pentru o mai bună lizibilitate, putem lista argumentele pe linii separate. În acest format, utilizarea virgulelor este opțională:
services:
database: PDO(
'mysql:host=127.0.0.1;dbname=test'
root
secret
)
Puteți, de asemenea, să denumiți argumentele, ceea ce vă permite să nu vă faceți griji cu privire la ordinea lor:
services:
database: PDO(
username: root
password: secret
dsn: 'mysql:host=127.0.0.1;dbname=test'
)
Dacă doriți să omiteți anumite argumente și să folosiți valorile lor implicite sau să introduceți un serviciu prin autocablare, utilizați un semn de subliniere:
services:
foo: Foo(_, %appDir%)
Argumentele pot fi servicii, parametri și multe altele, a se vedea mijloacele de exprimare.
Configurare
În secțiunea setup
, se definesc metodele care trebuie apelate la crearea serviciului.
services:
database:
create: PDO(%dsn%, %user%, %password%)
setup:
- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
În PHP, acest lucru ar arăta astfel:
public function createServiceDatabase(): PDO
{
$service = new PDO('...', '...', '...');
$service->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $service;
}
În plus față de apelurile la metode, puteți, de asemenea, să transmiteți valori la proprietăți. Adăugarea unui element la o matrice este, de asemenea, acceptată, dar trebuie să îl includeți între ghilimele pentru a evita coliziunea cu sintaxa NEON:
services:
foo:
create: Foo
setup:
- $value = 123
- '$onClick[]' = [@bar, clickHandler]
În PHP, acest lucru s-ar traduce prin:
public function createServiceFoo(): Foo
{
$service = new Foo;
$service->value = 123;
$service->onClick[] = [$this->getService('bar'), 'clickHandler'];
return $service;
}
În configurare, puteți apela și metode statice sau metode ale altor servicii. Dacă aveți nevoie să treceți serviciul
curent ca argument, utilizați @self
:
services:
foo:
create: Foo
setup:
- My\Helpers::initializeFoo(@self)
- @anotherService::setFoo(@self)
Rețineți că, pentru simplificare, în loc de ->
, folosim ::
, a se vedea expresia înseamnă. Aceasta generează următoarea metodă de fabrică:
public function createServiceFoo(): Foo
{
$service = new Foo;
My\Helpers::initializeFoo($service);
$this->getService('anotherService')->setFoo($service);
return $service;
}
Mijloace de exprimare
Nette DI ne oferă capacități de exprimare excepțional de bogate, permițându-ne să articulăm aproape orice. În fișierele de configurare, putem utiliza parametri:
# parametru
%wwwDir%
# valoarea unui parametru sub o cheie de parametru
%mailer.user%
# parametru în cadrul unui șir de caractere
'%wwwDir%/images'
De asemenea, putem crea obiecte, apela metode și funcții:
# creați un obiect
DateTime()
# apelarea unei metode statice
Collator::create(%locale%)
# apelarea unei funcții PHP
::getenv(DB_USER)
Faceți referire la servicii fie prin numele lor, fie prin tipul lor:
# serviciu după nume
@database
# serviciu după tip
@Nette\Database\Connection
Folosiți sintaxa de primă clasă a elementelor apelabile:
# creating a callback, equivalent to [@user, logout]
@user::logout(...)
Utilizați constante:
# constantă de clasă
FilesystemIterator::SKIP_DOTS
# constantă globală obținută prin funcția PHP constant()
::constant(PHP_VERSION)
Apelurile la metode pot fi înlănțuite, la fel ca în PHP. Pentru simplitate, în loc de ->
, folosim
::
:
DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')
@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()
Aceste expresii pot fi utilizate oriunde la crearea serviciilor, în argumente, în secțiunea de configurare sau în parametri:
parameters:
ipAddress: @http.request::getRemoteAddress()
services:
database:
create: DatabaseFactory::create( @anotherService::getDsn() )
setup:
- initialize( ::getenv('DB_USER') )
Funcții speciale
În cadrul fișierelor de configurare, puteți utiliza aceste funcții speciale:
not()
pentru negarea valorilorbool()
,int()
,float()
,string()
pentru turnarea fără pierderi a tipurilortyped()
pentru a genera o matrice a tuturor serviciilor de un tip specificattagged()
pentru a crea o matrice a tuturor serviciilor cu o anumită etichetă
services:
- Foo(
id: int(::getenv('ProjectId'))
productionMode: not(%debugMode%)
)
În comparație cu tipizarea convențională în PHP, cum ar fi (int)
, tipizarea fără pierderi va arunca
o excepție pentru valorile nenumerice.
Funcția typed()
creează o matrice cu toate serviciile de un anumit tip (clasă sau interfață). Aceasta
exclude serviciile cu cablarea automată dezactivată. Se pot specifica mai multe tipuri, separate prin virgule.
services:
- BarsDependent( typed(Bar) )
De asemenea, puteți transmite automat o matrice de servicii de un anumit tip ca argument, utilizând autowiring.
Funcția tagged()
creează o matrice a tuturor serviciilor cu o etichetă specificată. Pot fi enumerate mai
multe etichete, separate prin virgulă.
services:
- LoggersDependent( tagged(logger) )
Cablare automată
Tasta autowired
vă permite să modificați comportamentul de cablare automată pentru un anumit serviciu. Pentru
mai multe detalii, consultați capitolul privind cablarea automată.
services:
foo:
create: Foo
autowired: false # serviciul foo este exclus de la cablarea automată
Etichete
Etichetele sunt utilizate pentru a adăuga informații suplimentare la servicii. Puteți atribui una sau mai multe etichete unui serviciu:
services:
foo:
create: Foo
tags:
- cached
Etichetele pot avea și valori:
services:
foo:
create: Foo
tags:
logger: monolog.logger.event
Pentru a prelua toate serviciile cu anumite etichete, puteți utiliza funcția tagged()
:
services:
- LoggersDependent( tagged(logger) )
În containerul DI, puteți obține numele tuturor serviciilor cu o anumită etichetă utilizând metoda
findByTag()
:
$names = $container->findByTag('logger');
// $names este o matrice care conține numele serviciului și valoarea etichetei.
// de exemplu, ['foo' => 'monolog.logger.event', ...]
Modul de injectare
Utilizarea indicatorului inject: true
activează trecerea dependențelor prin intermediul variabilelor publice cu
adnotarea inject și metodele inject*().
services:
articles:
create: App\Model\Articles
inject: true
În mod implicit, inject
este activat numai pentru prezentatori.
Modificări ale serviciului
Containerul DI conține multe servicii adăugate fie prin extensii încorporate, fie prin extensii de utilizator. Puteți modifica definițiile acestor servicii direct în configurație. De
exemplu, puteți schimba clasa serviciului application.application
, care este în mod convențional
Nette\Application\Application
, în altceva:
services:
application.application:
create: MyApplication
alteration: true
Semnul alteration
este informativ, indicând că nu facem decât să modificăm un serviciu existent.
De asemenea, putem completa configurația:
services:
application.application:
create: MyApplication
alteration: true
setup:
- '$onStartup[]' = [@resource, init]
Atunci când suprascrieți un serviciu, este posibil să doriți să eliminați argumentele, elementele de configurare sau
etichetele originale, și aici reset
este util:
services:
application.application:
create: MyApplication
alteration: true
reset:
- arguments
- setup
- tags
Dacă doriți să eliminați un serviciu adăugat de o extensie, puteți face acest lucru în felul următor:
services:
cache.journal: false