Inject Methods and Attributes

Using specific examples, we will look at the possibilities of passing dependencies to presenters and explain the inject methods and attributes/annotations.

inject*() Methods

In presenter, as in any other code, the preferred way of passing dependencies is by using constructor. However, if the presenter inherits from a common ancestor (e.g. BasePresenter), it is better to use the methods of inject*() in that ancestor. It is a special case of a setter, where the method starts with a prefix inject. This is because we keep the constructor free for descendants:

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

The basic difference from a setter is that Nette DI automatically calls methods named this way in presenters as soon as the instance is created, passing all required dependencies to them. A presenter can contain multiple methods inject*() and each method can have any number of parameters.

If we passed dependencies to ancestors through their constructors, we would have to get their dependencies in all descendants and pass them to parent::__construct(), which complicates the code:

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); // this is a complication
		$this->bar = $bar;
	}
}

The inject*() methods are also useful in cases where the presenter is composed of traits and each of them requires its own dependency.

It is also possible to use annotation @inject, but it is important to keep in mind that encapsulation breaks.

Inject Annotations

This is an automatic passing of the dependency to the presenter's public member variable, which is annotated with @inject in the documentation comment. The type can also be specified in the documentation comment if you are using PHP lower than 7.4.

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

Since PHP 8.0, a property can be marked with an attribute Inject:

use Nette\DI\Attributes\Inject;

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

Again, Nette DI will automatically pass dependencies to properties annotated in this way in the presenter as soon as the instance is created.

This method has the same shortcomings as passing dependencies to a public property. It is used in presenter because it does not complicate the code and requires only a minimum of typing.