Bootstrap
A Bootstrap egy indítókód, amely inicializálja a környezetet, létrehozza a dependency injection (DI) konténert és elindítja az alkalmazást. Megbeszéljük:
- hogyan konfigurálható NEON fájlok segítségével
- hogyan különböztethető meg az éles és a fejlesztői mód
- hogyan hozható létre a DI konténer
Az alkalmazások, legyenek azok webesek vagy parancssorból futtatott szkriptek, működésüket valamilyen környezet
inicializálási formával kezdik. Régen ezt egy include.inc.php
nevű fájl intézte, amelyet az elsődleges fájl
inkludált. A modern Nette alkalmazásokban ezt a Bootstrap
osztály váltotta fel, amelyet az alkalmazás
részeként az app/Bootstrap.php
fájlban találhat meg. Például így nézhet ki:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
private Configurator $configurator;
private string $rootDir;
public function __construct()
{
$this->rootDir = dirname(__DIR__);
// A Configurator felelős az alkalmazás környezetének és szolgáltatásainak beállításáért.
$this->configurator = new Configurator;
// Beállítja a Nette által generált ideiglenes fájlok (pl. fordított sablonok) könyvtárát
$this->configurator->setTempDirectory($this->rootDir . '/temp');
}
public function bootWebApplication(): Nette\DI\Container
{
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}
private function initializeEnvironment(): void
{
// A Nette okos, és a fejlesztői mód automatikusan bekapcsolódik,
// vagy engedélyezheti egy adott IP-címre a következő sor kommentjének eltávolításával:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Aktiválja a Tracy-t: a végső "svájci bicska" a debuggoláshoz.
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: automatikusan betölti az összes osztályt a kiválasztott könyvtárban
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Betölti a konfigurációs fájlokat
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
A webalkalmazások esetében az elsődleges fájl az index.php
, amely a nyilvános könyvtárban
(www/
) található. Ez a Bootstrap osztálytól kéri a környezet inicializálását és a DI konténer
létrehozását. Ezután ebből szerzi be az Application
szolgáltatást, amely elindítja a webalkalmazást:
$bootstrap = new App\Bootstrap;
// Környezet inicializálása + DI konténer létrehozása
$container = $bootstrap->bootWebApplication();
// A DI konténer létrehozza a Nette\Application\Application objektumot
$application = $container->getByType(Nette\Application\Application::class);
// A Nette alkalmazás elindítása és a bejövő kérés feldolgozása
$application->run();
Mint látható, a környezet beállításában és a dependency injection (DI) konténer létrehozásában a Nette\Bootstrap\Configurator osztály segít, amelyet most részletesebben bemutatunk.
Fejlesztői vs éles mód
A Nette eltérően viselkedik attól függően, hogy fejlesztői vagy éles szerveren fut:
- 🛠️ Fejlesztői mód (Development)
- Megjeleníti a Tracy debugbart hasznos információkkal (SQL lekérdezések, végrehajtási idő, felhasznált memória)
- Hiba esetén részletes hibaoldalt jelenít meg a függvényhívásokkal és a változók tartalmával
- Automatikusan frissíti a cache-t a Latte sablonok módosításakor, a konfigurációs fájlok szerkesztésekor stb.
- 🚀 Éles mód (Production)
- Nem jelenít meg semmilyen debuggolási információt, minden hibát a logba ír
- Hiba esetén az ErrorPresentert vagy egy általános “Server Error” oldalt jelenít meg
- A cache soha nem frissül automatikusan!
- Optimalizálva a sebességre és a biztonságra
A mód kiválasztása automatikus felismeréssel történik, így általában nincs szükség semmit konfigurálni vagy manuálisan átváltani:
- fejlesztői mód: localhoston (IP-cím
127.0.0.1
vagy::1
), ha nincs proxy (azaz annak HTTP fejléce) - éles mód: mindenhol máshol
Ha a fejlesztői módot más esetekben is engedélyezni szeretnénk, például egy adott IP-címről hozzáférő programozók
számára, használjuk a setDebugMode()
metódust:
$this->configurator->setDebugMode('23.75.345.200'); // IP-címek tömbje is megadható
Határozottan javasoljuk az IP-cím és a cookie kombinálását. A nette-debug
cookie-ba mentsünk el egy titkos
tokent, pl. secret1234
, és így aktiváljuk a fejlesztői módot az adott IP-címről hozzáférő és a cookie-ban
említett tokennel rendelkező programozók számára:
$this->configurator->setDebugMode('secret1234@23.75.345.200');
A fejlesztői módot teljesen ki is kapcsolhatjuk, még localhostra is:
$this->configurator->setDebugMode(false);
Figyelem, a true
érték véglegesen bekapcsolja a fejlesztői módot, ami soha nem történhet meg éles
szerveren.
Tracy debuggoló eszköz
A könnyű debuggolás érdekében kapcsoljuk be a nagyszerű Tracy eszközt. Fejlesztői módban vizualizálja a hibákat, éles módban pedig a hibákat a megadott könyvtárba logolja:
$this->configurator->enableTracy($this->rootDir . '/log');
Ideiglenes fájlok
A Nette cache-t használ a DI konténerhez, a RobotLoaderhez, a sablonokhoz stb. Ezért szükséges beállítani annak a könyvtárnak az elérési útját, ahová a cache mentésre kerül:
$this->configurator->setTempDirectory($this->rootDir . '/temp');
Linuxon vagy macOS-en állítsa be a log/
és temp/
könyvtáraknak az írási jogokat.
RobotLoader
Általában szeretnénk automatikusan betölteni az osztályokat a RobotLoader segítségével, ezért el kell indítanunk, és hagynunk kell, hogy
betöltse az osztályokat abból a könyvtárból, ahol a Bootstrap.php
található (azaz __DIR__
), és
az összes alkönyvtárából:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Alternatív megközelítés az osztályok betöltésének kizárólag a Composer segítségével történő engedélyezése a PSR-4 betartása mellett.
Időzóna
A konfigurátoron keresztül beállíthatja az alapértelmezett időzónát.
$this->configurator->setTimeZone('Europe/Prague');
DI konténer konfigurálása
Az indítási folyamat része a DI konténer, vagyis az objektumgyár létrehozása, amely az egész alkalmazás szíve. Ez valójában egy PHP osztály, amelyet a Nette generál és a cache könyvtárba ment. A gyár gyártja az alkalmazás kulcsfontosságú objektumait, és a konfigurációs fájlok segítségével utasítjuk, hogyan hozza létre és állítsa be őket, ezzel befolyásolva az egész alkalmazás viselkedését.
A konfigurációs fájlokat általában NEON formátumban írják. Egy külön fejezetben olvashat arról, mit lehet konfigurálni.
Fejlesztői módban a konténer automatikusan frissül minden kód- vagy konfigurációs fájl módosításakor. Éles módban csak egyszer generálódik, és a változások a maximális teljesítmény érdekében nem kerülnek ellenőrzésre.
A konfigurációs fájlokat a addConfig()
segítségével töltjük be:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
Ha több konfigurációs fájlt szeretnénk hozzáadni, többször is meghívhatjuk az addConfig()
függvényt.
$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');
}
A cli.php
név nem elírás, a konfiguráció PHP fájlban is megadható, amely tömbként adja vissza.
További konfigurációs fájlokat is hozzáadhatunk az includes
szekcióban.
Ha a konfigurációs fájlokban azonos kulcsokkal rendelkező elemek jelennek meg, azok felülíródnak, vagy tömbök esetén egyesülnek. A később
beillesztett fájlnak magasabb prioritása van, mint az előzőnek. Annak a fájlnak, amelyben az includes
szekció
szerepel, magasabb prioritása van, mint a benne inkludált fájloknak.
Statikus paraméterek
A konfigurációs fájlokban használt paramétereket definiálhatjuk a parameters
szekcióban, és
átadhatjuk (vagy felülírhatjuk) az addStaticParameters()
metódussal (van addParameters()
aliasa is).
Fontos, hogy a paraméterek különböző értékei további DI konténerek, azaz további osztályok generálását
eredményezik.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
A projectId
paraméterre a konfigurációban a szokásos %projectId%
jelöléssel lehet
hivatkozni.
Dinamikus paraméterek
A konténerhez dinamikus paramétereket is hozzáadhatunk, amelyek különböző értékei, a statikus paraméterekkel ellentétben, nem okozzák új DI konténerek generálását.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
Így egyszerűen hozzáadhatunk pl. környezeti változókat, amelyekre aztán a konfigurációban a
%env.variable%
jelöléssel lehet hivatkozni.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Alapértelmezett paraméterek
A konfigurációs fájlokban használhatja ezeket a statikus paramétereket:
%appDir%
az abszolút elérési út aBootstrap.php
fájlt tartalmazó könyvtárhoz%wwwDir%
az abszolút elérési út aindex.php
bemeneti fájlt tartalmazó könyvtárhoz%tempDir%
az abszolút elérési út az ideiglenes fájlok könyvtárához%vendorDir%
az abszolút elérési út ahhoz a könyvtárhoz, ahová a Composer telepíti a könyvtárakat%rootDir%
az abszolút elérési út a projekt gyökérkönyvtárához%debugMode%
jelzi, hogy az alkalmazás debug módban van-e%consoleMode%
jelzi, hogy a kérés parancssorból érkezett-e
Importált szolgáltatások
Most mélyebbre megyünk. Bár a DI konténer célja az objektumok gyártása, kivételesen szükség lehet egy meglévő
objektum beillesztésére a konténerbe. Ezt úgy tehetjük meg, hogy a szolgáltatást imported: true
jelzővel
definiáljuk.
services:
myservice:
type: App\Model\MyCustomService
imported: true
És a bootstrapban beillesztjük az objektumot a konténerbe:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Eltérő környezet
Ne féljen módosítani a Bootstrap osztályt saját igényei szerint. A bootWebApplication()
metódushoz
hozzáadhat paramétereket a webprojektek megkülönböztetésére. Vagy kiegészíthetjük további metódusokkal, például
bootTestEnvironment()
, amely inicializálja a környezetet az egységtesztekhez,
bootConsoleApplication()
a parancssorból hívott szkriptekhez stb.
public function bootTestEnvironment(): Nette\DI\Container
{
Tester\Environment::setup(); // Nette Tester inicializálása
$this->setupContainer();
return $this->configurator->createContainer();
}
public function bootConsoleApplication(): Nette\DI\Container
{
$this->configurator->setDebugMode(false);
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}