Nette Documentation Preview

syntax
Definiranje storitev
********************

.[perex]
Konfiguracija je mesto, kjer učimo DI vsebnik, kako naj sestavlja posamezne storitve in kako jih povezuje z drugimi odvisnostmi. Nette ponuja zelo pregleden in eleganten način, kako to doseči.

Sekcija `services` v konfiguracijski datoteki formata NEON je mesto, kjer definiramo lastne storitve in njihove konfiguracije. Poglejmo si preprost primer definicije storitve, imenovane `database`, ki predstavlja instanco razreda `PDO`:

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

Navedena konfiguracija bo vodila do naslednje tovarne metode v [DI vsebniku|container]:

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

Imena storitev nam omogočajo, da se nanje sklicujemo v drugih delih konfiguracijske datoteke, in sicer v formatu `@imeStoritve`. Če storitve ni treba poimenovati, lahko preprosto uporabimo le alinejo:

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

Za pridobitev storitve iz DI vsebnika lahko uporabimo metodo `getService()` z imenom storitve kot parametrom ali metodo `getByType()` s tipom storitve:

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


Ustvarjanje storitve
====================

Večinoma ustvarimo storitev preprosto tako, da ustvarimo instanco določenega razreda. Na primer:

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

Če moramo konfiguracijo razširiti z dodatnimi ključi, lahko definicijo razpišemo v več vrstic:

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

Ključ `create` ima alias `factory`, obe varianti sta v praksi pogosti. Vendar priporočamo uporabo `create`.

Argumenti konstruktorja ali ustvarjalne metode so lahko alternativno zapisani v ključu `arguments`:

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

Storitve ni treba ustvarjati le s preprostim ustvarjanjem instance razreda, lahko so tudi rezultat klica statičnih metod ali metod drugih storitev:

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

Opazite, da se za enostavnost namesto `->` uporablja `::`, glej [#Izrazna sredstva]. Generirale se bodo te tovarne metode:

```php
public function createServiceDatabase(): PDO
{
	return DatabaseFactory::create();
}

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

DI vsebnik mora poznati tip ustvarjene storitve. Če ustvarjamo storitev s pomočjo metode, ki nima specificiranega vrnjenega tipa, moramo ta tip eksplicitno navesti v konfiguraciji:

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


Argumenti
=========

V konstruktor in metode predajamo argumente na način, ki je zelo podoben kot v samem PHP:

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

Za boljšo berljivost lahko argumente razpišemo v ločene vrstice. V takem primeru je uporaba vejic neobvezna:

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

Argumente lahko tudi poimenujete in vam ni treba skrbeti za njihov vrstni red:

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

Če želite nekatere argumente izpustiti in uporabiti njihovo privzeto vrednost ali dodati storitev s pomočjo [autowiringa|autowiring], uporabite podčrtaj:

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

Kot argumente lahko predajate storitve, uporabljate parametre in še veliko več, glej [#Izrazna sredstva].


Setup
=====

V sekciji `setup` definiramo metode, ki se morajo poklicati pri ustvarjanju storitve.

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

To bi v PHP izgledalo takole:

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

Poleg klicanja metod lahko tudi predajate vrednosti v lastnosti. Podprto je tudi dodajanje elementa v polje, ki ga je treba zapisati v narekovajih, da ne pride do kolizije s sintakso NEON:

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

Kar bi v PHP kodi izgledalo takole:

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

V setupu lahko pa kličete tudi statične metode ali metode drugih storitev. Če morate kot argument predati trenutno storitev, jo navedite kot `@self`:

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

Opazite, da se za enostavnost namesto `->` uporablja `::`, glej [#Izrazna sredstva]. Generirala se bo takšna tovarna metoda:

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


Izrazna sredstva
================

Nette DI nam daje izjemno bogata izrazna sredstva, s katerimi lahko zapišemo skoraj karkoli. V konfiguracijskih datotekah lahko tako uporabljamo [parametre |configuration#Parametri]:

```neon
# parameter
%wwwDir%

# vrednost parametra pod ključem
%mailer.user%

# parameter znotraj niza
'%wwwDir%/images'
```

Nadalje ustvarjati objekte, klicati metode in funkcije:

```neon
# ustvarjanje objekta
DateTime()

# klic statične metode
Collator::create(%locale%)

# klic PHP funkcije
::getenv(DB_USER)
```

Sklicujemo se na storitve bodisi po njihovem imenu ali s pomočjo tipa:

```neon
# storitev po imenu
@database

# storitev po tipu
@Nette\Database\Connection
```

Uporabljati first-class callable sintakso: .{data-version:3.2.0}

```neon
# ustvarjanje povratnega klica, podobno [@user, logout]
@user::logout(...)
```

Uporabljati konstante:

```neon
# konstanta razreda
FilesystemIterator::SKIP_DOTS

# globalno konstanto dobimo s PHP funkcijo constant()
::constant(PHP_VERSION)
```

Klicanje metod lahko verižimo enako kot v PHP. Le za enostavnost se namesto `->` uporablja `::`:

```neon
DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')

@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()
```

Te izraze lahko uporabljate kjerkoli, pri [ustvarjanju storitev |#Ustvarjanje storitve], v [argumentih |#Argumenti], v sekciji [#setup] ali [parametrih |configuration#Parametri]:

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

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


Posebne funkcije
----------------

V konfiguracijskih datotekah lahko uporabljate te posebne funkcije:

- `not()` negacija vrednosti
- `bool()`, `int()`, `float()`, `string()` pretvorba brez izgube v dani tip
- `typed()` ustvari polje vseh storitev specificiranega tipa
- `tagged()` ustvari polje vseh storitev z dano oznako

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

V primerjavi s klasično pretvorbo v PHP, kot je npr. `(int)`, pretvorba brez izgube vrže izjemo za neštevilske vrednosti.

Funkcija `typed()` ustvari polje vseh storitev danega tipa (razred ali vmesnik). Izpusti storitve, ki imajo izklopljen autowiring. Lahko navedete tudi več tipov, ločenih z vejico.

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

Polje storitev določenega tipa lahko predajate kot argument tudi samodejno s pomočjo [autowiringa |autowiring#Polje storitev].

Funkcija `tagged()` pa ustvarja polje vseh storitev z določeno oznako. Tudi tukaj lahko specificirate več oznak, ločenih z vejico.

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


Autowiring
==========

Ključ `autowired` omogoča vplivanje na obnašanje autowiringa za specifično storitev. Za podrobnosti glej [poglavje o autowiringu|autowiring].

```neon
services:
	foo:
		create: Foo
		autowired: false     # storitev foo je izključena iz autowiringa
```


Lazy storitve .{data-version:3.2.4}
===================================

Lazy loading je tehnika, ki odloži ustvarjanje storitve do trenutka, ko je dejansko potrebna. V globalni konfiguraciji lahko [omogočite lazy ustvarjanje |configuration#Lene storitve] za vse storitve hkrati. Za posamezne storitve pa lahko to obnašanje prepišete:

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

Ko je storitev definirana kot lazy, ob njeni zahtevi iz DI vsebnika dobimo poseben nadomestni objekt. Ta izgleda in se obnaša enako kot dejanska storitev, vendar se dejanska inicializacija (klic konstruktorja in setupa) zgodi šele ob prvem klicu katerekoli njene metode ali lastnosti.

.[note]
Lazy loading je mogoče uporabiti samo za uporabniške razrede, ne pa za notranje PHP razrede. Zahteva PHP 8.4 ali novejšo različico.


Oznake
======

Oznake (tags) služijo za dodajanje dopolnilnih informacij k storitvam. Storitvi lahko dodate eno ali več oznak:

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

Oznake lahko nosijo tudi vrednosti:

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

Da bi dobili vse storitve z določenimi oznakami, lahko uporabite funkcijo `tagged()`:

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

V DI vsebniku lahko dobite imena vseh storitev z določeno oznako s pomočjo metode `findByTag()`:

```php
$names = $container->findByTag('logger');
// $names je polje, ki vsebuje ime storitve in vrednost oznake
// npr. ['foo' => 'monolog.logger.event', ...]
```


Način Inject
============

S pomočjo zastavice `inject: true` se aktivira predajanje odvisnosti preko javnih spremenljivk z anotacijo [inject |best-practices:inject-method-attribute#Atributi Inject] in metod [inject*() |best-practices:inject-method-attribute#Metode inject].

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

Privzeto je `inject` aktiviran samo za presenterje.


Modifikacija storitev
=====================

DI vsebnik vsebuje veliko storitev, ki so bile dodane preko vgrajene ali [uporabniške razširitve|extensions]. Definicije teh storitev lahko prilagodite neposredno v konfiguraciji. Na primer, lahko spremenite razred storitve `application.application`, ki je standardno `Nette\Application\Application`, na drugega:

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

Zastavica `alteration` je informativna in pove, da le modificiramo obstoječo storitev.

Lahko tudi dopolnimo setup:

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

Pri prepisovanju storitve lahko želimo odstraniti prvotne argumente, postavke setupa ali oznake, za kar služi `reset`:

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

Če želite odstraniti storitev, dodano z razširitvijo, lahko to storite takole:

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

Definiranje storitev

Konfiguracija je mesto, kjer učimo DI vsebnik, kako naj sestavlja posamezne storitve in kako jih povezuje z drugimi odvisnostmi. Nette ponuja zelo pregleden in eleganten način, kako to doseči.

Sekcija services v konfiguracijski datoteki formata NEON je mesto, kjer definiramo lastne storitve in njihove konfiguracije. Poglejmo si preprost primer definicije storitve, imenovane database, ki predstavlja instanco razreda PDO:

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

Navedena konfiguracija bo vodila do naslednje tovarne metode v DI vsebniku:

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

Imena storitev nam omogočajo, da se nanje sklicujemo v drugih delih konfiguracijske datoteke, in sicer v formatu @imeStoritve. Če storitve ni treba poimenovati, lahko preprosto uporabimo le alinejo:

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

Za pridobitev storitve iz DI vsebnika lahko uporabimo metodo getService() z imenom storitve kot parametrom ali metodo getByType() s tipom storitve:

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

Ustvarjanje storitve

Večinoma ustvarimo storitev preprosto tako, da ustvarimo instanco določenega razreda. Na primer:

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

Če moramo konfiguracijo razširiti z dodatnimi ključi, lahko definicijo razpišemo v več vrstic:

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

Ključ create ima alias factory, obe varianti sta v praksi pogosti. Vendar priporočamo uporabo create.

Argumenti konstruktorja ali ustvarjalne metode so lahko alternativno zapisani v ključu arguments:

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

Storitve ni treba ustvarjati le s preprostim ustvarjanjem instance razreda, lahko so tudi rezultat klica statičnih metod ali metod drugih storitev:

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

Opazite, da se za enostavnost namesto -> uporablja ::, glej Izrazna sredstva. Generirale se bodo te tovarne metode:

public function createServiceDatabase(): PDO
{
	return DatabaseFactory::create();
}

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

DI vsebnik mora poznati tip ustvarjene storitve. Če ustvarjamo storitev s pomočjo metode, ki nima specificiranega vrnjenega tipa, moramo ta tip eksplicitno navesti v konfiguraciji:

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

Argumenti

V konstruktor in metode predajamo argumente na način, ki je zelo podoben kot v samem PHP:

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

Za boljšo berljivost lahko argumente razpišemo v ločene vrstice. V takem primeru je uporaba vejic neobvezna:

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

Argumente lahko tudi poimenujete in vam ni treba skrbeti za njihov vrstni red:

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

Če želite nekatere argumente izpustiti in uporabiti njihovo privzeto vrednost ali dodati storitev s pomočjo autowiringa, uporabite podčrtaj:

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

Kot argumente lahko predajate storitve, uporabljate parametre in še veliko več, glej Izrazna sredstva.

Setup

V sekciji setup definiramo metode, ki se morajo poklicati pri ustvarjanju storitve.

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

To bi v PHP izgledalo takole:

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

Poleg klicanja metod lahko tudi predajate vrednosti v lastnosti. Podprto je tudi dodajanje elementa v polje, ki ga je treba zapisati v narekovajih, da ne pride do kolizije s sintakso NEON:

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

Kar bi v PHP kodi izgledalo takole:

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

V setupu lahko pa kličete tudi statične metode ali metode drugih storitev. Če morate kot argument predati trenutno storitev, jo navedite kot @self:

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

Opazite, da se za enostavnost namesto -> uporablja ::, glej Izrazna sredstva. Generirala se bo takšna tovarna metoda:

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

Izrazna sredstva

Nette DI nam daje izjemno bogata izrazna sredstva, s katerimi lahko zapišemo skoraj karkoli. V konfiguracijskih datotekah lahko tako uporabljamo parametre:

# parameter
%wwwDir%

# vrednost parametra pod ključem
%mailer.user%

# parameter znotraj niza
'%wwwDir%/images'

Nadalje ustvarjati objekte, klicati metode in funkcije:

# ustvarjanje objekta
DateTime()

# klic statične metode
Collator::create(%locale%)

# klic PHP funkcije
::getenv(DB_USER)

Sklicujemo se na storitve bodisi po njihovem imenu ali s pomočjo tipa:

# storitev po imenu
@database

# storitev po tipu
@Nette\Database\Connection

Uporabljati first-class callable sintakso:

# ustvarjanje povratnega klica, podobno [@user, logout]
@user::logout(...)

Uporabljati konstante:

# konstanta razreda
FilesystemIterator::SKIP_DOTS

# globalno konstanto dobimo s PHP funkcijo constant()
::constant(PHP_VERSION)

Klicanje metod lahko verižimo enako kot v PHP. Le za enostavnost se namesto -> uporablja :::

DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')

@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()

Te izraze lahko uporabljate kjerkoli, pri ustvarjanju storitev, v argumentih, v sekciji setup ali parametrih:

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

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

Posebne funkcije

V konfiguracijskih datotekah lahko uporabljate te posebne funkcije:

  • not() negacija vrednosti
  • bool(), int(), float(), string() pretvorba brez izgube v dani tip
  • typed() ustvari polje vseh storitev specificiranega tipa
  • tagged() ustvari polje vseh storitev z dano oznako
services:
	- Foo(
		id: int(::getenv('ProjectId'))
		productionMode: not(%debugMode%)
	)

V primerjavi s klasično pretvorbo v PHP, kot je npr. (int), pretvorba brez izgube vrže izjemo za neštevilske vrednosti.

Funkcija typed() ustvari polje vseh storitev danega tipa (razred ali vmesnik). Izpusti storitve, ki imajo izklopljen autowiring. Lahko navedete tudi več tipov, ločenih z vejico.

services:
	- BarsDependent( typed(Bar) )

Polje storitev določenega tipa lahko predajate kot argument tudi samodejno s pomočjo autowiringa.

Funkcija tagged() pa ustvarja polje vseh storitev z določeno oznako. Tudi tukaj lahko specificirate več oznak, ločenih z vejico.

services:
	- LoggersDependent( tagged(logger) )

Autowiring

Ključ autowired omogoča vplivanje na obnašanje autowiringa za specifično storitev. Za podrobnosti glej poglavje o autowiringu.

services:
	foo:
		create: Foo
		autowired: false     # storitev foo je izključena iz autowiringa

Lazy storitve

Lazy loading je tehnika, ki odloži ustvarjanje storitve do trenutka, ko je dejansko potrebna. V globalni konfiguraciji lahko omogočite lazy ustvarjanje za vse storitve hkrati. Za posamezne storitve pa lahko to obnašanje prepišete:

services:
	foo:
		create: Foo
		lazy: false

Ko je storitev definirana kot lazy, ob njeni zahtevi iz DI vsebnika dobimo poseben nadomestni objekt. Ta izgleda in se obnaša enako kot dejanska storitev, vendar se dejanska inicializacija (klic konstruktorja in setupa) zgodi šele ob prvem klicu katerekoli njene metode ali lastnosti.

Lazy loading je mogoče uporabiti samo za uporabniške razrede, ne pa za notranje PHP razrede. Zahteva PHP 8.4 ali novejšo različico.

Oznake

Oznake (tags) služijo za dodajanje dopolnilnih informacij k storitvam. Storitvi lahko dodate eno ali več oznak:

services:
	foo:
		create: Foo
		tags:
			- cached

Oznake lahko nosijo tudi vrednosti:

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

Da bi dobili vse storitve z določenimi oznakami, lahko uporabite funkcijo tagged():

services:
	- LoggersDependent( tagged(logger) )

V DI vsebniku lahko dobite imena vseh storitev z določeno oznako s pomočjo metode findByTag():

$names = $container->findByTag('logger');
// $names je polje, ki vsebuje ime storitve in vrednost oznake
// npr. ['foo' => 'monolog.logger.event', ...]

Način Inject

S pomočjo zastavice inject: true se aktivira predajanje odvisnosti preko javnih spremenljivk z anotacijo inject in metod inject*().

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

Privzeto je inject aktiviran samo za presenterje.

Modifikacija storitev

DI vsebnik vsebuje veliko storitev, ki so bile dodane preko vgrajene ali uporabniške razširitve. Definicije teh storitev lahko prilagodite neposredno v konfiguraciji. Na primer, lahko spremenite razred storitve application.application, ki je standardno Nette\Application\Application, na drugega:

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

Zastavica alteration je informativna in pove, da le modificiramo obstoječo storitev.

Lahko tudi dopolnimo setup:

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

Pri prepisovanju storitve lahko želimo odstraniti prvotne argumente, postavke setupa ali oznake, za kar služi reset:

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

Če želite odstraniti storitev, dodano z razširitvijo, lahko to storite takole:

services:
	cache.journal: false