Metody i atrybuty wstrzykiwania

Na konkretnych przykładach przyjrzymy się możliwościom przekazywania zależności do prezenterów oraz wyjaśnimy metody inject i atrybuty/anotacje.

Metody inject*()

W prezenterze, jak w każdym innym kodzie, preferowanym sposobem przekazywania zależności jest użycie konstruktora. Jeśli jednak prezenter dziedziczy po wspólnym przodku (np. BasePresenter), lepiej jest użyć metod inject*() w tym przodku. Jest to specjalny przypadek settera, w którym metoda zaczyna się od przedrostka inject. Dzieje się tak dlatego, że zachowujemy konstruktor wolny dla potomków:

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
	private Foo $foo;

	public function injectBase(Foo $foo): void
	{
		$this->foo = $foo;
	}
}

class MyPresenter extends BasePresenter
{
	private Bar $bar;

	public function __construct(Bar $bar)
	{
		$this->bar = $bar;
	}
}

Podstawowa różnica w stosunku do settera polega na tym, że Nette DI automatycznie wywołuje metody nazwane w ten sposób w prezenterach zaraz po utworzeniu instancji i przekazuje im wszystkie wymagane zależności. Prezenter inject*() może zawierać wiele metod, a każda metoda może mieć dowolną liczbę parametrów.

Jeśli mielibyśmy przekazać zależności do przodków poprzez ich konstruktory, musielibyśmy pobrać ich zależności we wszystkich potomkach i przekazać je do parent::__construct(), co komplikuje kod:

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
	private Foo $foo;

	public function __construct(Foo $foo)
	{
		$this->foo = $foo;
	}
}

class MyPresenter extends BasePresenter
{
	private Bar $bar;

	public function __construct(Foo $foo, Bar $bar)
	{
		parent::__construct($foo); // to jest komplikacja
		$this->bar = $bar;
	}
}

Metody inject*() są również przydatne w przypadkach, gdy prezenter składa się z cech i każda z nich wymaga własnej zależności.

Możliwe jest również użycie adnotacji @inject, ale należy pamiętać, że enkapsulacja łamie się.

Annotacja inject

Jest to automatyczne przekazanie zależności do publicznej zmiennej członkowskiej prezentera, która jest opatrzona adnotacją @inject w komentarzu dokumentacji. Typ może być również określony w komentarzu do dokumentacji, jeśli używasz PHP niższego niż 7.4.

class MyPresenter extends Nette\Application\UI\Presenter
{
	/** @inject */
	public Cache $cache;
}

Od PHP 8.0 właściwość może być oznaczona atrybutem Inject:

use Nette\DI\Attributes\Inject;

class MyPresenter extends Nette\Application\UI\Presenter
{
	#[Inject]
	public Cache $cache;
}

Nette DI ponownie automatycznie przekaże zależności do takich adnotowanych zmiennych w prezenterze, gdy tylko instancja zostanie utworzona.

Ta metoda ma te same wady, co przekazywanie zależności do zmiennej publicznej. Jest on używany w prezenterze, ponieważ nie komplikuje kodu i wymaga tylko minimalnego wpisywania.