Metody i atrybuty inject
W tym artykule skupimy się na różnych sposobach przekazywania zależności do presenterów w frameworku Nette.
Porównamy preferowany sposób, którym jest konstruktor, z innymi możliwościami, takimi jak metody i atrybuty
inject
.
Również dla presenterów obowiązuje zasada, że przekazywanie zależności za pomocą konstruktora
jest preferowaną ścieżką. Jeśli jednak tworzysz wspólnego przodka, z którego dziedziczą inne presentery (np.
BasePresenter
), i ten przodek również ma zależności, pojawia się problem, który nazywamy constructor hell. Można go
obejść za pomocą alternatywnych ścieżek, które stanowią metody i atrybuty (dawniej adnotacje) inject
.
Metody inject*()
Jest to forma przekazywania zależności przez setter. Nazwa tych
setterów zaczyna się prefiksem inject
. Nette DI automatycznie wywołuje tak nazwane metody zaraz po utworzeniu
instancji presentera i przekazuje im wszystkie wymagane zależności. Muszą być zatem zadeklarowane jako public.
Metody inject*()
można uznać za pewnego rodzaju rozszerzenie konstruktora na wiele metod. Dzięki temu
BasePresenter
może przyjąć zależności przez 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;
}
}
Metod inject*()
presenter może zawierać dowolną liczbę, a każda może mieć dowolną liczbę parametrów.
Świetnie sprawdzają się również w przypadkach, gdy presenter jest złożony z traitów, a każdy z nich wymaga własnej
zależności.
Atrybuty Inject
Jest to forma wstrzykiwania do właściwości. Wystarczy oznaczyć, do których zmiennych ma nastąpić wstrzyknięcie, a Nette DI automatycznie przekaże zależności zaraz po utworzeniu instancji presentera. Aby mógł je wstawić, konieczne jest zadeklarowanie ich jako public.
Właściwości oznaczamy 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 Nette\Caching\Cache $cache; // Zmiana typu na Nette\Caching\Cache dla spójności z Cache
}
Zaletą tego sposobu przekazywania zależności była bardzo oszczędna forma zapisu. Jednak wraz z pojawieniem się constructor property promotion wydaje się łatwiejsze użycie konstruktora.
Z drugiej strony, ten sposób cierpi na te same wady, co przekazywanie zależności do właściwości ogólnie: nie mamy kontroli nad zmianami w zmiennej, a jednocześnie zmienna staje się częścią publicznego interfejsu klasy, co jest niepożądane.