Inject Metotları ve Attribute'ları

Bu yazı, Nette framework'ünde bağımlılıkları presenter'lara aktarmanın çeşitli yollarını ele alıyor. Tercih edilen yöntem olan constructor injection'ı, inject metotları ve attribute'ları gibi alternatiflerle karşılaştıracağız.

Presenter'larda da, diğer sınıflarda olduğu gibi, bağımlılıkları yapıcı üzerinden aktarmak tercih edilen yaklaşımdır. Ancak diğer presenter'ların türediği ortak bir ata sınıf (örneğin BasePresenter) oluşturursanız ve bu atanın da bağımlılıkları varsa, constructor hell adıyla bilinen bir sorun ortaya çıkabilir. Bu, alternatif yöntemlerle, yani inject metotları ve attribute'larıyla (eskiden açıklamalarla) aşılabilir.

inject*() Metotları

Bu, bağımlılıkları setter'lar üzerinden aktarmanın bir biçimidir. Bu setter'ların adları inject önekiyle başlamalıdır. Nette DI, bu şekilde adlandırılmış metotları presenter örneği oluşturulur oluşturulmaz otomatik olarak çağırır ve gereken tüm bağımlılıkları aktarır. Bu yüzden public olarak bildirilmeleri gerekir.

inject*() metotları, yapıcının birden çok metoda bölünmüş uzantıları gibi görülebilir. Bu, BasePresenter'ın bağımlılıklarını ayrı bir metotla almasını sağlar ve yapıcıyı torunlarına bırakır:

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

Bir presenter istediği kadar inject*() metoduna sahip olabilir ve her biri istediği kadar parametre alabilir. Bu yaklaşım, presenter'ın trait'lerden kurulduğu ve her trait'in kendi bağımlılıklarını gerektirdiği durumlara da çok uygundur.

Inject Attribute'ları

Bu, özelliklere enjekte etmenin bir biçimidir. Enjekte edilmesi gereken özellikleri işaretlemeniz yeterlidir; Nette DI, presenter örneği oluşturulur oluşturulmaz bağımlılıkları otomatik olarak aktarır. Enjeksiyonun mümkün olması için bu özelliklerin public olarak bildirilmesi gerekir.

Özellikler bir attribute ile işaretlenir: (eskiden /** @inject */ açıklaması kullanılıyordu)

use Nette\DI\Attributes\Inject;  // bu satır önemli

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

Bu bağımlılık aktarma yönteminin üstünlüğü, çok derli toplu söz dizimiydi. Ancak constructor property promotion geldikten sonra yapıcıyı kullanmak çoğu zaman daha basit görünüyor.

Buna karşılık bu yöntem, genel olarak property injection'ın taşıdığı sakıncaların aynısını taşır: değişkenin değişimi üzerinde denetimimiz olmaz ve değişken, sınıfın public arayüzünün bir parçası hâline gelir; bu da genellikle istenmeyen bir durumdur.