Nette DI Container

Nette DI, Nette'nin en ilginç kütüphanelerinden biridir. Son derece hızlı ve şaşırtıcı derecede kolay yapılandırılan, derlenmiş DI container'ları üretebilir ve otomatik olarak güncelleyebilir.

DI container'ın oluşturması gereken servislerin biçimi genellikle NEON biçimindeki yapılandırma dosyalarıyla tanımlanır. Önceki bölümde elle oluşturduğumuz container şöyle yazılırdı:

parameters:
	db:
		dsn: 'mysql:'
		user: root
		password: '***'

services:
	- Nette\Database\Connection(%db.dsn%, %db.user%, %db.password%)
	- ArticleFactory
	- EditController

Söz dizimi çok derli topludur.

ArticleFactory ve EditController sınıflarının yapıcılarında bildirilen tüm bağımlılıklar, autowiring sayesinde Nette DI tarafından bulunur ve otomatik olarak aktarılır; dolayısıyla yapılandırma dosyasında bir şey belirtmeye gerek yoktur. Böylece parametreler değişse bile yapılandırmada bir şey değiştirmeniz gerekmez. Geliştirme sırasında Nette container'ı otomatik olarak yeniden üretir. Yalnızca uygulama geliştirmeye odaklanabilirsiniz.

Bağımlılıkları setter'larla aktarmak istersek, bunun için setup bölümünü kullanırız.

Nette DI, container için doğrudan PHP kodu üretir. Sonuç, açıp inceleyebileceğiniz bir .php dosyasıdır. Böylece container'ın tam olarak nasıl çalıştığını görebilirsiniz. Onu IDE'nizde hata ayıklayabilir ve adım adım izleyebilirsiniz. Ve en önemlisi: üretilen PHP kodu son derece hızlıdır.

Nette DI, verilen bir arayüze dayanarak factory kodu da üretebilir. Bu yüzden ArticleFactory sınıfı yerine uygulamada yalnızca bir arayüz oluşturmamız yeterlidir:

interface ArticleFactory
{
	function create(): Article;
}

Tam örneği GitHub'da bulabilirsiniz.

Bağımsız Kullanım

Nette DI kütüphanesini bir uygulamaya katmak çok kolaydır. Önce onu Composer ile kuruyoruz (çünkü zip dosyası indirmek çok demode):

composer require nette/di

Aşağıdaki kod, config.neon dosyasında saklanan yapılandırmaya göre bir DI container örneği oluşturmak için Compiler kullanır:

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp');
$class = $loader->load(function ($compiler) {
	$compiler->loadConfig(__DIR__ . '/config.neon');
});
$container = new $class;

Container yalnızca bir kez üretilir, kodu önbelleğe (__DIR__ . '/temp' dizinine) yazılır ve sonraki isteklerde yalnızca oradan yüklenir.

Compiler kendi başına yapılandırmada yalnızca services ve parameters bölümlerini etkinleştirir. Diğerlerini (search, decorator, di ya da inject gibi) kullanmak için önce ilgili extension'ları kaydedin. Yapılandırmanın extensions bölümünden extension kaydedebilmek için de ExtensionsExtension ekleyin:

$compiler->addExtension('search', new Nette\DI\Extensions\SearchExtension($tempDir));
$compiler->addExtension('extensions', new Nette\DI\Extensions\ExtensionsExtension);

Tam Nette uygulamalarında kullanılan Configurator bunların hepsini otomatik olarak kaydeder.

Aynı önbellek dizininde birkaç farklı container tutuyorsanız, load() metoduna ikinci argüman olarak verilen bir anahtarla onları ayırt edin; bu anahtar üretilen sınıf adının bir parçası olur:

$class = $loader->load(
	fn($compiler) => $compiler->loadConfig(__DIR__ . '/config.neon'),
	'my-key',
);

Servisleri oluşturmak ve almak için getService() ya da getByType() metotları kullanılır. EditController nesnesini şöyle oluştururuz:

$controller = $container->getByType(EditController::class);
$controller->someMethod();

Geliştirme sırasında, herhangi bir sınıf ya da yapılandırma dosyası değiştiğinde container'ın kendiliğinden yeniden üretildiği otomatik yenileme kipini açmak yararlıdır. ContainerLoader yapıcısında ikinci argüman olarak true vermeniz yeterlidir.

$loader = new Nette\DI\ContainerLoader(__DIR__ . '/temp', true);

Container ile Çalışma

getService() ve getByType() dışında container nesnesi başka kullanışlı metotlar da sunar:

  • getByType(string $type, bool $throw = true): ?object verilen türdeki servisi döndürür. İkinci argüman olarak false verirseniz, böyle bir servis yoksa istisna fırlatmak yerine null döndürür.
  • hasService(string $name): bool ve isCreated(string $name): bool bir servisin tanımlı olup olmadığını ve örneklenip örneklenmediğini söyler.
  • getParameters(): array container'ın tüm parametrelerini, getParameter($key) ise tek bir parametreyi döndürür.
  • createInstance(string $class, array $args = []): object verilen sınıftan yeni bir örnek oluşturur ve yapıcı bağımlılıklarını autowiring ile aktarır.
  • callMethod(callable $function, array $args = []): mixed verilen callable'ı çağırır ve argümanlarını autowiring ile aktarır.
  • callInjects(object $service): void verilen nesnedeki tüm inject*() metotlarını çağırır ve onlara bağımlılıkları aktarır.

Container yapıcısı ayrıca, yapılandırmada tanımlananları tamamlayan bir parametre dizisi de kabul eder:

$container = new $class(['host' => 'localhost']);

Nette Framework ile Kullanım

Gösterdiğimiz gibi, Nette DI kullanımı Nette Framework ile kurulan uygulamalarla sınırlı değildir; onu yalnızca üç satır kodla her yere katabilirsiniz. Ancak Nette Framework kullanarak uygulama geliştiriyorsanız, container'ın yapılandırılmasını ve oluşturulmasını Bootstrap üstlenir.

versiyon: 3.x