Nette Documentation Preview

syntax
Definirea serviciilor
*********************

.[perex]
Configurația este locul unde învățăm containerul DI cum să asambleze serviciile individuale și cum să le conecteze cu alte dependențe. Nette oferă o modalitate foarte clară și elegantă de a realiza acest lucru.

Secțiunea `services` din fișierul de configurație în format NEON este locul unde definim serviciile proprii și configurațiile lor. Să vedem un exemplu simplu de definire a unui serviciu numit `database`, care reprezintă o instanță a clasei `PDO`:

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

Configurația menționată va rezulta în următoarea metodă factory în [containerul DI|container]:

```php
public function createServiceDatabase(): PDO
{
	return new PDO('sqlite::memory:');
}
```

Numele serviciilor ne permit să ne referim la ele în alte părți ale fișierului de configurație, în formatul `@numeServiciu`. Dacă nu este necesar să numim serviciul, putem folosi pur și simplu doar o liniuță:

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

Pentru a obține 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 serviciului
===================

De cele mai multe ori, creăm un serviciu pur și simplu prin crearea unei instanțe a unei anumite clase. De exemplu:

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

Dacă avem nevoie să extindem configurația cu alte chei, definiția poate fi împărțită pe mai multe rânduri:

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

Cheia `create` are aliasul `factory`, ambele variante sunt comune în practică. Cu toate acestea, recomandăm utilizarea `create`.

Argumentele constructorului sau ale metodei de creare pot fi alternativ scrise în cheia `arguments`:

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

Serviciile nu trebuie create doar prin simpla instanțiere a unei clase, ele pot fi, de asemenea, rezultatul apelării metodelor statice sau metodelor altor servicii:

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

Observați că, pentru simplitate, în loc de `->` se folosește `::`, vezi [#Expresii]. Se vor genera aceste metode factory:

```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 specificat tipul returnat, trebuie să specificăm explicit acest tip în configurație:

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


Argumente
=========

Transmitem argumente constructorului și metodelor într-un mod foarte similar cu cel din PHP însuși:

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

Pentru o mai bună lizibilitate, putem împărți argumentele pe rânduri separate. În acest caz, utilizarea virgulelor este opțională:

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

Puteți, de asemenea, să numiți argumentele și nu trebuie să vă mai 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 unele argumente și să folosiți valoarea lor implicită sau să injectați un serviciu folosind [autowiring |autowiring], utilizați underscore `_`:

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

Ca argumente se pot transmite servicii, se pot utiliza parametri și multe altele, vezi [#Expresii].


Setup
=====

În secțiunea `setup` definim metodele care trebuie apelate la crearea serviciului.

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

Acest lucru ar arăta astfel în PHP:

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

Pe lângă apelarea metodelor, se pot transmite și valori către proprietăți. Este suportată și adăugarea unui element într-un array, care trebuie scris între ghilimele pentru a nu intra în conflict cu sintaxa NEON:

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

Ceea ce în codul PHP ar arăta astfel:

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

În setup se pot apela însă și metode statice sau metode ale altor servicii. Dacă aveți nevoie să transmiteți serviciul curent ca argument, specificați-l ca `@self`:

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

Observați că, pentru simplitate, în loc de `->` se folosește `::`, vezi [#Expresii]. Se va genera o astfel de metodă factory:

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


Expresii
========

Nette DI ne oferă expresii extrem de bogate, cu ajutorul cărora putem scrie aproape orice. În fișierele de configurație putem astfel utiliza [parametri |configuration#Parametri]:

```neon
# parametru
%wwwDir%

# valoarea parametrului sub cheie
%mailer.user%

# parametru în interiorul șirului
'%wwwDir%/images'
```

Mai departe, putem crea obiecte, apela metode și funcții:

```neon
# crearea obiectului
DateTime()

# apelarea metodei statice
Collator::create(%locale%)

# apelarea funcției PHP
::getenv(DB_USER)
```

Ne putem referi la servicii fie după numele lor, fie după tip:

```neon
# serviciu după nume
@database

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

Putem folosi sintaxa first-class callable: .{data-version:3.2.0}

```neon
# crearea callback-ului, echivalent cu [@user, logout]
@user::logout(...)
```

Putem folosi constante:

```neon
# constanta clasei
FilesystemIterator::SKIP_DOTS

# constanta globală o obținem cu funcția PHP constant()
::constant(PHP_VERSION)
```

Apelurile metodelor pot fi înlănțuite la fel ca în PHP. Doar pentru simplitate, în loc de `->` se folosește `::`:

```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 le puteți utiliza oriunde, la [crearea serviciilor |#Crearea serviciului], în [#argumente], în secțiunea [#Setup] sau în [parametri |configuration#Parametri]:

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

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


Funcții speciale
----------------

În fișierele de configurație puteți utiliza aceste funcții speciale:

- `not()` negația valorii
- `bool()`, `int()`, `float()`, `string()` conversie de tip fără pierderi la tipul specificat
- `typed()` creează un array al tuturor serviciilor de tipul specificat
- `tagged()` creează un array al tuturor serviciilor cu tag-ul dat

```neon
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)
```

Spre deosebire de conversia de tip clasică în PHP, cum ar fi de ex. `(int)`, conversia de tip fără pierderi va arunca o excepție pentru valorile non-numerice.

Funcția `typed()` creează un array al tuturor serviciilor de tipul dat (clasă sau interfață). Omite serviciile care au autowiring-ul dezactivat. Se pot specifica și mai multe tipuri separate prin virgulă.

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

Puteți transmite array-ul de servicii de un anumit tip ca argument și automat folosind [autowiring |autowiring#Array de servicii].

Funcția `tagged()` creează apoi un array al tuturor serviciilor cu un anumit tag. Și aici puteți specifica mai multe tag-uri separate prin virgulă.

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


Autowiring
==========

Cheia `autowired` permite influențarea comportamentului autowiring-ului pentru un serviciu specific. Pentru detalii, vezi [capitolul despre autowiring|autowiring].

```neon
services:
	foo:
		create: Foo
		autowired: false     # serviciul foo este exclus din autowiring
```


Servicii lazy .{data-version:3.2.4}
===================================

Încărcarea leneșă (Lazy loading) este o tehnică care amână crearea unui serviciu până în momentul în care este efectiv necesar. În configurația globală se poate [permite crearea lazy |configuration#Servicii lazy] pentru toate serviciile simultan. Pentru servicii individuale, puteți apoi suprascrie acest comportament:

```neon
services:
	foo:
		create: Foo
		lazy: false
```

Când un serviciu este definit ca lazy, la solicitarea sa din containerul DI, primim un obiect substituent special. Acesta arată și se comportă la fel ca serviciul real, dar inițializarea reală (apelarea constructorului și a setup-ului) are loc abia la primul apel al oricărei metode sau proprietăți ale sale.

.[note]
Încărcarea leneșă poate fi utilizată numai pentru clasele definite de utilizator, nu și pentru clasele interne PHP. Necesită PHP 8.4 sau o versiune mai recentă.


Tag-uri
=======

Tag-urile servesc la adăugarea de informații suplimentare serviciilor. Puteți adăuga unul sau mai multe tag-uri unui serviciu:

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

Tag-urile pot purta și valori:

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

Pentru a obține toate serviciile cu anumite tag-uri, puteți utiliza funcția `tagged()`:

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

În containerul DI puteți obține numele tuturor serviciilor cu un anumit tag folosind metoda `findByTag()`:

```php
$names = $container->findByTag('logger');
// $names este un array care conține numele serviciului și valoarea tag-ului
// de ex. ['foo' => 'monolog.logger.event', ...]
```


Mod Inject
==========

Folosind flag-ul `inject: true` se activează transmiterea dependențelor prin proprietăți publice cu adnotarea [inject |best-practices:inject-method-attribute#Atribute Inject] și metodele [inject*() |best-practices:inject-method-attribute#Metode inject].

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

În mod implicit, `inject` este activat doar pentru presenteri.


Modificarea serviciilor
=======================

Containerul DI conține multe servicii care au fost adăugate prin extensii încorporate sau [extensii utilizator|extensions]. Puteți modifica definițiile acestor servicii direct în configurație. De exemplu, puteți schimba clasa serviciului `application.application`, care este standard `Nette\Application\Application`, cu alta:

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

Flag-ul `alteration` este informativ și indică faptul că doar modificăm un serviciu existent.

Putem, de asemenea, completa setup-ul:

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

La suprascrierea unui serviciu, putem dori să eliminăm argumentele originale, elementele setup sau tag-urile, pentru aceasta folosim `reset`:

```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, o puteți face astfel:

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

Definirea serviciilor

Configurația este locul unde învățăm containerul DI cum să asambleze serviciile individuale și cum să le conecteze cu alte dependențe. Nette oferă o modalitate foarte clară și elegantă de a realiza acest lucru.

Secțiunea services din fișierul de configurație în format NEON este locul unde definim serviciile proprii și configurațiile lor. Să vedem un exemplu simplu de definire a unui serviciu numit database, care reprezintă o instanță a clasei PDO:

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

Configurația menționată va rezulta în următoarea metodă factory în containerul DI:

public function createServiceDatabase(): PDO
{
	return new PDO('sqlite::memory:');
}

Numele serviciilor ne permit să ne referim la ele în alte părți ale fișierului de configurație, în formatul @numeServiciu. Dacă nu este necesar să numim serviciul, putem folosi pur și simplu doar o liniuță:

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

Pentru a obține 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 serviciului

De cele mai multe ori, creăm un serviciu pur și simplu prin crearea unei instanțe a unei anumite clase. De exemplu:

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

Dacă avem nevoie să extindem configurația cu alte chei, definiția poate fi împărțită pe mai multe rânduri:

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

Cheia create are aliasul factory, ambele variante sunt comune în practică. Cu toate acestea, recomandăm utilizarea create.

Argumentele constructorului sau ale metodei de creare pot fi alternativ scrise în cheia arguments:

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

Serviciile nu trebuie create doar prin simpla instanțiere a unei clase, ele pot fi, de asemenea, rezultatul apelării metodelor statice sau metodelor altor servicii:

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

Observați că, pentru simplitate, în loc de -> se folosește ::, vezi Expresii. Se vor genera aceste metode factory:

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 specificat tipul returnat, trebuie să specificăm explicit acest tip în configurație:

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

Argumente

Transmitem argumente constructorului și metodelor într-un mod foarte similar cu cel din PHP însuși:

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

Pentru o mai bună lizibilitate, putem împărți argumentele pe rânduri separate. În acest caz, utilizarea virgulelor este opțională:

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

Puteți, de asemenea, să numiți argumentele și nu trebuie să vă mai 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 unele argumente și să folosiți valoarea lor implicită sau să injectați un serviciu folosind autowiring, utilizați underscore _:

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

Ca argumente se pot transmite servicii, se pot utiliza parametri și multe altele, vezi Expresii.

Setup

În secțiunea setup definim metodele care trebuie apelate la crearea serviciului.

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

Acest lucru ar arăta astfel în PHP:

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

Pe lângă apelarea metodelor, se pot transmite și valori către proprietăți. Este suportată și adăugarea unui element într-un array, care trebuie scris între ghilimele pentru a nu intra în conflict cu sintaxa NEON:

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

Ceea ce în codul PHP ar arăta astfel:

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

În setup se pot apela însă și metode statice sau metode ale altor servicii. Dacă aveți nevoie să transmiteți serviciul curent ca argument, specificați-l ca @self:

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

Observați că, pentru simplitate, în loc de -> se folosește ::, vezi Expresii. Se va genera o astfel de metodă factory:

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

Expresii

Nette DI ne oferă expresii extrem de bogate, cu ajutorul cărora putem scrie aproape orice. În fișierele de configurație putem astfel utiliza parametri:

# parametru
%wwwDir%

# valoarea parametrului sub cheie
%mailer.user%

# parametru în interiorul șirului
'%wwwDir%/images'

Mai departe, putem crea obiecte, apela metode și funcții:

# crearea obiectului
DateTime()

# apelarea metodei statice
Collator::create(%locale%)

# apelarea funcției PHP
::getenv(DB_USER)

Ne putem referi la servicii fie după numele lor, fie după tip:

# serviciu după nume
@database

# serviciu după tip
@Nette\Database\Connection

Putem folosi sintaxa first-class callable:

# crearea callback-ului, echivalent cu [@user, logout]
@user::logout(...)

Putem folosi constante:

# constanta clasei
FilesystemIterator::SKIP_DOTS

# constanta globală o obținem cu funcția PHP constant()
::constant(PHP_VERSION)

Apelurile metodelor pot fi înlănțuite la fel ca în PHP. Doar pentru simplitate, în loc de -> se folosește :::

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 le puteți utiliza oriunde, la crearea serviciilor, în argumente, în secțiunea Setup sau în parametri:

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

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

Funcții speciale

În fișierele de configurație puteți utiliza aceste funcții speciale:

  • not() negația valorii
  • bool(), int(), float(), string() conversie de tip fără pierderi la tipul specificat
  • typed() creează un array al tuturor serviciilor de tipul specificat
  • tagged() creează un array al tuturor serviciilor cu tag-ul dat
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

Spre deosebire de conversia de tip clasică în PHP, cum ar fi de ex. (int), conversia de tip fără pierderi va arunca o excepție pentru valorile non-numerice.

Funcția typed() creează un array al tuturor serviciilor de tipul dat (clasă sau interfață). Omite serviciile care au autowiring-ul dezactivat. Se pot specifica și mai multe tipuri separate prin virgulă.

services:
	- BarsDependent( typed(Bar) )

Puteți transmite array-ul de servicii de un anumit tip ca argument și automat folosind autowiring.

Funcția tagged() creează apoi un array al tuturor serviciilor cu un anumit tag. Și aici puteți specifica mai multe tag-uri separate prin virgulă.

services:
	- LoggersDependent( tagged(logger) )

Autowiring

Cheia autowired permite influențarea comportamentului autowiring-ului pentru un serviciu specific. Pentru detalii, vezi capitolul despre autowiring.

services:
	foo:
		create: Foo
		autowired: false     # serviciul foo este exclus din autowiring

Servicii lazy

Încărcarea leneșă (Lazy loading) este o tehnică care amână crearea unui serviciu până în momentul în care este efectiv necesar. În configurația globală se poate permite crearea lazy pentru toate serviciile simultan. Pentru servicii individuale, puteți apoi suprascrie acest comportament:

services:
	foo:
		create: Foo
		lazy: false

Când un serviciu este definit ca lazy, la solicitarea sa din containerul DI, primim un obiect substituent special. Acesta arată și se comportă la fel ca serviciul real, dar inițializarea reală (apelarea constructorului și a setup-ului) are loc abia la primul apel al oricărei metode sau proprietăți ale sale.

Încărcarea leneșă poate fi utilizată numai pentru clasele definite de utilizator, nu și pentru clasele interne PHP. Necesită PHP 8.4 sau o versiune mai recentă.

Tag-uri

Tag-urile servesc la adăugarea de informații suplimentare serviciilor. Puteți adăuga unul sau mai multe tag-uri unui serviciu:

services:
	foo:
		create: Foo
		tags:
			- cached

Tag-urile pot purta și valori:

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

Pentru a obține toate serviciile cu anumite tag-uri, puteți utiliza funcția tagged():

services:
	- LoggersDependent( tagged(logger) )

În containerul DI puteți obține numele tuturor serviciilor cu un anumit tag folosind metoda findByTag():

$names = $container->findByTag('logger');
// $names este un array care conține numele serviciului și valoarea tag-ului
// de ex. ['foo' => 'monolog.logger.event', ...]

Mod Inject

Folosind flag-ul inject: true se activează transmiterea dependențelor prin proprietăți publice cu adnotarea inject și metodele inject*().

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

În mod implicit, inject este activat doar pentru presenteri.

Modificarea serviciilor

Containerul DI conține multe servicii care au fost adăugate prin extensii încorporate sau extensii utilizator. Puteți modifica definițiile acestor servicii direct în configurație. De exemplu, puteți schimba clasa serviciului application.application, care este standard Nette\Application\Application, cu alta:

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

Flag-ul alteration este informativ și indică faptul că doar modificăm un serviciu existent.

Putem, de asemenea, completa setup-ul:

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

La suprascrierea unui serviciu, putem dori să eliminăm argumentele originale, elementele setup sau tag-urile, pentru aceasta folosim reset:

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

Dacă doriți să eliminați un serviciu adăugat de o extensie, o puteți face astfel:

services:
	cache.journal: false