Servislerin Tanımlanması
Yapılandırma, DI konteynerine bireysel servisleri nasıl oluşturacağını ve diğer bağımlılıklarla nasıl bağlayacağını öğrettiğimiz yerdir. Nette, bunu başarmak için çok net ve zarif bir yol sunar.
NEON formatındaki yapılandırma dosyasındaki services
bölümü, kendi servislerimizi ve yapılandırmalarını
tanımladığımız yerdir. PDO
sınıfının bir örneğini temsil eden database
adlı bir servisin
basit bir tanım örneğine bakalım:
services:
database: PDO('sqlite::memory:')
Yukarıdaki yapılandırma, DI konteynerinde aşağıdaki fabrika metoduna yol açacaktır:
public function createServiceDatabase(): PDO
{
return new PDO('sqlite::memory:');
}
Servis adları, yapılandırma dosyasının diğer bölümlerinde @servisAdi
formatında onlara başvurmamızı
sağlar. Bir servisi adlandırmaya gerek yoksa, basitçe bir tire kullanabiliriz:
services:
- PDO('sqlite::memory:')
DI konteynerinden bir servis almak için, parametre olarak servis adıyla getService()
metodunu veya servis
türüyle getByType()
metodunu kullanabiliriz:
$database = $container->getService('database');
$database = $container->getByType(PDO::class);
Servis Oluşturma
Çoğunlukla, bir servisi basitçe belirli bir sınıfın bir örneğini oluşturarak oluştururuz. Örneğin:
services:
database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
Yapılandırmayı ek anahtarlarla genişletmemiz gerekirse, tanımı birden çok satıra ayırabiliriz:
services:
database:
create: PDO('sqlite::memory:')
setup: ...
create
anahtarının factory
takma adı vardır, her iki varyant da pratikte yaygındır. Ancak,
create
kullanmanızı öneririz.
Yapıcı veya oluşturma metodunun argümanları alternatif olarak arguments
anahtarında yazılabilir:
services:
database:
create: PDO
arguments: ['mysql:host=127.0.0.1;dbname=test', root, secret]
Servisler sadece bir sınıfın örneğini basitçe oluşturarak oluşturulmak zorunda değildir, aynı zamanda statik metotların veya diğer servislerin metotlarının çağrılmasının sonucu da olabilirler:
services:
database: DatabaseFactory::create()
router: @routerFactory::create()
Basitlik için ->
yerine ::
kullanıldığına dikkat edin, bkz. #İfade Araçları. Bu fabrika metotları üretilecektir:
public function createServiceDatabase(): PDO
{
return DatabaseFactory::create();
}
public function createServiceRouter(): RouteList
{
return $this->getService('routerFactory')->create();
}
DI konteynerinin oluşturulan servisin türünü bilmesi gerekir. Belirtilen bir dönüş türü olmayan bir metot kullanarak bir servis oluşturuyorsak, bu türü yapılandırmada açıkça belirtmemiz gerekir:
services:
database:
create: DatabaseFactory::create()
type: PDO
Argümanlar
Yapıcıya ve metotlara argümanları, PHP'nin kendisinde olduğu gibi çok benzer bir şekilde iletiyoruz:
services:
database: PDO('mysql:host=127.0.0.1;dbname=test', root, secret)
Daha iyi okunabilirlik için argümanları ayrı satırlara ayırabiliriz. Bu durumda virgül kullanımı isteğe bağlıdır:
services:
database: PDO(
'mysql:host=127.0.0.1;dbname=test'
root
secret
)
Argümanları adlandırabilir ve sıralarıyla ilgilenmek zorunda kalmazsınız:
services:
database: PDO(
username: root
password: secret
dsn: 'mysql:host=127.0.0.1;dbname=test'
)
Bazı argümanları atlamak ve varsayılan değerlerini kullanmak veya autowiring kullanarak bir servis eklemek isterseniz, alt çizgi kullanın:
services:
foo: Foo(_, %appDir%)
Argüman olarak servisleri iletebilir, parametreleri kullanabilir ve çok daha fazlasını yapabilirsiniz, bkz. #İfade Araçları.
Setup
setup
bölümünde, servis oluşturulurken çağrılması gereken metotları tanımlarız.
services:
database:
create: PDO(%dsn%, %user%, %password%)
setup:
- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
Bu, PHP'de şöyle görünürdü:
public function createServiceDatabase(): PDO
{
$service = new PDO('...', '...', '...');
$service->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $service;
}
Metotları çağırmanın yanı sıra, özelliklere değerler de iletebilirsiniz. Bir diziye öğe eklemek de desteklenir, bu, NEON sözdizimiyle çakışmaması için tırnak içinde yazılmalıdır:
services:
foo:
create: Foo
setup:
- $value = 123
- '$onClick[]' = [@bar, clickHandler]
Bu, PHP kodunda şöyle görünürdü:
public function createServiceFoo(): Foo
{
$service = new Foo;
$service->value = 123;
$service->onClick[] = [$this->getService('bar'), 'clickHandler'];
return $service;
}
Ancak setup'ta statik metotları veya diğer servislerin metotlarını da çağırabilirsiniz. Argüman olarak mevcut servisi
iletmeniz gerekiyorsa, onu @self
olarak belirtin:
services:
foo:
create: Foo
setup:
- My\Helpers::initializeFoo(@self)
- @anotherService::setFoo(@self)
Basitlik için ->
yerine ::
kullanıldığına dikkat edin, bkz. #İfade Araçları. Böyle bir fabrika metodu üretilecektir:
public function createServiceFoo(): Foo
{
$service = new Foo;
My\Helpers::initializeFoo($service);
$this->getService('anotherService')->setFoo($service);
return $service;
}
İfade Araçları
Nette DI, neredeyse her şeyi yazabileceğimiz son derece zengin ifade araçları sunar. Yapılandırma dosyalarında parametreler kullanabiliriz:
# parametre
%wwwDir%
# anahtar altındaki parametre değeri
%mailer.user%
# dize içindeki parametre
'%wwwDir%/images'
Ayrıca nesneler oluşturabilir, metotları ve fonksiyonları çağırabiliriz:
# nesne oluşturma
DateTime()
# statik metot çağırma
Collator::create(%locale%)
# PHP fonksiyonu çağırma
::getenv(DB_USER)
Servislere adlarıyla veya türleriyle başvurabiliriz:
# ada göre servis
@database
# türe göre servis
@Nette\Database\Connection
Birinci sınıf çağrılabilir sözdizimini kullanın:
# geri arama oluşturma, [@user, logout] benzeri
@user::logout(...)
Sabitleri kullanın:
# sınıf sabiti
FilesystemIterator::SKIP_DOTS
# global sabiti PHP fonksiyonu constant() ile alırız
::constant(PHP_VERSION)
Metot çağrıları PHP'de olduğu gibi zincirlenebilir. Sadece basitlik için ->
yerine ::
kullanılır:
DateTime()::format('Y-m-d')
# PHP: (new DateTime())->format('Y-m-d')
@http.request::getUrl()::getHost()
# PHP: $this->getService('http.request')->getUrl()->getHost()
Bu ifadeleri her yerde, servis oluşturma, argümanlarda, #Setup bölümünde veya parametrelerde kullanabilirsiniz:
parameters:
ipAddress: @http.request::getRemoteAddress()
services:
database:
create: DatabaseFactory::create( @anotherService::getDsn() )
setup:
- initialize( ::getenv('DB_USER') )
Özel Fonksiyonlar
Yapılandırma dosyalarında şu özel fonksiyonları kullanabilirsiniz:
not()
değerin olumsuzlanmasıbool()
,int()
,float()
,string()
kayıpsız olarak belirtilen türe dönüştürmetyped()
belirtilen türdeki tüm servislerin bir dizisini oluştururtagged()
belirtilen etikete sahip tüm servislerin bir dizisini oluşturur
services:
- Foo(
id: int(::getenv('ProjectId'))
productionMode: not(%debugMode%)
)
PHP'deki klasik tür dönüştürme, örneğin (int)
gibi, aksine kayıpsız tür dönüştürme sayısal olmayan
değerler için bir istisna fırlatır.
typed()
fonksiyonu, belirtilen türdeki (sınıf veya arayüz) tüm servislerin bir dizisini oluşturur.
Autowiring'i devre dışı bırakılmış servisleri atlar. Virgülle ayrılmış birden çok tür de belirtebilirsiniz.
services:
- BarsDependent( typed(Bar) )
Belirli bir türdeki servislerin dizisini autowiring kullanarak otomatik olarak argüman olarak da iletebilirsiniz.
tagged()
fonksiyonu daha sonra belirli bir etikete sahip tüm servislerin bir dizisini oluşturur. Burada da
virgülle ayrılmış birden çok etiket belirtebilirsiniz.
services:
- LoggersDependent( tagged(logger) )
Autowiring
autowired
anahtarı, belirli bir servis için autowiring davranışını etkilemenizi sağlar. Ayrıntılar için
autowiring bölümü bakın.
services:
foo:
create: Foo
autowired: false # foo servisi autowiring'den çıkarıldı
Lazy Servisler
Lazy loading, bir servisin oluşturulmasını gerçekten ihtiyaç duyulana kadar erteleyen bir tekniktir. Global yapılandırmada, tüm servisler için aynı anda lazy oluşturmayı etkinleştirin. Bireysel servisler için daha sonra bu davranışı geçersiz kılabilirsiniz:
services:
foo:
create: Foo
lazy: false
Bir servis lazy olarak tanımlandığında, DI konteynerinden istendiğinde özel bir yer tutucu nesne alırız. Bu, gerçek servis gibi görünür ve davranır, ancak gerçek başlatma (yapıcı ve setup çağrısı) yalnızca herhangi bir metodunun veya özelliğinin ilk çağrısında gerçekleşir.
Lazy loading yalnızca kullanıcı sınıfları için kullanılabilir, dahili PHP sınıfları için kullanılamaz. PHP 8.4 veya daha yenisini gerektirir.
Etiketler (Tags)
Etiketler, servislere ek bilgiler eklemek için kullanılır. Bir servise bir veya daha fazla etiket ekleyebilirsiniz:
services:
foo:
create: Foo
tags:
- cached
Etiketler ayrıca değerler de taşıyabilir:
services:
foo:
create: Foo
tags:
logger: monolog.logger.event
Belirli etiketlere sahip tüm servisleri almak için tagged()
fonksiyonunu kullanabilirsiniz:
services:
- LoggersDependent( tagged(logger) )
DI konteynerinde, belirli bir etikete sahip tüm servislerin adlarını findByTag()
metodunu kullanarak
alabilirsiniz:
$names = $container->findByTag('logger');
// $names, servis adını ve etiket değerini içeren bir dizidir
// örn. ['foo' => 'monolog.logger.event', ...]
Inject Modu
inject: true
bayrağı kullanılarak, inject anotasyonuna sahip public
değişkenler ve inject*()
metotları aracılığıyla bağımlılıkların iletilmesi etkinleştirilir.
services:
articles:
create: App\Model\Articles
inject: true
Varsayılan olarak, inject
yalnızca presenter'lar için etkinleştirilir.
Servislerin Değiştirilmesi
DI konteyneri, yerleşik veya kullanıcı uzantısı aracılığıyla eklenen birçok servis
içerir. Bu servislerin tanımlarını doğrudan yapılandırmada değiştirebilirsiniz. Örneğin,
application.application
servisinin sınıfını, standart olarak Nette\Application\Application
olan,
başka bir sınıfla değiştirebilirsiniz:
services:
application.application:
create: MyApplication
alteration: true
alteration
bayrağı bilgilendiricidir ve yalnızca mevcut bir servisi değiştirdiğimizi belirtir.
Setup'ı da tamamlayabiliriz:
services:
application.application:
create: MyApplication
alteration: true
setup:
- '$onStartup[]' = [@resource, init]
Bir servisi yeniden yazarken, orijinal argümanları, setup öğelerini veya etiketleri kaldırmak isteyebiliriz, bunun için
reset
kullanılır:
services:
application.application:
create: MyApplication
alteration: true
reset:
- arguments
- setup
- tags
Bir uzantı tarafından eklenen bir servisi kaldırmak isterseniz, bunu şu şekilde yapabilirsiniz:
services:
cache.journal: false