Üretilen Fabrikalar

Nette DI, arayüze dayalı olarak otomatik olarak fabrika kodu oluşturabilir, bu da sizi kod yazmaktan kurtarır.

Fabrika, nesneleri oluşturan ve yapılandıran bir sınıftır. Bu nedenle bağımlılıklarını da onlara aktarır. Lütfen fabrikaları kullanmanın belirli bir yolunu tanımlayan ve bu konuyla ilgili olmayan factory method tasarım kalıbı ile karıştırmayın.

Giriş bölümünde böyle bir fabrikanın neye benzediğini göstermiştik:

class ArticleFactory
{
	public function __construct(
		private Nette\Database\Connection $db,
	) {
	}

	public function create(): Article
	{
		return new Article($this->db);
	}
}

Nette DI otomatik olarak fabrika kodu üretebilir. Tek yapmanız gereken bir arayüz oluşturmaktır ve Nette DI bir uygulama üretecektir. Arayüz, create adında tam olarak bir yönteme sahip olmalı ve bir dönüş türü bildirmelidir:

interface ArticleFactory
{
	function create(): Article;
}

Dolayısıyla ArticleFactory fabrikasının Article nesnelerini oluşturan bir create yöntemi vardır. Örneğin Article sınıfı aşağıdaki gibi görünebilir:

class Article
{
	public function __construct(
		private Nette\Database\Connection $db,
	) {
	}
}

Fabrikayı yapılandırma dosyasına ekleyin:

services:
	- ArticleFactory

Nette DI ilgili fabrika uygulamasını oluşturacaktır.

Böylece, fabrikayı kullanan kodda, nesneyi arayüze göre talep ederiz ve Nette DI üretilen uygulamayı kullanır:

class UserController
{
	public function __construct(
		private ArticleFactory $articleFactory,
	) {
	}

	public function foo()
	{
		// fabrikanın bir nesne oluşturmasına izin verin
		$article = $this->articleFactory->create();
	}
}

Parametrelendirilmiş Fabrika

create fabrika yöntemi, daha sonra kurucuya aktaracağı parametreleri kabul edebilir. Örneğin, Article sınıfına bir makale yazarı kimliği ekleyelim:

class Article
{
	public function __construct(
		private Nette\Database\Connection $db,
		private int $authorId,
	) {
	}
}

Ayrıca fabrikaya parametre de ekleyeceğiz:

interface ArticleFactory
{
	function create(int $authorId): Article;
}

Yapıcıdaki parametre ve fabrikadaki parametre aynı ada sahip olduğundan, Nette DI bunları otomatik olarak geçirecektir.

Gelişmiş Tanım

Tanım, implement tuşu kullanılarak çok satırlı olarak da yazılabilir:

services:
	articleFactory:
		implement: ArticleFactory

Bu uzun şekilde yazarken, normal hizmetlerde olduğu gibi arguments anahtarındaki kurucu için ek argümanlar ve setup kullanarak ek yapılandırma sağlamak mümkündür.

Örnek: create() yöntemi $authorId parametresini kabul etmeseydi, yapılandırmada Article yapıcısına aktarılacak sabit bir değer belirtebilirdik:

services:
	articleFactory:
		implement: ArticleFactory
		arguments:
			authorId: 123

Ya da tersine, eğer create() parametre kabul etseydi $authorId ancak bu parametre kurucunun bir parçası olmasaydı ve Article::setAuthorId() yöntemi tarafından aktarılsaydı, bu parametreye setup bölümünde atıfta bulunacaktık:

services:
	articleFactory:
		implement: ArticleFactory
		setup:
			- setAuthorId($authorId)

Accessor

Nette, fabrikaların yanı sıra erişimci adı verilen nesneler de üretebilir. Erişimci, DI konteynerinden belirli bir hizmeti döndüren get() yöntemine sahip bir nesnedir. Birden fazla get() çağrısı her zaman aynı örneği döndürecektir.

Accessor'lar bağımlılıklara tembel yükleme getirir. Hataları özel bir veritabanına kaydeden bir sınıfımız olsun. Eğer veritabanı bağlantısı sınıfın kurucusunda bir bağımlılık olarak aktarılsaydı, bağlantının her zaman oluşturulması gerekirdi, ancak sadece nadiren bir hata ortaya çıktığında kullanılacağından bağlantı çoğunlukla kullanılmadan kalırdı. Bunun yerine, sınıf bir erişimci geçebilir ve get() yöntemi çağrıldığında, yalnızca o zaman veritabanı nesnesi oluşturulur:

Bir accessor nasıl oluşturulur? Sadece bir arayüz yazın ve Nette DI uygulamayı oluşturacaktır. Arayüz, get adında tam olarak bir yönteme sahip olmalı ve dönüş türünü bildirmelidir:

interface PDOAccessor
{
	function get(): PDO;
}

Erişiciyi, erişicinin döndüreceği hizmetin tanımıyla birlikte yapılandırma dosyasına ekleyin:

services:
	- PDOAccessor
	- PDO(%dsn%, %user%, %password%)

Erişimci, PDO türünde bir hizmet döndürür ve yapılandırmada bu türden yalnızca bir hizmet olduğu için erişimci bunu döndürür. Bu türde birden fazla yapılandırılmış hizmet varsa, adını kullanarak hangisinin döndürüleceğini belirtebilirsiniz, örneğin - PDOAccessor(@db1).

Multifactory/Accessor

Şimdiye kadar, fabrikalar ve erişimciler yalnızca tek bir nesne oluşturabiliyor veya döndürebiliyordu. Bir erişimci ile birleştirilmiş bir çoklu fabrika da oluşturulabilir. Böyle bir çoklu fabrika sınıfının arayüzü, aşağıdaki gibi adlandırılan birden fazla yöntemden oluşabilir create<name>() ve get<name>()Örneğin:

interface MultiFactory
{
	function createArticle(): Article;
	function getDb(): PDO;
}

Birden fazla oluşturulmuş fabrika ve erişimci geçirmek yerine, yalnızca bir karmaşık çoklu fabrika geçirebilirsiniz.

Alternatif olarak, birden fazla yöntem yerine bir parametre ile get() adresini kullanabilirsiniz:

interface MultiFactoryAlt
{
	function get($name): PDO;
}

Bu durumda, MultiFactory::getArticle(), MultiFactoryAlt::get('article') ile aynı şeyi yapar. Ancak, alternatif sözdiziminin birkaç dezavantajı vardır. Hangi $name değerlerinin desteklendiği açık değildir ve birden fazla farklı $name değeri kullanıldığında dönüş türü arayüzde belirtilemez.

Liste ile Tanımlama

Bu yol, yapılandırmada birden fazla fabrika tanımlamak için kullanılabilir:

services:
	- MultiFactory(
		article: Article                      # defines createArticle()
		db: PDO(%dsn%, %user%, %password%)    # defines getDb()
	)

Veya fabrika tanımında, bir referans kullanarak mevcut hizmetlere atıfta bulunabiliriz:

services:
	article: Article
	- PDO(%dsn%, %user%, %password%)
	- MultiFactory(
		article: @article    # defines createArticle()
		db: @\PDO            # defines getDb()
	)

Etiketlerle Tanım

Bir multifactory'nin nasıl tanımlanacağına dair bir başka seçenek de etiket kullanmaktır:

services:
	- App\Core\RouterFactory::createRouter
	- App\Model\DatabaseAccessor(
		db1: @database.db1.explorer
	)
versiyon: 3.x