Métodos y atributos inject

En este artículo, nos centraremos en las diferentes formas de pasar dependencias a los Presenters en el framework Nette. Compararemos la forma preferida, que es el constructor, con otras opciones como los métodos y atributos inject.

También para los Presenters, pasar dependencias mediante el constructor es la ruta preferida. Sin embargo, si creas un ancestro común del que heredan otros Presenters (p. ej., BasePresenter), y este ancestro también tiene dependencias, surge un problema que llamamos constructor hell. Esto se puede evitar utilizando rutas alternativas, que son los métodos y atributos (anotaciones) inject.

Métodos inject*()

Es una forma de pasar dependencias mediante setter. El nombre de estos setters comienza con el prefijo inject. Nette DI llama automáticamente a los métodos con este nombre justo después de crear la instancia del Presenter y les pasa todas las dependencias requeridas. Por lo tanto, deben declararse como public.

Los métodos inject*() pueden considerarse como una especie de extensión del constructor en múltiples métodos. Gracias a esto, BasePresenter puede recibir dependencias a través de otro método y dejar el constructor libre para sus descendientes:

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 puede contener cualquier número de métodos inject*() y cada uno puede tener cualquier número de parámetros. También son excelentes en casos donde el Presenter está compuesto de traits y cada uno requiere su propia dependencia.

Atributos Inject

Es una forma de inyección en la propiedad. Simplemente marca en qué variables se debe inyectar, y Nette DI pasa automáticamente las dependencias justo después de crear la instancia del Presenter. Para poder insertarlas, es necesario declararlas como public.

Marcamos las propiedades con un atributo: (anteriormente se usaba la anotación /** @inject */)

use Nette\DI\Attributes\Inject;  // esta línea es importante

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

La ventaja de esta forma de pasar dependencias era una sintaxis muy concisa. Sin embargo, con la llegada de constructor property promotion, parece más fácil usar el constructor.

Por el contrario, esta forma sufre las mismas deficiencias que pasar dependencias a propiedades en general: no tenemos control sobre los cambios en la variable y, al mismo tiempo, la variable se convierte en parte de la interfaz pública de la clase, lo cual no es deseable.