Nette DI için Uzantılar Oluşturma
Yapılandırma dosyalarına ek olarak bir DI konteyneri oluşturmak, uzantılar olarak adlandırılanları
da etkiler. Bunları extensions
bölümündeki yapılandırma dosyasında etkinleştiriyoruz.
BlogExtension
sınıfı tarafından temsil edilen uzantıyı blog
adıyla bu şekilde ekleriz:
extensions:
blog: BlogExtension
Her derleyici uzantısı Nette\DI\CompilerExtension adresinden miras alır ve DI derlemesi sırasında çağrılan aşağıdaki yöntemleri uygulayabilir:
- getConfigSchema()
- loadConfiguration()
- beforeCompile()
- afterCompile()
getConfigSchema()
Bu yöntem ilk olarak çağrılır. Yapılandırma parametrelerini doğrulamak için kullanılan şemayı tanımlar.
Uzantılar, adı uzantının eklendiği bölümle aynı olan bir bölümde yapılandırılır, örneğin blog
.
# uzantımla aynı isim
blog:
postsPerPage: 10
comments: false
Türleri, kabul edilen değerleri ve muhtemelen varsayılan değerleri de dahil olmak üzere tüm yapılandırma seçeneklerini tanımlayan bir şema tanımlayacağız:
use Nette\Schema\Expect;
class BlogExtension extends Nette\DI\CompilerExtension
{
public function getConfigSchema(): Nette\Schema\Schema
{
return Expect::structure([
'postsPerPage' => Expect::int(),
'allowComments' => Expect::bool()->default(true),
]);
}
}
Belgeler için Şema 'ya bakın. Ayrıca, dynamic()
adresini kullanarak
hangi seçeneklerin dinamik olabileceğini
belirtebilirsiniz, örneğin Expect::int()->dynamic()
.
Yapılandırmaya $this->config
, bir nesne olan stdClass
aracılığıyla erişiriz:
class BlogExtension extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
$num = $this->config->postPerPage;
if ($this->config->allowComments) {
// ...
}
}
}
loadConfiguration()
Bu yöntem konteynere hizmet eklemek için kullanılır. Bu işlem Nette\DI\ContainerBuilder tarafından yapılır:
class BlogExtension extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
$builder = $this->getContainerBuilder();
$builder->addDefinition($this->prefix('articles'))
->setFactory(App\Model\HomepageArticles::class, ['@connection']) // veya setCreator()
->addSetup('setLogger', ['@logger']);
}
}
Kural, bir uzantı tarafından eklenen hizmetlerin önüne kendi adını eklemektir, böylece isim çakışmaları ortaya
çıkmaz. Bu prefix()
tarafından yapılır, bu nedenle uzantı ‚blog‘ olarak adlandırılırsa, hizmet
blog.articles
olarak adlandırılacaktır.
Bir hizmeti yeniden adlandırmamız gerekirse, geriye dönük uyumluluğu korumak için orijinal adıyla bir takma ad
oluşturabiliriz. Benzer şekilde, Nette'in örneğin routing.router
için yaptığı şey budur, bu da daha önceki
router
adı altında da mevcuttur.
$builder->addAlias('router', 'routing.router');
Hizmetleri Bir Dosyadan Alma
ContainerBuilder API'sini kullanarak hizmetler oluşturabiliriz, ancak bunları tanıdık NEON yapılandırma dosyası ve
services
bölümü aracılığıyla da ekleyebiliriz. @extension
öneki mevcut uzantıyı
temsil eder.
services:
articles:
create: MyBlog\ArticlesModel(@connection)
comments:
create: MyBlog\CommentsModel(@connection, @extension.articles)
articlesList:
create: MyBlog\Components\ArticlesList(@extension.articles)
Hizmetleri bu şekilde ekleyeceğiz:
class BlogExtension extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
$builder = $this->getContainerBuilder();
// uzantı için yapılandırma dosyasını yükle
$this->compiler->loadDefinitionsFromConfig(
$this->loadFromFile(__DIR__ . '/blog.neon')['services'],
);
}
}
beforeCompile()
Kapsayıcı, loadConfiguration
yöntemlerinde bireysel uzantılar tarafından eklenen tüm hizmetleri ve
kullanıcı yapılandırma dosyalarını içerdiğinde yöntem çağrılır. Birleştirmenin bu aşamasında, daha sonra hizmet
tanımlarını değiştirebilir veya aralarına bağlantılar ekleyebiliriz. Hizmetleri etiketlere göre aramak için
findByTag()
yöntemini veya sınıf ya da arayüze göre aramak için findByType()
yöntemini
kullanabilirsiniz.
class BlogExtension extends Nette\DI\CompilerExtension
{
public function beforeCompile()
{
$builder = $this->getContainerBuilder();
foreach ($builder->findByTag('logaware') as $serviceName => $tagValue) {
$builder->getDefinition($serviceName)->addSetup('setLogger');
}
}
}
afterCompile()
Bu aşamada, konteyner sınıfı zaten bir ClassType nesnesi olarak üretilmiştir, servisin oluşturduğu tüm yöntemleri içerir ve PHP dosyası olarak önbelleğe alınmaya hazırdır. Bu noktada ortaya çıkan sınıf kodunu hala düzenleyebiliriz.
class BlogExtension extends Nette\DI\CompilerExtension
{
public function afterCompile(Nette\PhpGenerator\ClassType $class)
{
$method = $class->getMethod('__construct');
// ...
}
}
$başlatma
Yapılandırıcı, addBody() yöntemi kullanılarak bir
$this->initialization
nesnesine yazılarak oluşturulan konteyner oluşturulduktan sonra başlatma kodunu
çağırır.
Bir oturumun nasıl başlatılacağına veya başlatma kodunu kullanarak run
etiketine sahip hizmetlerin nasıl
başlatılacağına dair bir örnek göstereceğiz:
class BlogExtension extends Nette\DI\CompilerExtension
{
public function loadConfiguration()
{
// otomatik oturum başlatma
if ($this->config->session->autoStart) {
$this->initialization->addBody('$this->getService("session")->start()');
}
// 'run' etiketine sahip hizmetler konteyner oluşturulduktan sonra oluşturulmalıdır
$builder = $this->getContainerBuilder();
foreach ($builder->findByTag('run') as $name => $foo) {
$this->initialization->addBody('$this->getService(?);', [$name]);
}
}
}