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.