Nette Documentation Preview

syntax
Pojemnik Nette DI
*****************

.[perex]
Nette DI to jedna z najciekawszych bibliotek Nette. Może generować i automatycznie aktualizować skompilowane kontenery DI, które są niezwykle szybkie i niesamowicie łatwe do skonfigurowania.

Forma usług, które mają być tworzone przez kontener DI, jest zwykle definiowana za pomocą plików konfiguracyjnych w [formacie NEON |neon:format]. Kontener, który ręcznie stworzyliśmy w [poprzednim rozdziale |container], zostałby zapisany w następujący sposób:

```neon
parameters:
	db:
		dsn: 'mysql:'
		user: root
		password: '***'

services:
	- Nette\Database\Connection(%db.dsn%, %db.user%, %db.password%)
	- ArticleFactory
	- UserController
```

Zapis jest naprawdę krótki.

Wszystkie zależności zadeklarowane w konstruktorach klas `ArticleFactory` i `UserController` są wykrywane i przekazywane przez samo Nette DI dzięki tzw. [autowiringowi |autowiring], więc nie trzeba niczego określać w pliku konfiguracyjnym.
Więc nawet jeśli parametry się zmienią, nie musisz zmieniać niczego w konfiguracji. Nette automatycznie zregeneruje kontener. Tam możesz skupić się wyłącznie na tworzeniu aplikacji.

Jeśli chcemy przekazać zależności za pomocą setterów, używamy do tego sekcji [setup |services#Setup].

Nette DI wygeneruje bezpośrednio kod PHP dla kontenera. Wynikiem jest więc plik `.php`, który możesz otworzyć i przestudiować. Dzięki temu możesz zobaczyć dokładnie jak działa kontener. Możesz także debugować go w IDE i przechodzić przez niego krok po kroku. I co najważniejsze: wygenerowany PHP jest niezwykle szybki.

Nette DI może również wygenerować kod [fabryczny |factory] w oparciu o dostarczony interfejs. Dlatego zamiast klasy `ArticleFactory` musimy stworzyć w aplikacji jedynie interfejs:

```php
interface ArticleFactory
{
	function create(): Article;
}
```

Pełny przykład można znaleźć [na GitHubie |https://github.com/nette-examples/di-example-doc].


Użytkowanie samodzielne .[#toc-standalone-use]
----------------------------------------------

Wdrożenie biblioteki Nette DI do aplikacji jest bardzo proste. Najpierw instalujemy go za pomocą Composera (bo ściąganie plików zip jest takie przestarzałe):

```shell
composer require nette/di
```

Poniższy kod tworzy instancję kontenera DI zgodnie z konfiguracją zapisaną w pliku `config.neon`:

```php
$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp');
$class = $loader->load(function ($compiler) {
	$compiler->loadConfig(__DIR__ . '/config.neon');
});
$container = new $class;
```

Kontener jest generowany tylko raz, jego kod jest zapisywany do cache (katalog `__DIR__ . '/temp'`) i przy kolejnych żądaniach jest tylko stamtąd odczytywany.

Do tworzenia i pobierania serwisów służą metody `getService()` lub `getByType()` W ten sposób tworzymy obiekt `UserController`:

```php
$database = $container->getByType(UserController::class);
$database->query('...');
```

Podczas rozwoju warto włączyć tryb autoodświeżania, w którym kontener jest automatycznie regenerowany w przypadku zmiany jakiejkolwiek klasy lub pliku konfiguracyjnego. Wystarczy podać `true` jako drugi argument w konstruktorze `ContainerLoader`.

```php
$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true);
```


Zastosowanie z ramą Nette .[#toc-using-it-with-the-nette-framework]
-------------------------------------------------------------------

Jak pokazaliśmy, wykorzystanie Nette DI nie ogranicza się do aplikacji napisanych w Nette Framework, można je wdrożyć wszędzie, mając do dyspozycji zaledwie 3 linie kodu.
Jeśli jednak tworzysz aplikacje w Nette Framework, [Bootstrap |application:bootstrap#di-container-configuration] jest odpowiedzialny za konfigurację i tworzenie kontenera.

Pojemnik Nette DI

Nette DI to jedna z najciekawszych bibliotek Nette. Może generować i automatycznie aktualizować skompilowane kontenery DI, które są niezwykle szybkie i niesamowicie łatwe do skonfigurowania.

Forma usług, które mają być tworzone przez kontener DI, jest zwykle definiowana za pomocą plików konfiguracyjnych w formacie NEON. Kontener, który ręcznie stworzyliśmy w poprzednim rozdziale, zostałby zapisany w następujący sposób:

parameters:
	db:
		dsn: 'mysql:'
		user: root
		password: '***'

services:
	- Nette\Database\Connection(%db.dsn%, %db.user%, %db.password%)
	- ArticleFactory
	- UserController

Zapis jest naprawdę krótki.

Wszystkie zależności zadeklarowane w konstruktorach klas ArticleFactory i UserController są wykrywane i przekazywane przez samo Nette DI dzięki tzw. autowiringowi, więc nie trzeba niczego określać w pliku konfiguracyjnym. Więc nawet jeśli parametry się zmienią, nie musisz zmieniać niczego w konfiguracji. Nette automatycznie zregeneruje kontener. Tam możesz skupić się wyłącznie na tworzeniu aplikacji.

Jeśli chcemy przekazać zależności za pomocą setterów, używamy do tego sekcji setup.

Nette DI wygeneruje bezpośrednio kod PHP dla kontenera. Wynikiem jest więc plik .php, który możesz otworzyć i przestudiować. Dzięki temu możesz zobaczyć dokładnie jak działa kontener. Możesz także debugować go w IDE i przechodzić przez niego krok po kroku. I co najważniejsze: wygenerowany PHP jest niezwykle szybki.

Nette DI może również wygenerować kod fabryczny w oparciu o dostarczony interfejs. Dlatego zamiast klasy ArticleFactory musimy stworzyć w aplikacji jedynie interfejs:

interface ArticleFactory
{
	function create(): Article;
}

Pełny przykład można znaleźć na GitHubie.

Użytkowanie samodzielne

Wdrożenie biblioteki Nette DI do aplikacji jest bardzo proste. Najpierw instalujemy go za pomocą Composera (bo ściąganie plików zip jest takie przestarzałe):

composer require nette/di

Poniższy kod tworzy instancję kontenera DI zgodnie z konfiguracją zapisaną w pliku config.neon:

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp');
$class = $loader->load(function ($compiler) {
	$compiler->loadConfig(__DIR__ . '/config.neon');
});
$container = new $class;

Kontener jest generowany tylko raz, jego kod jest zapisywany do cache (katalog __DIR__ . '/temp') i przy kolejnych żądaniach jest tylko stamtąd odczytywany.

Do tworzenia i pobierania serwisów służą metody getService() lub getByType() W ten sposób tworzymy obiekt UserController:

$database = $container->getByType(UserController::class);
$database->query('...');

Podczas rozwoju warto włączyć tryb autoodświeżania, w którym kontener jest automatycznie regenerowany w przypadku zmiany jakiejkolwiek klasy lub pliku konfiguracyjnego. Wystarczy podać true jako drugi argument w konstruktorze ContainerLoader.

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true);

Zastosowanie z ramą Nette

Jak pokazaliśmy, wykorzystanie Nette DI nie ogranicza się do aplikacji napisanych w Nette Framework, można je wdrożyć wszędzie, mając do dyspozycji zaledwie 3 linie kodu. Jeśli jednak tworzysz aplikacje w Nette Framework, Bootstrap jest odpowiedzialny za konfigurację i tworzenie kontenera.