Nette Documentation Preview

syntax
Otomatik Kablolama
******************

.[perex]
Autowiring, servisleri yapıcıya ve diğer yöntemlere otomatik olarak geçirebilen harika bir özelliktir, böylece bunları yazmamıza gerek kalmaz. Size çok zaman kazandırır.

Bu, hizmet tanımlarını yazarken argümanların büyük çoğunluğunu atlamamızı sağlar. Bunun yerine:

```neon
services:
	articles: Model\ArticleRepository(@database, @cache.storage)
```

Sadece yaz:

```neon
services:
	articles: Model\ArticleRepository
```

Otomatik kablolama tipler tarafından yönlendirilir, bu nedenle `ArticleRepository` sınıfı aşağıdaki gibi tanımlanmalıdır:

```php
namespace Model;

class ArticleRepository
{
	public function __construct(\PDO $db, \Nette\Caching\Storage $storage)
	{}
}
```

Autowiring'i kullanmak için, konteynerdeki her tür için **sadece bir servis** olmalıdır. Daha fazlası olsaydı, autowiring hangisini geçireceğini bilemez ve bir istisna atardı:

```neon
services:
	mainDb: PDO(%dsn%, %user%, %password%)
	tempDb: PDO('sqlite::memory:')
	articles: Model\ArticleRepository # İSTİSNA OLUŞTURUR, hem mainDb hem de tempDb eşleşir
```

Çözüm, otomatik kablolamayı atlamak ve hizmet adını açıkça belirtmek olabilir (örn. `articles: Model\ArticleRepository(@mainDb)`). Ancak, bir hizmetin veya [tercih |#Preferred Autowiring] edilen ilk hizmetin otomatik kablolamasını [devre dışı |#Disabled autowiring] bırakmak daha uygundur.


Devre Dışı Otomatik Kablolama .[#toc-disabled-autowiring]
---------------------------------------------------------

`autowired: no` seçeneğini kullanarak servis otomatik kablolamayı devre dışı bırakabilirsiniz:

```neon
services:
	mainDb: PDO(%dsn%, %user%, %password%)

	tempDb:
		create: PDO('sqlite::memory:')
		autowired: false # tempDb'yi otomatik bağlantıdan kaldırır

	articles: Model\ArticleRepository # bu nedenle mainDb'yi kurucuya geçirir
```

`articles` hizmeti, kurucuya aktarılabilecek `PDO` türünde iki eşleşen hizmet (yani `mainDb` ve `tempDb`) olduğu istisnasını atmaz, çünkü yalnızca `mainDb` hizmetini görür.

.[note]
Nette'de otomatik kablolamanın yapılandırılması, `autowire: false` seçeneğinin hizmet kurucu argümanları için otomatik kablolamanın kullanılmaması gerektiğini söylediği Symfony'den farklı çalışır.
Nette'de, ister kurucunun argümanları ister başka herhangi bir yöntem için olsun, otomatik bağlantı her zaman kullanılır. `autowired: false` seçeneği, servis örneğinin autowiring kullanılarak hiçbir yere aktarılmaması gerektiğini söyler.


Tercih Edilen Otomatik Kablolama .[#toc-preferred-autowiring]
-------------------------------------------------------------

Aynı türde daha fazla hizmetimiz varsa ve bunlardan biri `autowired` seçeneğine sahipse, bu hizmet tercih edilen hizmet olur:

```neon
services:
	mainDb:
		create: PDO(%dsn%, %user%, %password%)
		autowired: PDO # tercih edilmesini sağlar

	tempDb:
		create: PDO('sqlite::memory:')

	articles: Model\ArticleRepository
```

`articles` hizmeti, eşleşen iki `PDO` hizmeti (yani `mainDb` ve `tempDb`) olduğu için istisna oluşturmaz, ancak tercih edilen hizmeti, yani `mainDb` kullanır.


Hizmetlerin Toplanması .[#toc-collection-of-services]
-----------------------------------------------------

Otomatik kablolama ayrıca belirli bir türdeki hizmetlerin bir dizisini de geçirebilir. PHP dizi öğelerinin türünü yerel olarak belirtemediğinden, `array` türüne ek olarak, `ClassName[]` gibi öğe türünü içeren bir phpDoc yorumu eklenmelidir:

```php
namespace Model;

class ShipManager
{
	/**
	 * @param Shipper[] $shippers
	 */
	public function __construct(array $shippers)
	{}
}
```

DI kapsayıcısı daha sonra verilen türle eşleşen bir dizi hizmeti otomatik olarak geçirir. Otomatik kablolamanın kapalı olduğu hizmetleri atlar.

Yorumdaki tür şu biçimde de olabilir `array<int, Class>` veya `list<Class>`. Eğer phpDoc yorumunun biçimini kontrol edemiyorsanız, yapılandırmada doğrudan bir dizi hizmet iletebilirsiniz [`typed()` |services#Special Functions].


Skaler Argümanlar .[#toc-scalar-arguments]
------------------------------------------

Autowiring yalnızca nesneleri ve nesne dizilerini aktarabilir. Skaler argümanlar (örn. dizeler, sayılar, booleanlar) [yapılandırmada yazılır |services#Arguments].
Bir alternatif, skaler bir değeri (veya birden fazla değeri) [nesne |best-practices:passing-settings-to-presenters] olarak kapsülleyen bir [settings-object |best-practices:passing-settings-to-presenters] oluşturmaktır; bu [nesne |best-practices:passing-settings-to-presenters] daha sonra autowiring kullanılarak tekrar aktarılabilir.

```php
class MySettings
{
	public function __construct(
		// readonly PHP 8.1'den beri kullanılabilir
		public readonly bool $value,
	)
	{}
}
```

Yapılandırmaya ekleyerek bir hizmet oluşturursunuz:

```neon
services:
	- MySettings('any value')
```

Daha sonra tüm sınıflar otomatik kablolama yoluyla bunu talep edecektir.


Otomatik Kablolamanın Daraltılması .[#toc-narrowing-of-autowiring]
------------------------------------------------------------------

Bireysel hizmetler için, otomatik kablolama belirli sınıflara veya arayüzlere daraltılabilir.

Normalde, otomatik kablolama hizmeti, hizmetin türüne karşılık gelen her bir yöntem parametresine geçirir. Daraltma, yöntem parametreleri için belirtilen türlerin, hizmetin onlara aktarılması için karşılaması gereken koşulları belirttiğimiz anlamına gelir.

Bir örnek verelim:

```php
class ParentClass
{}

class ChildClass extends ParentClass
{}

class ParentDependent
{
	function __construct(ParentClass $obj)
	{}
}

class ChildDependent
{
	function __construct(ChildClass $obj)
	{}
}
```

Hepsini hizmet olarak kaydetseydik, otomatik kablolama başarısız olurdu:

```neon
services:
	parent: ParentClass
	child: ChildClass
	parentDep: ParentDependent  # İSTİSNAYI KALDIRIR, hem ebeveyn hem de çocuk eşleşir
	childDep: ChildDependent    # 'child' hizmetini yapıcıya geçirir
```

`parentDep` hizmeti `Multiple services of type ParentClass found: parent, child` istisnasını atar çünkü hem `parent` hem de `child` kurucusuna sığar ve otomatik kablolama hangisini seçeceğine karar veremez.

Bu nedenle `child` hizmeti için otomatik kablolamayı `ChildClass` olarak daraltabiliriz:

```neon
services:
	parent: ParentClass
	child:
		create: ChildClass
		autowired: ChildClass  # alternatif: 'autowired: self'

	parentDep: ParentDependent # THROWS EXCEPTION, 'child' autowired olamaz
	childDep: ChildDependent   # 'child' hizmetini yapıcıya geçirir
```

`parentDep` hizmeti artık tek eşleşen nesne olduğu için `parentDep` hizmet kurucusuna aktarılır. `child` hizmeti artık otomatik bağlantı ile aktarılmamaktadır. Evet, `child` hizmeti hala `ParentClass` türündedir, ancak parametre türü için verilen daraltma koşulu artık geçerli değildir, yani `ParentClass` 'nin `ChildClass`'un *bir süper türü* olduğu artık doğru değildir.

`child` durumunda, `self` mevcut hizmet türü anlamına geldiğinden `autowired: ChildClass`, `autowired: self` olarak yazılabilir.

`autowired` anahtarı, dizi olarak birkaç sınıf ve arayüz içerebilir:

```neon
autowired: [BarClass, FooInterface]
```

Örneğe arayüzler eklemeye çalışalım:

```php
interface FooInterface
{}

interface BarInterface
{}

class ParentClass implements FooInterface
{}

class ChildClass extends ParentClass implements BarInterface
{}

class FooDependent
{
	function __construct(FooInterface $obj)
	{}
}

class BarDependent
{
	function __construct(BarInterface $obj)
	{}
}

class ParentDependent
{
	function __construct(ParentClass $obj)
	{}
}

class ChildDependent
{
	function __construct(ChildClass $obj)
	{}
}
```

`child` hizmetini sınırlandırmadığımızda, tüm `FooDependent`, `BarDependent`, `ParentDependent` ve `ChildDependent` sınıflarının kurucularına sığacak ve otomatik kablolama onu oraya geçirecektir.

Ancak, `autowired: ChildClass` (veya `self`) kullanarak `ChildClass` 'a otomatik bağlanmasını daraltırsak, otomatik bağlama sadece `ChildDependent` kurucusuna iletir, çünkü `ChildClass` türünde bir argüman gerektirir ve `ChildClass` * `ChildClass` türündedir. Diğer parametreler için belirtilen başka hiçbir tür `ChildClass`'un bir üst kümesi değildir, bu nedenle hizmet aktarılmaz.

Eğer `autowired: ParentClass` kullanarak bunu `ParentClass` ile sınırlarsak, otomatik kablolama bunu tekrar `ChildDependent` kurucusuna (gerekli tip `ChildClass`, `ParentClass`'un bir üst kümesi olduğundan) ve `ParentDependent` kurucusuna da iletecektir, çünkü `ParentClass` 'un gerekli tipi de eşleşmektedir.

Eğer `FooInterface` ile kısıtlarsak, `ParentDependent` (gerekli tip `ParentClass`, `FooInterface`'un bir üst tipidir) ve `ChildDependent`'a otomatik olarak bağlanmaya devam eder, ancak ek olarak `FooDependent` kurucusuna bağlanır, ancak `BarInterface`, `FooInterface`'un bir üst tipi olmadığı için `BarDependent`'a bağlanmaz.

```neon
services:
	child:
		create: ChildClass
		autowired: FooInterface

	fooDep: FooDependent        # servis çocuğunu yapıcıya geçirir
	barDep: BarDependent        # İSTİSNA OLUŞTURUR, hiçbir hizmet geçemez
	parentDep: ParentDependent  # hizmet çocuğunu yapıcıya geçirir
	childDep: ChildDependent    # hizmet çocuğunu yapıcıya geçirir
```

Otomatik Kablolama

Autowiring, servisleri yapıcıya ve diğer yöntemlere otomatik olarak geçirebilen harika bir özelliktir, böylece bunları yazmamıza gerek kalmaz. Size çok zaman kazandırır.

Bu, hizmet tanımlarını yazarken argümanların büyük çoğunluğunu atlamamızı sağlar. Bunun yerine:

services:
	articles: Model\ArticleRepository(@database, @cache.storage)

Sadece yaz:

services:
	articles: Model\ArticleRepository

Otomatik kablolama tipler tarafından yönlendirilir, bu nedenle ArticleRepository sınıfı aşağıdaki gibi tanımlanmalıdır:

namespace Model;

class ArticleRepository
{
	public function __construct(\PDO $db, \Nette\Caching\Storage $storage)
	{}
}

Autowiring'i kullanmak için, konteynerdeki her tür için sadece bir servis olmalıdır. Daha fazlası olsaydı, autowiring hangisini geçireceğini bilemez ve bir istisna atardı:

services:
	mainDb: PDO(%dsn%, %user%, %password%)
	tempDb: PDO('sqlite::memory:')
	articles: Model\ArticleRepository # İSTİSNA OLUŞTURUR, hem mainDb hem de tempDb eşleşir

Çözüm, otomatik kablolamayı atlamak ve hizmet adını açıkça belirtmek olabilir (örn. articles: Model\ArticleRepository(@mainDb)). Ancak, bir hizmetin veya tercih edilen ilk hizmetin otomatik kablolamasını devre dışı bırakmak daha uygundur.

Devre Dışı Otomatik Kablolama

autowired: no seçeneğini kullanarak servis otomatik kablolamayı devre dışı bırakabilirsiniz:

services:
	mainDb: PDO(%dsn%, %user%, %password%)

	tempDb:
		create: PDO('sqlite::memory:')
		autowired: false # tempDb'yi otomatik bağlantıdan kaldırır

	articles: Model\ArticleRepository # bu nedenle mainDb'yi kurucuya geçirir

articles hizmeti, kurucuya aktarılabilecek PDO türünde iki eşleşen hizmet (yani mainDb ve tempDb) olduğu istisnasını atmaz, çünkü yalnızca mainDb hizmetini görür.

Nette'de otomatik kablolamanın yapılandırılması, autowire: false seçeneğinin hizmet kurucu argümanları için otomatik kablolamanın kullanılmaması gerektiğini söylediği Symfony'den farklı çalışır. Nette'de, ister kurucunun argümanları ister başka herhangi bir yöntem için olsun, otomatik bağlantı her zaman kullanılır. autowired: false seçeneği, servis örneğinin autowiring kullanılarak hiçbir yere aktarılmaması gerektiğini söyler.

Tercih Edilen Otomatik Kablolama

Aynı türde daha fazla hizmetimiz varsa ve bunlardan biri autowired seçeneğine sahipse, bu hizmet tercih edilen hizmet olur:

services:
	mainDb:
		create: PDO(%dsn%, %user%, %password%)
		autowired: PDO # tercih edilmesini sağlar

	tempDb:
		create: PDO('sqlite::memory:')

	articles: Model\ArticleRepository

articles hizmeti, eşleşen iki PDO hizmeti (yani mainDb ve tempDb) olduğu için istisna oluşturmaz, ancak tercih edilen hizmeti, yani mainDb kullanır.

Hizmetlerin Toplanması

Otomatik kablolama ayrıca belirli bir türdeki hizmetlerin bir dizisini de geçirebilir. PHP dizi öğelerinin türünü yerel olarak belirtemediğinden, array türüne ek olarak, ClassName[] gibi öğe türünü içeren bir phpDoc yorumu eklenmelidir:

namespace Model;

class ShipManager
{
	/**
	 * @param Shipper[] $shippers
	 */
	public function __construct(array $shippers)
	{}
}

DI kapsayıcısı daha sonra verilen türle eşleşen bir dizi hizmeti otomatik olarak geçirir. Otomatik kablolamanın kapalı olduğu hizmetleri atlar.

Yorumdaki tür şu biçimde de olabilir array<int, Class> veya list<Class>. Eğer phpDoc yorumunun biçimini kontrol edemiyorsanız, yapılandırmada doğrudan bir dizi hizmet iletebilirsiniz typed().

Skaler Argümanlar

Autowiring yalnızca nesneleri ve nesne dizilerini aktarabilir. Skaler argümanlar (örn. dizeler, sayılar, booleanlar) yapılandırmada yazılır. Bir alternatif, skaler bir değeri (veya birden fazla değeri) nesne olarak kapsülleyen bir settings-object oluşturmaktır; bu nesne daha sonra autowiring kullanılarak tekrar aktarılabilir.

class MySettings
{
	public function __construct(
		// readonly PHP 8.1'den beri kullanılabilir
		public readonly bool $value,
	)
	{}
}

Yapılandırmaya ekleyerek bir hizmet oluşturursunuz:

services:
	- MySettings('any value')

Daha sonra tüm sınıflar otomatik kablolama yoluyla bunu talep edecektir.

Otomatik Kablolamanın Daraltılması

Bireysel hizmetler için, otomatik kablolama belirli sınıflara veya arayüzlere daraltılabilir.

Normalde, otomatik kablolama hizmeti, hizmetin türüne karşılık gelen her bir yöntem parametresine geçirir. Daraltma, yöntem parametreleri için belirtilen türlerin, hizmetin onlara aktarılması için karşılaması gereken koşulları belirttiğimiz anlamına gelir.

Bir örnek verelim:

class ParentClass
{}

class ChildClass extends ParentClass
{}

class ParentDependent
{
	function __construct(ParentClass $obj)
	{}
}

class ChildDependent
{
	function __construct(ChildClass $obj)
	{}
}

Hepsini hizmet olarak kaydetseydik, otomatik kablolama başarısız olurdu:

services:
	parent: ParentClass
	child: ChildClass
	parentDep: ParentDependent  # İSTİSNAYI KALDIRIR, hem ebeveyn hem de çocuk eşleşir
	childDep: ChildDependent    # 'child' hizmetini yapıcıya geçirir

parentDep hizmeti Multiple services of type ParentClass found: parent, child istisnasını atar çünkü hem parent hem de child kurucusuna sığar ve otomatik kablolama hangisini seçeceğine karar veremez.

Bu nedenle child hizmeti için otomatik kablolamayı ChildClass olarak daraltabiliriz:

services:
	parent: ParentClass
	child:
		create: ChildClass
		autowired: ChildClass  # alternatif: 'autowired: self'

	parentDep: ParentDependent # THROWS EXCEPTION, 'child' autowired olamaz
	childDep: ChildDependent   # 'child' hizmetini yapıcıya geçirir

parentDep hizmeti artık tek eşleşen nesne olduğu için parentDep hizmet kurucusuna aktarılır. child hizmeti artık otomatik bağlantı ile aktarılmamaktadır. Evet, child hizmeti hala ParentClass türündedir, ancak parametre türü için verilen daraltma koşulu artık geçerli değildir, yani ParentClass 'nin ChildClass'un bir süper türü olduğu artık doğru değildir.

child durumunda, self mevcut hizmet türü anlamına geldiğinden autowired: ChildClass, autowired: self olarak yazılabilir.

autowired anahtarı, dizi olarak birkaç sınıf ve arayüz içerebilir:

autowired: [BarClass, FooInterface]

Örneğe arayüzler eklemeye çalışalım:

interface FooInterface
{}

interface BarInterface
{}

class ParentClass implements FooInterface
{}

class ChildClass extends ParentClass implements BarInterface
{}

class FooDependent
{
	function __construct(FooInterface $obj)
	{}
}

class BarDependent
{
	function __construct(BarInterface $obj)
	{}
}

class ParentDependent
{
	function __construct(ParentClass $obj)
	{}
}

class ChildDependent
{
	function __construct(ChildClass $obj)
	{}
}

child hizmetini sınırlandırmadığımızda, tüm FooDependent, BarDependent, ParentDependent ve ChildDependent sınıflarının kurucularına sığacak ve otomatik kablolama onu oraya geçirecektir.

Ancak, autowired: ChildClass (veya self) kullanarak ChildClass 'a otomatik bağlanmasını daraltırsak, otomatik bağlama sadece ChildDependent kurucusuna iletir, çünkü ChildClass türünde bir argüman gerektirir ve ChildClass * ChildClass türündedir. Diğer parametreler için belirtilen başka hiçbir tür ChildClass'un bir üst kümesi değildir, bu nedenle hizmet aktarılmaz.

Eğer autowired: ParentClass kullanarak bunu ParentClass ile sınırlarsak, otomatik kablolama bunu tekrar ChildDependent kurucusuna (gerekli tip ChildClass, ParentClass'un bir üst kümesi olduğundan) ve ParentDependent kurucusuna da iletecektir, çünkü ParentClass 'un gerekli tipi de eşleşmektedir.

Eğer FooInterface ile kısıtlarsak, ParentDependent (gerekli tip ParentClass, FooInterface'un bir üst tipidir) ve ChildDependent'a otomatik olarak bağlanmaya devam eder, ancak ek olarak FooDependent kurucusuna bağlanır, ancak BarInterface, FooInterface'un bir üst tipi olmadığı için BarDependent'a bağlanmaz.

services:
	child:
		create: ChildClass
		autowired: FooInterface

	fooDep: FooDependent        # servis çocuğunu yapıcıya geçirir
	barDep: BarDependent        # İSTİSNA OLUŞTURUR, hiçbir hizmet geçemez
	parentDep: ParentDependent  # hizmet çocuğunu yapıcıya geçirir
	childDep: ChildDependent    # hizmet çocuğunu yapıcıya geçirir