Bootstrap
A Bootstrap egy indító kód, amely inicializálja a környezetet, létrehoz egy függőségi injektálási (DI) konténert, és elindítja az alkalmazást. Megbeszéljük:
- hogyan konfigurálhatja az alkalmazást NEON fájlok segítségével.
- hogyan kezelje a termelési és a fejlesztési módokat
- hogyan hozzuk létre a DI konténert
Az alkalmazások, akár webes alapúak, akár parancssori szkriptek, valamilyen környezet-inicializálással kezdődnek.
A régi időkben ez egy pl. include.inc.php
nevű fájl lehetett, amely ezért volt felelős, és a kezdeti fájlban
szerepelt. A modern Nette alkalmazásokban ezt felváltotta a Bootstrap
osztály, amely az alkalmazás részeként a
app/Bootstrap.php
. Ez 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 konfigurátor felelős az alkalmazási környezet és a szolgáltatások beállításáért.
$this->configurator = new Configurator;
// A Nette által generált ideiglenes fájlok (pl. lefordított sablonok) könyvtárának beállítása.
$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 intelligens, és a fejlesztői üzemmód automatikusan bekapcsol,
// vagy engedélyezheti egy adott IP-címre a következő sor megjegyzésének feloldásával:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Bekapcsolja a Tracy-t: a végső "svájci bicska" hibakeresési eszköz.
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: automatikusan feltölti az összes osztályt a megadott könyvtárban.
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Konfigurációs fájlok betöltése
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
A webes alkalmazások kezdőfájlja a index.php
, amely a www/
nyilvános könyvtárban található.
A Bootstrap
osztályt használja a környezet inicializálásához és a DI konténer létrehozásához. Ezután
megszerzi a Application
szolgáltatást a konténerből, amely elindítja a webalkalmazást:
$bootstrap = new App\Bootstrap;
// A környezet inicializálása + DI konténer létrehozása
$container = $bootstrap->bootWebApplication();
// A DI konténer létrehoz egy Nette\Application\Application objektumot.
$application = $container->getByType(Nette\Application\Application::class);
// A Nette-alkalmazás elindítása és a bejövő kérések kezelése.
$application->run();
Mint látható, a Nette\Bootstrap\Configurator osztály, amelyet most részletesebben bemutatunk, segít a környezet beállításában és a függőségi injektálás (DI) konténer létrehozásában.
Fejlesztői vs. termelési üzemmód
A Nette két alapvető módot különböztet meg, amelyben egy kérés végrehajtásra kerül: fejlesztési és termelési mód. A fejlesztési mód a programozó maximális kényelmére összpontosít, a Tracy megjelenik, a gyorsítótár automatikusan frissül, ha a sablonok vagy a DI konténer konfigurációja változik, stb. A termelési mód a teljesítményre összpontosít, a Tracy csak a hibákat naplózza, a sablonok és egyéb fájlok módosításait nem ellenőrzi.
A mód kiválasztása automatikus felismeréssel történik, így általában nem szükséges kézzel konfigurálni vagy
váltani semmit. A mód fejlesztési, ha az alkalmazás localhoston fut (azaz a 127.0.0.1
vagy a ::1
IP-címen ) és nincs proxy (azaz a HTTP fejléce). Ellenkező esetben termelési üzemmódban fut.
Ha más esetekben, például egy adott IP-címről hozzáférő programozók számára szeretné engedélyezni a fejlesztési
üzemmódot, akkor a setDebugMode()
címet használhatja:
$this->configurator->setDebugMode('23.75.345.200'); // egy vagy több IP-cím
Mindenképpen javasoljuk az IP-cím és a cookie kombinálását. A nette-debug
cookie-ban tárolunk egy titkos
tokent, pl. secret1234
, és a fejlesztési mód az IP és a cookie ilyen kombinációjával rendelkező programozók
számára aktiválódik.
$this->configurator->setDebugMode('secret1234@23.75.345.200');
A fejlesztői módot teljesen ki is kapcsolhatjuk, akár a localhost esetében is:
$this->configurator->setDebugMode(false);
A true
érték keményen bekapcsolja a fejlesztői módot, ami soha nem történhet meg egy termelő
szerveren.
Hibakereső eszköz Tracy
Az egyszerű hibakeresés érdekében bekapcsoljuk a Tracy nevű nagyszerű eszközt. Fejlesztői módban megjeleníti a hibákat, termelési módban pedig a megadott könyvtárba naplózza a hibákat:
$this->configurator->enableTracy($this->rootDir . '/log');
Ideiglenes fájlok
A Nette a DI konténer, a RobotLoader, a sablonok stb. számára használja a gyorsítótárat. Ezért szükséges annak a könyvtárnak az elérési útvonalát beállítani, ahol a gyorsítótár tárolásra kerül:
$this->configurator->setTempDirectory($this->rootDir . '/temp');
Linuxon vagy macOS-en állítsa be a log/
és a temp/
könyvtárak írási engedélyeit.
RobotLoader
Általában a RobotLoader segítségével szeretnénk automatikusan
betölteni az osztályokat, 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 annak összes alkönyvtárából:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Egy alternatív megoldás az, hogy csak a Composer PSR-4 automatikus betöltését használjuk.
Időzóna
A Configurator lehetővé teszi, hogy megadjon egy időzónát az alkalmazásához.
$this->configurator->setTimeZone('Europe/Prague');
DI konténer konfigurálása
Az indítási folyamat része a DI konténer, azaz az objektumgyár létrehozása, amely az egész alkalmazás szíve. Ez tulajdonképpen egy Nette által generált és egy cache könyvtárban tárolt PHP osztály. A gyár létrehozza az alkalmazás kulcsfontosságú objektumait, a konfigurációs fájlok pedig utasítják, hogyan hozza létre és konfigurálja őket, és így befolyásoljuk az egész alkalmazás viselkedését.
A konfigurációs fájlokat általában NEON formátumban írjuk. Itt olvashatja el, hogy mit lehet konfigurálni.
Fejlesztői üzemmódban a konténer automatikusan frissül minden alkalommal, amikor megváltoztatja a kódot vagy a konfigurációs fájlokat. Termelési módban csak egyszer generálódik, és a teljesítmény maximalizálása érdekében a fájlváltozásokat nem ellenőrzi a rendszer.
A konfigurációs fájlok betöltése a addConfig()
segítségével történik:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
A addConfig()
metódus többször is meghívható több fájl hozzáadásához.
$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ó egy PHP fájlba is írható, amely tömbként adja vissza.
Alternatívaként használhatjuk a includes
szekciót is,
hogy több konfigurációs fájlt töltsünk be.
Ha a konfigurációs fájlokban azonos kulcsú elemek jelennek meg, akkor azok felülíródnak, vagy tömbök esetén összevonásra kerülnek. A később bevont
fájlnak magasabb prioritása van, mint az előzőnek. Az a fájl, amelyben a includes
szakasz szerepel, magasabb
prioritással rendelkezik, mint a benne foglalt fájlok.
Statikus paraméterek
A konfigurációs fájlokban használt paramétereket a parameters
szakaszban lehet
definiálni, és a addStaticParameters()
metódus (amelynek alias neve addParameters()
) is átadhatja
(vagy felülírhatja). Fontos, hogy a különböző paraméterértékek további DI-konténerek, azaz további osztályok
generálását okozzák.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
A konfigurációs fájlokban a %projectId%
szokásos jelölést írhatjuk a projectId
nevű
paraméter eléréséhez.
Dinamikus paraméterek
A konténerhez dinamikus paramétereket is hozzáadhatunk, ezek eltérő értékei a statikus paraméterekkel ellentétben nem okoznak új DI-konténerek generálását.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
A környezeti változókat könnyen elérhetővé tehetnénk dinamikus paraméterek segítségével. A konfigurációs
fájlokban a %env.variable%
címen keresztül érhetjük el őket.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Alapértelmezett paraméterek
A konfigurációs fájlokban a következő statikus paramétereket használhatja:
%appDir%
aBootstrap.php
fájl könyvtárának abszolút elérési útja.%wwwDir%
aindex.php
beviteli fájlt tartalmazó könyvtár abszolút elérési útja.%tempDir%
az ideiglenes fájlok könyvtárának abszolút elérési útja.%vendorDir%
az abszolút elérési út a könyvtárak Composer általi telepítésének könyvtárához.%rootDir%
a projekt gyökérkönyvtárának abszolút elérési útvonala.%debugMode%
jelzi, hogy az alkalmazás hibakeresési módban van-e.%consoleMode%
jelzi, hogy a kérés a parancssoron keresztül érkezett-e.
Importált szolgáltatások
Most mélyebbre megyünk. Bár a DI konténer célja az objektumok létrehozása, kivételesen szükség lehet arra, hogy egy
meglévő objektumot beillesszünk a konténerbe. Ezt úgy tesszük meg, hogy a szolgáltatást a imported: true
attribútummal definiáljuk.
services:
myservice:
type: App\Model\MyCustomService
imported: true
Hozzunk létre egy új példányt, és illesszük be a bootstrapbe:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Különböző környezetek
Ne habozzon, ha a Bootstrap
osztályt saját igényei szerint alakíthatja. A bootWebApplication()
metódushoz paramétereket adhat hozzá a webes projektek megkülönböztetése érdekében. Alternatívaként más metódusokat
is hozzáadhat, például a bootTestEnvironment()
a környezet inicializálásához a unit tesztekhez, a
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();
}