Metody i atrybuty wstrzykiwania

W tym artykule skupimy się na różnych sposobach przekazywania zależności do prezenterów w frameworku Nette. Porównamy preferowaną metodę, jaką jest konstruktor, z innymi opcjami, takimi jak inject metody i atrybuty.

Również dla prezenterów przekazywanie zależności za pomocą konstruktora jest preferowanym sposobem. Jednakże, jeśli stworzysz wspólnego przodka, z którego dziedziczą inne prezentery (np. BasePresenter), a ten przodek również posiada zależności, pojawia się problem, który nazywamy piekłem konstruktora. Można to obejść, stosując alternatywne metody, które obejmują metody wstrzykiwania i atrybuty (adnotacje).

Metody inject*()

Jest to forma przekazywania zależności za pomocą seterów. Nazwy tych seterów zaczynają się od przedrostka inject. Nette DI automatycznie wywołuje tak nazwane metody zaraz po utworzeniu instancji prezentera i przekazuje do nich wszystkie wymagane zależności. Dlatego muszą być one zadeklarowane jako publiczne.

inject*() metody można uznać za rodzaj rozszerzenia konstruktora na wiele metod. Dzięki temu BasePresenter może przyjmować zależności poprzez inną metodę i pozostawić konstruktor wolny dla swoich 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;
	}
}

Prezenter może zawierać dowolną liczbę metod inject*(), a każda z nich może mieć dowolną liczbę parametrów. Jest to również świetne rozwiązanie dla przypadków, w których prezenter składa się z cech, a każda z nich wymaga własnej zależności.

Inject Atrybuty

Jest to forma wstrzyknięcia do właściwości. Wystarczy wskazać, które właściwości powinny zostać wstrzyknięte, a Nette DI automatycznie przekazuje zależności zaraz po utworzeniu instancji prezentera. Aby je wstawić, konieczne jest zadeklarowanie ich jako publicznych.

Właściwości oznaczane są atrybutem: (wcześniej używano adnotacji /** @inject */)

use Nette\DI\Attributes\Inject; // ta linia jest ważna.

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

Zaletą tej metody przekazywania zależności była bardzo oszczędna forma notacji. Jednak po wprowadzeniu promocji właściwości konstruktora, korzystanie z konstruktora wydaje się łatwiejsze.

Z drugiej strony, metoda ta cierpi na te same wady, co przekazywanie zależności do właściwości w ogóle: nie mamy kontroli nad zmianami w zmiennej, a jednocześnie zmienna staje się częścią publicznego interfejsu klasy, co jest niepożądane.