Metodi e attributi inject

In questo articolo ci concentreremo sui diversi modi di passare le dipendenze ai presenter nel framework Nette. Confronteremo il metodo preferito, che è il costruttore, con altre opzioni come i metodi e gli attributi inject.

Anche per i presenter vale che il passaggio delle dipendenze tramite il costruttore è il percorso preferito. Tuttavia, se si crea un antenato comune da cui ereditano altri presenter (ad es. BasePresenter), e questo antenato ha anch'esso delle dipendenze, si verifica un problema che chiamiamo constructor hell. Questo può essere aggirato utilizzando percorsi alternativi, che sono rappresentati dai metodi e dagli attributi (annotazioni) inject.

Metodi inject*()

È una forma di passaggio della dipendenza tramite setter. Il nome di questi setter inizia con il prefisso inject. Nette DI chiama automaticamente i metodi così denominati subito dopo la creazione dell'istanza del presenter e passa loro tutte le dipendenze richieste. Devono quindi essere dichiarati come public.

I metodi inject*() possono essere considerati come una sorta di estensione del costruttore in più metodi. Grazie a ciò, BasePresenter può ricevere le dipendenze tramite un altro metodo e lasciare il costruttore libero per i suoi discendenti:

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;
	}
}

Un presenter può contenere un numero qualsiasi di metodi inject*() e ognuno può avere un numero qualsiasi di parametri. Sono ottimi anche nei casi in cui il presenter è composto da trait e ognuno di essi richiede la propria dipendenza.

Attributi Inject

È una forma di iniezione nella proprietà. È sufficiente contrassegnare in quali variabili iniettare e Nette DI passerà automaticamente le dipendenze subito dopo la creazione dell'istanza del presenter. Per poterle inserire, è necessario dichiararle come public.

Contrassegniamo le proprietà con un attributo: (in precedenza si usava l'annotazione /** @inject */)

use Nette\DI\Attributes\Inject;  // questa riga è importante

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

Il vantaggio di questo modo di passare le dipendenze era la forma di scrittura molto concisa. Tuttavia, con l'avvento della constructor property promotion, sembra più facile utilizzare il costruttore.

Al contrario, questo metodo soffre degli stessi svantaggi del passaggio delle dipendenze alle proprietà in generale: non abbiamo controllo sulle modifiche nella variabile e allo stesso tempo la variabile diventa parte dell'interfaccia pubblica della classe, il che è indesiderabile.