Vylepšit tuto stránku

Bootstrap

Bootstrap je zaváděcí kód, který inicializuje prostředí, vytvoří dependency injection (DI) kontejner a spustí aplikaci. Řekneme si:

  • jak se konfiguruje pomocí NEON souborů
  • jak rozlišit produkční a vývojářský režim
  • jak vytvořit DI kontejner

Aplikace, ať už jde o ty webové nebo skripty spouštěné z příkazové řádky, začínají svůj běh nějakou formou inicializace prostředí. V dávných dobách to míval na starosti soubor s názvem třeba include.inc.php, který prvotní soubor inkludoval. V moderních Nette aplikacích jej nahradil soubor bootstrap.php, který jakožto součást aplikace najdete v souboru app/bootstrap.php. Může vypadat kupříkladu takto:

$configurator = new Nette\Configurator;
//$configurator->setDebugMode('secret@23.75.345.200');
$configurator->enableTracy(__DIR__ . '/../log');
$configurator->setTempDirectory(__DIR__ . '/../temp');
$configurator->createRobotLoader()
	->addDirectory(__DIR__)
	->register();
$configurator->addConfig(__DIR__ . '/config/config.neon');
// vytvoření DI kontejneru
$container = $configurator->createContainer();

index.php

Prvotní soubor je v případě webových aplikací index.php, který se nachází ve veřejném adresáři www/. Ten si nechá od souboru bootstrap.php inicializovat prostředí a vrátit DI kontejner $container. Z něj získá službu Application, kterou spustí webovou aplikaci:

// inicializace prostředí + získání DI kontejneru
$container = require __DIR__ . '/../app/bootstrap.php';
// DI kontejner vytvoří objekt Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// spuštění Nette aplikace
$application->run();

Jak vidno, s nastavením prostředí a vytvořením dependency injection (DI) kontejneru pomáhá třída Nette\Configurator, kterou si nyní blíže představíme.

Vývojářský vs produkční režim

Pokud je aplikace spuštěna na localhostu, automaticky se aktivuje vývojářský režim. Jinak běží v produkčním režimu. Obvykle tedy není potřeba nic konfigurovat nebo ručně přepínat režimy pro vývoj a pro ostré nasazení.

Pokud chceme vývojářský režim povolit i v dalších případech, například programátorům přistupujícím z konkrétní IP adresy, použijeme setDebugMode():

$configurator->setDebugMode('23.75.345.200'); // lze uvést i pole IP adres

Rozhodně doporučujeme kombinovat IP adresu s cookie. Do cookie nette-debug uložíme tajný token, např. secret1234, a tímto způsobem aktivujeme vývojářský režim pro programátory přistupující z konkrétní IP adresy a zároveň mající v cookie zmíněný token:

$configurator->setDebugMode('secret1234@23.75.345.200');

Vývojářský režim můžeme také vypnout úplně, i pro localhost:

$configurator->setDebugMode(false);

Debugovací nástroj Tracy

Pro snadné debugování ještě zapneme skvělý nástroj Tracy. Ve vývojářském režimu chyby vizualizuje a v produkčním režimu chyby loguje do uvedeného adresáře:

$configurator->enableTracy(__DIR__ . '/../log');

Dočasné soubory

Nette využívá cache pro DI kontejner, RobotLoader, šablony atd. Proto je nutné nastavit cestu k adresáři, kam se bude cache ukládat:

$configurator->setTempDirectory(__DIR__ . '/../temp');

Na Linuxu nebo macOS nastavte adresářům log/ a temp/ práva pro zápis.

RobotLoader

Zpravidla budeme chtít automaticky načítat třídy pomocí RobotLoaderu, musíme ho tedy nastartovat a necháme jej načítat třídy z adresáře, kde je umístěný bootstrap.php (tj. __DIR__), a všech podadresářů:

$configurator->createRobotLoader()
	->addDirectory(__DIR__)
	->register();

Alternativní přístup je nechat třídy načítat pouze přes Composer při dodržení PSR-4.

Timezone

Přes konfigurátor můžete nastavit výchozí časovou zónu.

$configurator->setTimeZone('Europe/Prague');

Konfigurace DI kontejneru

Součástí bootovacího procesu je vytvoření DI kontejneru neboli továrny na objekty, což je srdce celé aplikace. Jde vlastně o PHP třídu, kterou vygeneruje Nette a uloží do adresáře s cache. Továrna vyrábí klíčové objekty aplikace a pomocí konfiguračních souborů jí instruujeme, jak je má vytvářet a nastavovat, čímž ovlivňujeme chování celé aplikace.

Konfigurační soubory se obvykle zapisují ve formátu NEON. V samostatné kapitole se dočtete, co vše lze konfigurovat.

Ve vývojářském režimu se kontejner automaticky aktualizuje při každé změně kódu nebo konfiguračních souborů. V produkčním režimu se vygeneruje jen jednou a změny se kvůli maximalizaci výkonu nekontrolují.

Konfigurační soubory načteme pomocí addConfig():

$configurator->addConfig(__DIR__ . '/config/config.neon');

Pokud chceme přidat více konfiguračních souborů, můžeme funkci addConfig() zavolat vícekrát.

$configurator->addConfig(__DIR__ . '/config/config.neon');
$configurator->addConfig(__DIR__ . '/config/config.local.neon');
if (PHP_SAPI === 'cli') {
	$configurator->addConfig(__DIR__ . '/config/cli.php');
}

Název cli.php není překlep, konfigurace může být zapsaná také v PHP souboru, který ji vrátí jako pole.

Také můžeme přidat další konfigurační soubory v sekci includes.

Pokud se v konfiguračních souborech objeví prvky se stejnými klíči, budou přepsány, nebo v případě polí sloučeny. Později vkládaný soubor má vyšší prioritu než předchozí. Soubor, ve kterém je sekce includes uvedena, má vyšší prioritu než v něm inkludované soubory.

Statické parametry

Parametry používané v konfiguračních souborech můžeme definovat v sekci parameters a také je předávat (či přepisovat) metodou addParameters(). Důležité je, že různé hodnoty parametrů způsobí vygenerování dalších DI kontejnerů, tedy dalších tříd.

$configurator->addParameters([
	'projectId' => 23,
]);

Na parametr projectId se lze v konfiguraci odkázat obvyklým zápisem %projectId%. Třída Configurator automaticky přidává parametry appDir, wwwDir, tempDir, debugMode a consoleMode.

Dynamické parametry

Do kontejneru můžeme přidat i dynamické parametry, jejichž různé hodnoty na rozdíl od statických parameterů nezpůsobí generování nových DI kontejnerů.

$configurator->addDynamicParameters([
	'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);

Jednoduše tak můžeme přidat např. environmentální proměnné, na které se pak lze v konfiguraci odkázat zápisem %env.variable%.

$configurator->addDynamicParameters([
	'env' => $_ENV,
]);

Importované služby

Nyní už jdeme hlouběji. Ačkoliv je smyslem DI kontejneru objekty vyrábet, výjimečně může vzniknout potřeba do kontejneru existující objekt vložit. Uděláme to tak, že službu definujeme s příznakem dynamic: true.

services:
	myservice:
		class: App\Model\MyCustomService
		dynamic: true

A v bootstrapu do kontejneru vložíme objekt:

$configurator->addServices([
	'myservice' => new App\Model\MyCustomService('foobar'),
]);