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 a Bootstrap.php fájlt tartalmazó könyvtárhoz
  • %wwwDir% az abszolút elérési út a index.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();
}
verzió: 4.0