Bootstrapping
Bootstrapping, uygulama ortamının hazırlanması, bağımlılık enjeksiyonu (DI) konteynerinin oluşturulması ve uygulamanın başlatılması sürecidir. Şunları ele alacağız:
- Bootstrap sınıfının ortamı nasıl hazırladığını
- uygulamaların NEON dosyalarıyla nasıl yapılandırıldığını
- üretim ve geliştirme modunun nasıl ayırt edildiğini
- DI konteynerinin nasıl oluşturulup yapılandırıldığını
Uygulamalar, ister web tabanlı ister komut satırından çalıştırılan betikler olsun, çalışmalarına bir tür ortam
hazırlığıyla başlar. Eskiden bundan, ilk dosyanın dahil ettiği belki include.inc.php adlı bir dosya
sorumluydu. Modern Nette uygulamalarında onun yerini, uygulamanın bir parçası olarak app/Bootstrap.php
dosyasında bulunan Bootstrap sınıfı aldı. Örneğin şöyle görünebilir:
namespace App;
use Nette;
use Nette\Bootstrap\Configurator;
class Bootstrap
{
private Configurator $configurator;
private string $rootDir;
public function __construct()
{
$this->rootDir = dirname(__DIR__);
// Configurator, uygulama ortamının ve servislerin kurulumundan sorumludur.
$this->configurator = new Configurator;
// Nette'in ürettiği geçici dosyalar (örneğin derlenmiş şablonlar) için dizini ayarla
$this->configurator->setTempDirectory($this->rootDir . '/temp');
}
public function bootWebApplication(): Nette\DI\Container
{
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}
private function initializeEnvironment(): void
{
// Nette akıllıdır ve geliştirme modu kendiliğinden açılır,
// ya da aşağıdaki satırın yorumunu kaldırarak belirli bir IP adresi için etkinleştirebilirsiniz:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Tracy'yi etkinleştirir: en iyi "İsviçre çakısı" hata ayıklama aracı.
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: seçilen dizindeki tüm sınıfları otomatik yükler
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Yapılandırma dosyalarını yükle
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
Web uygulamalarında ilk dosya, genel
dizin www/ içinde yer alan index.php'dir. Bootstrap sınıfına ortamı hazırlamasını ve DI
konteynerini oluşturmasını söyler. Sonra konteynerden Application servisini alır ve o da web uygulamasını
çalıştırır:
$bootstrap = new App\Bootstrap;
// Ortamı hazırla + DI konteynerini oluştur
$container = $bootstrap->bootWebApplication();
// DI konteyneri bir Nette\Application\Application nesnesi oluşturur
$application = $container->getByType(Nette\Application\Application::class);
// Nette uygulamasını başlat ve gelen isteği işle
$application->run();
$application nesnesi, isteği işlerken olaylar yayar: onStartup, onRequest,
onPresenter, onResponse, onShutdown ve onError (işlenmemiş bir istisnada).
Bunlara işleyici bağlayabilirsiniz; günlükleme veya uygulama geneli izleme için kullanışlıdır.
Gördüğünüz gibi, ortamın kurulmasına ve bağımlılık enjeksiyonu (DI) konteynerinin oluşturulmasına Nette\Bootstrap\Configurator sınıfı yardım eder. Şimdi onu daha ayrıntılı tanıtacağız.
Geliştirme modu ve üretim modu
Nette, bir geliştirme sunucusunda mı yoksa üretim sunucusunda mı çalıştığına göre farklı davranır:
- 🛠️ Geliştirme modu
- Yararlı bilgiler içeren Tracy hata ayıklama çubuğunu gösterir (SQL sorguları, çalışma süresi, kullanılan bellek)
- Hata durumunda, fonksiyon çağrılarını ve değişken içeriklerini gösteren ayrıntılı bir hata sayfası gösterir
- Latte şablonları, yapılandırma dosyaları vb. değiştiğinde önbelleği otomatik yeniler
- 🚀 Üretim modu
- Hiçbir hata ayıklama bilgisi göstermez, tüm hatalar günlüğe yazılır
- Hata durumunda ErrorPresenter'ı veya genel bir “Server Error” sayfasını gösterir
- Önbellek asla otomatik yenilenmez!
- Hız ve güvenlik için iyileştirilmiştir
Mod seçimi otomatik algılamayla yapılır, bu yüzden genellikle bir şey yapılandırmaya veya modu elle değiştirmeye gerek yoktur:
- geliştirme modu: localhost'ta (IP adresi
127.0.0.1veya::1), proxy yoksa (yani HTTP header'ı algılanmıyorsa) - üretim modu: diğer her yerde
Geliştirme modunu başka durumlarda da etkinleştirmek istersek, örneğin belirli bir IP adresinden erişen programcılar
için, setDebugMode() kullanırız:
$this->configurator->setDebugMode('23.75.345.200'); // bir IP adresi dizisi de verilebilir
IP adresini bir çerezle birleştirmenizi kesinlikle öneririz. nette-debug çerezinde gizli bir belirteç,
örneğin secret1234, saklayın ve böylece geliştirme modunu, belirli bir IP adresinden erişen ve çerezinde bu
belirteci de taşıyan programcılar için etkinleştirin:
$this->configurator->setDebugMode('secret1234@23.75.345.200');
Geliştirme modunu, localhost için bile, tamamen kapatabiliriz de:
$this->configurator->setDebugMode(false);
true değerinin geliştirme modunu zorla açtığını, bunun da bir üretim sunucusunda asla olmaması
gerektiğini unutmayın.
Otomatik algılamayı içeride Configurator::detectDebugMode() statik metodu yürütür; onu kendiniz de
çağırabilirsiniz, örneğin geliştirme modunu configurator dışında algılamak için. İsteğe bağlı bir IP adresi veya
bilgisayar adı beyaz listesi kabul eder ve geçerli isteğin geliştirme modunda çalışıp çalışmayacağını
döndürür:
$debug = Nette\Bootstrap\Configurator::detectDebugMode('23.75.345.200');
Hata ayıklama aracı Tracy
Kolay hata ayıklama için mükemmel Tracy aracını etkinleştireceğiz. Geliştirme modunda hataları görselleştirir, üretim modunda ise belirtilen dizine günlükler:
$this->configurator->enableTracy($this->rootDir . '/log');
Geçici dosyalar
Nette; DI konteyneri, RobotLoader, şablonlar vb. için önbellek kullanır. Bu yüzden önbelleğin saklanacağı dizinin yolunu ayarlamak gerekir:
$this->configurator->setTempDirectory($this->rootDir . '/temp');
Linux veya macOS'ta log/ ve temp/ dizinleri için yazma izinlerini ayarlayın.
RobotLoader
Genellikle sınıfları RobotLoader ile otomatik yüklemek isteriz, bu
yüzden onu başlatmamız ve Bootstrap.php'nin bulunduğu dizinden (yani __DIR__) ve tüm alt
dizinlerinden sınıfları yüklemesini sağlamamız gerekir:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Alternatif bir yaklaşım, sınıfları yalnızca PSR-4'e uygun olarak Composer üzerinden yüklemektir.
Saat dilimi
Varsayılan saat dilimini configurator ile ayarlayabilirsiniz.
$this->configurator->setTimeZone('Europe/Prague');
DI konteynerinin yapılandırması
Başlatma sürecinin bir parçası, tüm uygulamanın kalbi olan DI konteynerinin, yani nesne factory'sinin oluşturulmasıdır. Aslında Nette tarafından üretilen ve önbellek dizininde saklanan bir PHP sınıfıdır. Factory, uygulamanın anahtar nesnelerini üretir; yapılandırma dosyalarıyla ona bunları nasıl oluşturup ayarlayacağını söyleriz ve böylece tüm uygulamanın davranışını etkileriz.
Yapılandırma dosyaları genellikle NEON formatında yazılır. Ayrı bir bölümde neyin yapılandırılabileceğini okuyabilirsiniz.
Geliştirme modunda konteyner, kod veya yapılandırma dosyaları her değiştiğinde otomatik güncellenir. Üretim modunda ise yalnızca bir kez üretilir ve performansı en üst düzeye çıkarmak için değişiklikler denetlenmez.
createContainer() konteyneri kurup örneğini döndürürken, loadContainer() metodu yalnızca
üretilen konteyner sınıfının adını döndürür; onu kendiniz örnekleyebilirsiniz. Bu, ileri düzey senaryolarda
işe yarar.
Yapılandırma dosyaları addConfig() ile yüklenir:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
Daha fazla yapılandırma dosyası eklemek istersek, addConfig() fonksiyonunu birden çok kez
çağırabiliriz.
$configDir = $this->rootDir . '/config';
$this->configurator->addConfig($configDir . '/common.neon');
$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
$this->configurator->addConfig($configDir . '/cli.php');
}
cli.php adı yazım hatası değildir; yapılandırma, onu dizi olarak döndüren bir PHP dosyasında da
yazılabilir.
Başka yapılandırma dosyalarını includes bölümünde
de ekleyebiliriz.
Yapılandırma dosyalarında aynı anahtarlara sahip öğeler geçerse üzerine yazılır, dizilerde ise birleştirilir. Sonra dahil
edilen dosyanın önceliği öncekinden yüksektir. includes bölümünün listelendiği dosyanın önceliği,
içinde dahil edilen dosyalardan yüksektir.
Statik parametreler
Yapılandırma dosyalarında kullanılan parametreler parameters bölümünde
tanımlanabilir ve ayrıca addStaticParameters() metoduyla (eski, artık kullanımdan kaldırılmış takma adı
addParameters()) aktarılabilir veya üzerine yazılabilir. Önemli olan, farklı parametre değerlerinin ek DI
konteynerlerinin, yani ek sınıfların üretilmesine yol açmasıdır.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
projectId parametresine yapılandırmada standart %projectId% gösterimiyle başvurulabilir.
Dinamik parametreler
Konteynere dinamik parametreler de ekleyebiliriz; bunların farklı değerleri, statik parametrelerin aksine, yeni DI konteynerlerinin üretilmesine yol açmaz.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
Böylece örneğin ortam değişkenlerini kolayca ekleyebiliriz; onlara yapılandırmada %env.degisken%
gösterimiyle başvurulabilir.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Varsayılan parametreler
Yapılandırma dosyalarında şu parametreleri kullanabilirsiniz:
%appDir%,Bootstrap.phpdosyasını içeren dizinin mutlak yoludur%wwwDir%, giriş dosyasıindex.php'yi içeren dizinin mutlak yoludur%tempDir%, geçici dosyalar dizininin mutlak yoludur%vendorDir%, Composer'ın kütüphaneleri kurduğu dizinin mutlak yoludur%rootDir%, projenin kök dizininin mutlak yoludur%baseUrl%, kök dizine giden mutlak URL'dir (çalışma zamanında çözülen dinamik bir parametre)%debugMode%, uygulamanın hata ayıklama modunda olup olmadığını belirtir%consoleMode%, isteğin komut satırından gelip gelmediğini belirtir
İçe aktarılan servisler
Şimdi biraz derine iniyoruz. DI konteynerinin amacı nesne oluşturmak olsa da, ara sıra var olan bir nesneyi konteynere
yerleştirme ihtiyacı doğabilir. Bunu, servisi imported: true bayrağıyla tanımlayarak yaparız.
services:
myservice:
type: App\Model\MyCustomService
imported: true
Ve bootstrap'ta nesneyi konteynere yerleştiririz:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Farklı ortamlar
Bootstrap sınıfını ihtiyaçlarınıza göre çekinmeden değiştirin. Web projelerini ayırt etmek için
bootWebApplication() metoduna parametre ekleyebilirsiniz. Ya da başka metotlar ekleyebiliriz; örneğin birim
testleri için ortamı hazırlayan bootTestEnvironment(), komut satırından çağrılan betikler için
bootConsoleApplication() vb.
public function bootTestEnvironment(): Nette\DI\Container
{
Tester\Environment::setup(); // Nette Tester'ın başlatılması
$this->setupContainer();
return $this->configurator->createContainer();
}
public function bootConsoleApplication(): Nette\DI\Container
{
$this->configurator->setDebugMode(false);
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}