Nette Documentation Preview

syntax
Definiții ale serviciilor
*************************

.[perex]
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`:

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

Această configurație are ca rezultat următoarea metodă factory în [containerul DI |container]:

```php
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:

```neon
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:

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


Crearea de servicii .[#toc-service-creation]
============================================

Cel mai adesea, creăm un serviciu prin simpla instanțiere a unei clase specifice. De exemplu:

```neon
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:

```neon
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`:

```neon
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:

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

Rețineți că, pentru simplificare, în loc de `->`, folosim `::`, a se vedea [expresia înseamnă |#expression means]. Aceste metode fabrică sunt generate:

```php
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:

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


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

Trecem argumente către constructori și metode într-o manieră foarte asemănătoare cu cea din PHP obișnuit:

```neon
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ă:

```neon
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:

```neon
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 |autowiring], utilizați un semn de subliniere:

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

Argumentele pot fi servicii, parametri și multe altele, a se vedea [mijloacele de exprimare |#expression means].


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

În secțiunea `setup`, se definesc metodele care trebuie apelate la crearea serviciului.

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

În PHP, acest lucru ar arăta astfel:

```php
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:

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

În PHP, acest lucru s-ar traduce prin:

```php
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`:

```neon
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ă |#expression means]. Aceasta generează următoarea metodă de fabrică:

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


Mijloace de exprimare .[#toc-expression-means]
==============================================

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 |configuration#parameters]:

```neon
# 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:

```neon
# 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:

```neon
# serviciu după nume
@database

# serviciu după tip
@Nette\Database\Connection
```

Folosiți sintaxa de primă clasă a elementelor apelabile: .{data-version:3.2.0}

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

Utilizați constante:

```neon
# 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 `::`:

```neon
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 |#Service Creation], în [argumente |#Arguments], în secțiunea de [configurare |#setup] sau în [parametri |configuration#parameters]:

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

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


Funcții speciale .[#toc-special-functions]
------------------------------------------

În cadrul fișierelor de configurare, puteți utiliza aceste funcții speciale:

- `not()` pentru negarea valorilor
- `bool()`, `int()`, `float()`, `string()` pentru turnarea fără pierderi a tipurilor
- `typed()` pentru a genera o matrice a tuturor serviciilor de un tip specificat
- `tagged()` pentru a crea o matrice a tuturor serviciilor cu o anumită etichetă

```neon
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.

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

De asemenea, puteți transmite automat o matrice de servicii de un anumit tip ca argument, utilizând [autowiring |autowiring#Collection of Services].

Funcția `tagged()` creează o matrice a tuturor serviciilor cu o etichetă specificată. Pot fi enumerate mai multe etichete, separate prin virgulă.

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


Cablare automată .[#toc-autowiring]
===================================

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ă |autowiring].

```neon
services:
	foo:
		create: Foo
		autowired: false     # serviciul foo este exclus de la cablarea automată
```


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

Etichetele sunt utilizate pentru a adăuga informații suplimentare la servicii. Puteți atribui una sau mai multe etichete unui serviciu:

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

Etichetele pot avea și valori:

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

Pentru a prelua toate serviciile cu anumite etichete, puteți utiliza funcția `tagged()`:

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

În containerul DI, puteți obține numele tuturor serviciilor cu o anumită etichetă utilizând metoda `findByTag()`:

```php
$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 .[#toc-inject-mode]
======================================

Utilizarea indicatorului `inject: true` activează trecerea dependențelor prin intermediul variabilelor publice cu adnotarea [inject |best-practices:inject-method-attribute#Inject Attributes] și metodele [inject*() |best-practices:inject-method-attribute#inject Methods].

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

În mod implicit, `inject` este activat numai pentru prezentatori.


Modificări ale serviciului .[#toc-service-modifications]
========================================================

Containerul DI conține multe servicii adăugate fie prin [extensii |#extensions] încorporate, fie prin [extensii de utilizator |#extensions]. 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:

```neon
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:

```neon
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:

```neon
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:

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

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 valorilor
  • bool(), int(), float(), string() pentru turnarea fără pierderi a tipurilor
  • typed() pentru a genera o matrice a tuturor serviciilor de un tip specificat
  • tagged() 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