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): ?objectverilen türdeki servisi döndürür. İkinci argüman olarakfalseverirseniz, böyle bir servis yoksa istisna fırlatmak yerinenulldöndürür.hasService(string $name): boolveisCreated(string $name): boolbir servisin tanımlı olup olmadığını ve örneklenip örneklenmediğini söyler.getParameters(): arraycontainer'ın tüm parametrelerini,getParameter($key)ise tek bir parametreyi döndürür.createInstance(string $class, array $args = []): objectverilen 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 = []): mixedverilen callable'ı çağırır ve argümanlarını autowiring ile aktarır.callInjects(object $service): voidverilen nesnedeki tüminject*()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.