Konfigurace DI kontejneru
*************************
.[perex]
Přehled konfiguračních voleb pro Nette DI kontejner.
Konfigurační soubor
===================
Nette DI kontejner se snadno ovládá pomocí konfiguračních souborů. Ty se obvykle zapisují ve [formátu NEON|neon:format]. K editaci doporučujeme [editory s podporou |tools:ide] tohoto formátu.
<pre>
"decorator .[prism-token prism-atrule]":[#decorator]: "Dekorátor .[prism-token prism-comment]"<br>
"di .[prism-token prism-atrule]":[#DI]: "DI kontejner .[prism-token prism-comment]"<br>
"extensions .[prism-token prism-atrule]":[#Rozšíření]: "Instalace dalších DI rozšíření .[prism-token prism-comment]"<br>
"includes .[prism-token prism-atrule]":[#Vkládání souborů]: "Vkládání souborů .[prism-token prism-comment]"<br>
"parameters .[prism-token prism-atrule]":[#parametry]: "Parametry .[prism-token prism-comment]"<br>
"search .[prism-token prism-atrule]":[#Search]: "Automatická registrace služeb .[prism-token prism-comment]"<br>
"services .[prism-token prism-atrule]":[services]: "Služby .[prism-token prism-comment]"
</pre>
.[note]
Chcete-li zapsat řetězec obsahující znak `%`, musíte jej escapovat zdvojením na `%%`.
Parametry
=========
V konfiguraci můžete definovat parametry, které lze pak použít jako součást definic služeb. Můžete tak zpřehlednit konfiguraci nebo sjednotit a vyčlenit hodnoty, které se budou měnit.
```neon
parameters:
dsn: 'mysql:host=127.0.0.1;dbname=test'
user: root
password: secret
```
Na parametr `dsn` se odkážeme kdekoliv v konfiguraci zápisem `%dsn%`. Parametry lze používat i uvnitř řetězců jako `'%wwwDir%/images'`.
Parametry nemusí být jen řetězce nebo čísla, mohou také obsahovat pole:
```neon
parameters:
mailer:
host: smtp.example.com
secure: ssl
user: franta@gmail.com
languages: [cs, en, de]
```
Na konkrétní klíč se odkážeme jako `%mailer.user%`.
Pokud potřebujete ve vašem kódu, například třídě, zjistit hodnotu jakéhokoliv parametru, tak jej do této třídy předejte. Například v konstruktoru. Neexistuje žádný globální objekt představující konfiguraci, kterého by se třídy dotazovaly na hodnoty parametrů. To by bylo porušením principu dependency injection.
Služby
======
Viz [samostatná kapitola|services].
Decorator
=========
Jak upravit hromadně všechny služby určitého typu? Třeba zavolat určitou metodu u všech presenterů, které dědí od konkrétního společného předka? Od toho je tu decorator.
```neon
decorator:
# u všech služeb, co jsou instancí této třídy nebo rozhraní
App\Presentation\BasePresenter:
setup:
- setProjectId(10) # zavolej tuto metodu
- $absoluteUrls = true # a nastav proměnnou
```
Decorator se dá používat také pro nastavení [tagů |services#Tagy] nebo zapnutí režimu [inject |services#Režim Inject].
```neon
decorator:
InjectableInterface:
tags: [mytag: 1]
inject: true
```
DI
===
Technické nastavení DI kontejneru.
```neon
di:
# zobrazit DIC v Tracy Bar?
debugger: ... # (bool) výchozí je autodetekce (zapne se, když je přítomná Tracy)
# typy parametrů, které nikdy neautowirovat
excluded: ... # (string[])
# povolit lazy vytváření služeb?
lazy: ... # (bool) výchozí je false
# třída, od které dědí DI kontejner
parentClass: ... # (string) výchozí je Nette\DI\Container
```
Lazy služby .{data-version:3.2.4}
---------------------------------
Nastavení `lazy: true` aktivuje lazy (odložené) vytváření služeb. To znamená, že služby nejsou skutečně vytvořeny v okamžiku, kdy si je vyžádáme z DI kontejneru, ale až ve chvíli jejich prvního použití. Což může zrychlit start aplikace a snížit paměťové nároky, protože se vytváří jen ty služby, které jsou v daném požadavku skutečně potřeba.
U konkrétní služby lze lazy vytváření [změnit |services#Lazy služby].
.[note]
Lazy objekty lze použít pouze pro uživatelské třídy, nikoliv pro interní PHP třídy. Vyžaduje PHP 8.4 nebo novější.
Export metadat
--------------
Třída DI kontejneru obsahuje i spoustu metadat. Můžete ji zmenšit tím, že export metadat zredukujete.
```neon
di:
export:
# exportovat parametry?
parameters: false # (bool) výchozí je true
# exportovat tagy a které?
tags: # (string[]|bool) výchozí jsou všechny
- event.subscriber
# exportovat data pro autowiring a které?
types: # (string[]|bool) výchozí jsou všechny
- Nette\Database\Connection
- Symfony\Component\Console\Application
```
Pokud nevyužíváte pole `$container->getParameters()`, můžete vypnout export parametrů. Dále můžete exportovat jen ty tagy, přes které získáváte služby metodou `$container->findByTag(...)`. Pokud metodu nevoláte vůbec, můžete zcela vypnout export tagů pomocí `false`.
Výrazně můžete zredukovat metadata pro [autowiring] tím, že uvedete třídy, které používáte jako parametr metody `$container->getByType()`. A opět, pokud metodu nevoláte vůbec (resp. jen v [bootstrapu|application:bootstrapping] pro získání `Nette\Application\Application`), můžete export úplně vypnout pomocí `false`.
Rozšíření
=========
Registrace dalších DI rozšíření. Tímto způsobem přidáme např. DI rozšíření `Dibi\Bridges\Nette\DibiExtension3` pod názvem `dibi`:
```neon
extensions:
dibi: Dibi\Bridges\Nette\DibiExtension3
```
Následně ho tedy konfigurujeme v sekci `dibi`:
```neon
dibi:
host: localhost
```
Jako rozšíření lze přidat i třídu, která má parametry:
```neon
extensions:
application: Nette\Bridges\ApplicationDI\ApplicationExtension(%debugMode%, [%appDir%], %tempDir%/cache)
```
Vkládání souborů
================
Další konfigurační soubory můžeme vložit v sekci `includes`:
```neon
includes:
- parameters.php
- services.neon
- presenters.neon
```
Název `parameters.php` není překlep, konfigurace může být zapsaná také v PHP souboru, který ji vrátí jako pole:
```php
<?php
return [
'database' => [
'main' => [
'dsn' => 'sqlite::memory:',
],
],
];
```
Pokud se v konfiguračních souborech objeví prvky se stejnými klíči, budou přepsány, nebo v případě [polí sloučeny |#Slučování]. Později vkládaný soubor má vyšší prioritu než předchozí. Soubor, ve kterém je sekce `includes` uvedena, má vyšší prioritu než v něm vkládané soubory.
Search
======
Automatické přidávání služeb do DI kontejneru nesmírně zpříjemňuje práci. Nette automaticky přidává do kontejneru presentery, lze však snadno přidávat i jakékoliv jiné třídy.
Stačí uvést, ve kterých adresářích (a podadresářích) má třídy hledat:
```neon
search:
- in: %appDir%/Forms
- in: %appDir%/Model
```
Pokud vám stačí jediné pravidlo hledání, můžete seznam vynechat a jeho klíče zapsat přímo pod `search`:
```neon
search:
in: %appDir%
```
Obvykle ovšem nechceme přidávat úplně všechny třídy a rozhraní, proto je můžeme filtrovat:
```neon
search:
- in: %appDir%/Forms
# filtrování podle názvu souboru (string|string[])
files:
- *Factory.php
# filtrování podle názvu třídy (string|string[])
classes:
- *Factory
```
Nebo můžeme vybírat třídy, které dědí či implementují alespoň jednu z uvedených tříd:
```neon
search:
- in: %appDir%
extends:
- App\*Form
implements:
- App\*FormInterface
```
Lze definovat i vylučující pravidla, tj. masky názvu třídy nebo dědičné předky; pokud jim třída vyhovuje, služba se do DI kontejneru nepřidá:
```neon
search:
- in: %appDir%
exclude:
files: ...
classes: ...
extends: ...
implements: ...
```
Všem automaticky registrovaným službám lze nastavit tagy:
```neon
search:
- in: %appDir%
tags: ...
```
Kromě tříd zaregistruje hledání i rozhraní, která mají jedinou metodu `create()` nebo `get()`, a to jako [generované továrny nebo accessory |factory]. Třídy, pro které už je v kontejneru zaregistrovaná služba stejného typu, se přeskočí, takže nevznikají duplicity.
Slučování
=========
Pokud se ve více konfiguračních souborech objeví prvky se stejnými klíči, budou přepsány, nebo v případě polí sloučeny. Později vkládaný soubor má vyšší prioritu než předchozí.
<table class=table>
<tr>
<th width=33%>config1.neon</th>
<th width=33%>config2.neon</th>
<th>výsledek</th>
</tr>
<tr>
<td>
```neon
items:
- 1
- 2
```
</td>
<td>
```neon
items:
- 3
```
</td>
<td>
```neon
items:
- 1
- 2
- 3
```
</td>
</tr>
</table>
U polí lze zabránit slučování uvedením vykřičníku za názvem klíče:
<table class=table>
<tr>
<th width=33%>config1.neon</th>
<th width=33%>config2.neon</th>
<th>výsledek</th>
</tr>
<tr>
<td>
```neon
items:
- 1
- 2
```
</td>
<td>
```neon
items!:
- 3
```
</td>
<td>
```neon
items:
- 3
```
</td>
</tr>
</table>
{{maintitle: Konfigurace DI kontejneru v Nette: služby a parametry}}
{{description: Konfigurace DI kontejneru Nette v NEON: parametry, služby, decorator, rozšíření, vkládání souborů, vyhledávání služeb a slučování konfigurací.}}
Konfigurace DI kontejneru
Přehled konfiguračních voleb pro Nette DI kontejner.
Konfigurační soubor
Nette DI kontejner se snadno ovládá pomocí konfiguračních souborů. Ty se obvykle zapisují ve formátu NEON. K editaci doporučujeme editory s podporou tohoto formátu.
decorator:
di:
extensions:
includes:
parameters:
search:
services:
Chcete-li zapsat řetězec obsahující znak %, musíte jej escapovat zdvojením na
%%.
Parametry
V konfiguraci můžete definovat parametry, které lze pak použít jako součást definic služeb. Můžete tak zpřehlednit
konfiguraci nebo sjednotit a vyčlenit hodnoty, které se budou měnit.
parameters:
dsn: 'mysql:host=127.0.0.1;dbname=test'
user: root
password: secret
Na parametr dsn se odkážeme kdekoliv v konfiguraci zápisem %dsn%. Parametry lze používat
i uvnitř řetězců jako '%wwwDir%/images'.
Parametry nemusí být jen řetězce nebo čísla, mohou také obsahovat pole:
parameters:
mailer:
host: smtp.example.com
secure: ssl
user: franta@gmail.com
languages: [cs, en, de]
Na konkrétní klíč se odkážeme jako %mailer.user%.
Pokud potřebujete ve vašem kódu, například třídě, zjistit hodnotu jakéhokoliv parametru, tak jej do této třídy
předejte. Například v konstruktoru. Neexistuje žádný globální objekt představující konfiguraci, kterého by se třídy
dotazovaly na hodnoty parametrů. To by bylo porušením principu dependency injection.
Služby
Viz samostatná kapitola.
Decorator
Jak upravit hromadně všechny služby určitého typu? Třeba zavolat určitou metodu u všech presenterů, které dědí od
konkrétního společného předka? Od toho je tu decorator.
decorator:
# u všech služeb, co jsou instancí této třídy nebo rozhraní
App\Presentation\BasePresenter:
setup:
- setProjectId(10) # zavolej tuto metodu
- $absoluteUrls = true # a nastav proměnnou
Decorator se dá používat také pro nastavení tagů nebo zapnutí režimu inject.
decorator:
InjectableInterface:
tags: [mytag: 1]
inject: true
DI
Technické nastavení DI kontejneru.
di:
# zobrazit DIC v Tracy Bar?
debugger: ... # (bool) výchozí je autodetekce (zapne se, když je přítomná Tracy)
# typy parametrů, které nikdy neautowirovat
excluded: ... # (string[])
# povolit lazy vytváření služeb?
lazy: ... # (bool) výchozí je false
# třída, od které dědí DI kontejner
parentClass: ... # (string) výchozí je Nette\DI\Container
Lazy služby
Nastavení lazy: true aktivuje lazy (odložené) vytváření služeb. To znamená, že služby nejsou skutečně
vytvořeny v okamžiku, kdy si je vyžádáme z DI kontejneru, ale až ve chvíli jejich prvního použití. Což může
zrychlit start aplikace a snížit paměťové nároky, protože se vytváří jen ty služby, které jsou v daném požadavku
skutečně potřeba.
U konkrétní služby lze lazy vytváření změnit.
Lazy objekty lze použít pouze pro uživatelské třídy, nikoliv pro interní PHP třídy. Vyžaduje PHP
8.4 nebo novější.
Třída DI kontejneru obsahuje i spoustu metadat. Můžete ji zmenšit tím, že export metadat zredukujete.
di:
export:
# exportovat parametry?
parameters: false # (bool) výchozí je true
# exportovat tagy a které?
tags: # (string[]|bool) výchozí jsou všechny
- event.subscriber
# exportovat data pro autowiring a které?
types: # (string[]|bool) výchozí jsou všechny
- Nette\Database\Connection
- Symfony\Component\Console\Application
Pokud nevyužíváte pole $container->getParameters(), můžete vypnout export parametrů. Dále můžete
exportovat jen ty tagy, přes které získáváte služby metodou $container->findByTag(...). Pokud metodu
nevoláte vůbec, můžete zcela vypnout export tagů pomocí false.
Výrazně můžete zredukovat metadata pro autowiring
tím, že uvedete třídy, které používáte jako parametr metody $container->getByType(). A opět, pokud
metodu nevoláte vůbec (resp. jen v bootstrapu pro získání
Nette\Application\Application), můžete export úplně vypnout pomocí false.
Rozšíření
Registrace dalších DI rozšíření. Tímto způsobem přidáme např. DI rozšíření
Dibi\Bridges\Nette\DibiExtension3 pod názvem dibi:
extensions:
dibi: Dibi\Bridges\Nette\DibiExtension3
Následně ho tedy konfigurujeme v sekci dibi:
dibi:
host: localhost
Jako rozšíření lze přidat i třídu, která má parametry:
extensions:
application: Nette\Bridges\ApplicationDI\ApplicationExtension(%debugMode%, [%appDir%], %tempDir%/cache)
Vkládání souborů
Další konfigurační soubory můžeme vložit v sekci includes:
includes:
- parameters.php
- services.neon
- presenters.neon
Název parameters.php není překlep, konfigurace může být zapsaná také v PHP souboru, který ji vrátí
jako pole:
<?php
return [
'database' => [
'main' => [
'dsn' => 'sqlite::memory:',
],
],
];
Pokud se v konfiguračních souborech objeví prvky se stejnými klíči, budou přepsány, nebo v případě polí sloučeny. Později vkládaný soubor má vyšší prioritu než předchozí. Soubor, ve kterém
je sekce includes uvedena, má vyšší prioritu než v něm vkládané soubory.
Search
Automatické přidávání služeb do DI kontejneru nesmírně zpříjemňuje práci. Nette automaticky přidává do
kontejneru presentery, lze však snadno přidávat i jakékoliv jiné třídy.
Stačí uvést, ve kterých adresářích (a podadresářích) má třídy hledat:
search:
- in: %appDir%/Forms
- in: %appDir%/Model
Pokud vám stačí jediné pravidlo hledání, můžete seznam vynechat a jeho klíče zapsat přímo pod
search:
search:
in: %appDir%
Obvykle ovšem nechceme přidávat úplně všechny třídy a rozhraní, proto je můžeme filtrovat:
search:
- in: %appDir%/Forms
# filtrování podle názvu souboru (string|string[])
files:
- *Factory.php
# filtrování podle názvu třídy (string|string[])
classes:
- *Factory
Nebo můžeme vybírat třídy, které dědí či implementují alespoň jednu z uvedených tříd:
search:
- in: %appDir%
extends:
- App\*Form
implements:
- App\*FormInterface
Lze definovat i vylučující pravidla, tj. masky názvu třídy nebo dědičné předky; pokud jim třída vyhovuje, služba
se do DI kontejneru nepřidá:
search:
- in: %appDir%
exclude:
files: ...
classes: ...
extends: ...
implements: ...
Všem automaticky registrovaným službám lze nastavit tagy:
search:
- in: %appDir%
tags: ...
Kromě tříd zaregistruje hledání i rozhraní, která mají jedinou metodu create() nebo get(), a
to jako generované továrny nebo accessory. Třídy, pro
které už je v kontejneru zaregistrovaná služba stejného typu, se přeskočí, takže nevznikají duplicity.
Slučování
Pokud se ve více konfiguračních souborech objeví prvky se stejnými klíči, budou přepsány, nebo v případě polí
sloučeny. Později vkládaný soubor má vyšší prioritu než předchozí.
| config1.neon |
config2.neon |
výsledek |
items:
- 1
- 2
|
items:
- 3
|
items:
- 1
- 2
- 3
|
U polí lze zabránit slučování uvedením vykřičníku za názvem klíče:
| config1.neon |
config2.neon |
výsledek |
items:
- 1
- 2
|
items!:
- 3
|
items:
- 3
|