Nette DI Container

Nette DI je jednou z nejzajímavějších knihoven Nette. Umí generovat a automaticky aktualizovat kompilované DI kontejnery, které jsou extrémně rychlé a úžasně snadno konfigurovatelné.

Podobu služeb, které má vytvářet DI kontejner, definujeme obvykle pomocí konfiguračních souborů ve formátu NEON. Kontejner, který jsme ručně vytvořili v předchozí kapitole, by se zapsal takto:

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

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

Zápis je opravdu stručný.

Všechny závislosti deklarované v konstruktorech tříd ArticleFactory a UserController si Nette DI samo zjistí a předá díky tzv. autowiringu, v konfiguračním souboru proto není potřeba nic uvádět. Takže i když dojde ke změně parametrů, nemusíte v konfiguraci nic měnit. Nette kontejner automaticky přegeneruje. Vy se tam můžete soustředit čistě na vývoj aplikace.

Pokud chceme závislosti předávat pomocí setterů, použijeme k tomu sekci setup.

Nette DI vygeneruje přímo PHP kód kontejneru. Výsledkem je tedy soubor .php, který si můžete otevřít a studovat. Díky tomu přesně vidíte, jak kontejner funguje. Můžete jej také debuggovat v IDE a krokovat. A hlavně: vygenerované PHP je extrémně rychlé.

Nette DI umí také generovat kód továren na základě dodaného rozhraní. Proto místo třídy ArticleFactory nám bude stačit vytvořit v aplikaci jen interface:

interface ArticleFactory
{
	function create(): Article;
}

Celý příklad najdete na GitHubu.

Samostatné použití

Nasazení knihovny Nette DI do aplikace je velmi snadné. Nejprve ji nainstalujeme Composerem (protože stahování zipů je tááák zastaralé):

composer require nette/di

Následující kód vytvoří instanci DI kontejneru podle konfigurace uložené v souboru config.neon:

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

Kontejner se vygeneruje jen jednou, jeho kód se zapíše do cache (adresář __DIR__ . '/temp') a při dalších požadavcích se už jen odsud načítá.

Pro vytvoření a získání služeb slouží metody getService() nebo getByType(). Takto vytvoříme objekt UserController:

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

Během vývoje je užitečné aktivovat auto-refresh mód, kdy se kontejner automaticky přegeneruje, pokud dojde ke změně jakékoliv třídy nebo konfiguračního souboru. Stačí v konstruktoru ContainerLoader uvést jako druhý argument true.

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

Použití s frameworkem Nette

Jak jsme si ukázali, použití Nette DI není limitované na aplikace psané v Nette Frameworku, můžete jej pomocí pouhých 3 řádků kódu nasadit kdekoliv. Pokud však vyvíjíte aplikace v Nette Framework, konfiguraci a vytvoření kontejneru má na starosti Bootstrap.