Bootstrap
Bootstrap je zagonska koda, ki inicializira okolje, ustvari dependency injection (DI) vsebnik in zažene aplikacijo. Povedali si bomo:
- kako se konfigurira s pomočjo NEON datotek
- kako razlikovati produkcijski in razvojni način
- kako ustvariti DI vsebnik
Aplikacije, bodisi spletne ali skripti, zagnani iz ukazne vrstice, začnejo svoje delovanje z neko obliko inicializacije
okolja. V davnih časih je za to skrbel datoteka z imenom, na primer include.inc.php
, ki jo je prvotna datoteka
vključila. V sodobnih Nette aplikacijah jo je nadomestil razred Bootstrap
, ki ga kot del aplikacije najdete
v datoteki app/Bootstrap.php
. Lahko izgleda na primer takole:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
private Configurator $configurator;
private string $rootDir;
public function __construct()
{
$this->rootDir = dirname(__DIR__);
// Konfigurator je odgovoren za nastavitev okolja aplikacije in storitev.
$this->configurator = new Configurator;
// Nastavi mapo za začasne datoteke, ki jih generira Nette (npr. prevedene predloge)
$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 je pameten in razvojni način se vklopi samodejno,
// ali pa ga lahko omogočite za določen IP naslov z odkomentiranjem naslednje vrstice:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Aktivira Tracy: ultimativni "švicarski nož" za razhroščevanje.
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: samodejno naloži vse razrede v izbrani mapi
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Naloži konfiguracijske datoteke
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
Prvotna datoteka je v primeru spletnih aplikacij index.php
, ki se nahaja v javni mapi www/
. Ta si
pusti od razreda Bootstrap inicializirati okolje in izdelati DI vsebnik. Nato iz njega pridobi storitev Application
,
ki zažene spletno aplikacijo:
$bootstrap = new App\Bootstrap;
// Inicializacija okolja + ustvarjanje DI vsebnika
$container = $bootstrap->bootWebApplication();
// DI vsebnik ustvari objekt Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Zagon aplikacije Nette in obdelava dohodnega zahtevka
$application->run();
Kot je vidno, pri nastavitvi okolja in ustvarjanju dependency injection (DI) vsebnika pomaga razred Nette\Bootstrap\Configurator, ki si ga bomo zdaj podrobneje predstavili.
Razvojni vs produkcijski način
Nette se obnaša različno glede na to, ali teče na razvojnem ali produkcijskem strežniku:
- 🛠️ Razvojni način (Development)
- Prikazuje Tracy debugbar z uporabnimi informacijami (SQL poizvedbe, čas izvajanja, uporabljeni pomnilnik)
- Ob napaki prikaže podrobno stran z napako s klici funkcij in vsebino spremenljivk
- Samodejno obnavlja predpomnilnik ob spremembi Latte predlog, urejanju konfiguracijskih datotek itd.
- 🚀 Produkcijski način (Production)
- Ne prikazuje nobenih informacij za razhroščevanje, vse napake zapisuje v dnevnik
- Ob napaki prikaže ErrorPresenter ali splošno stran “Server Error”
- Predpomnilnik se nikoli samodejno ne obnavlja!
- Optimiziran za hitrost in varnost
Izbira načina se izvaja s samodejnim zaznavanjem, zato običajno ni treba ničesar konfigurirati ali ročno preklapljati:
- razvojni način: na localhostu (IP naslov
127.0.0.1
ali::1
) če ni prisoten proxy (tj. njegova HTTP glava) - produkcijski način: povsod drugje
Če želimo razvojni način omogočiti tudi v drugih primerih, na primer programerjem, ki dostopajo z določenega IP naslova,
uporabimo setDebugMode()
:
$this->configurator->setDebugMode('23.75.345.200'); // lahko navedemo tudi polje IP naslovov
Vsekakor priporočamo kombiniranje IP naslova s piškotkom. V piškotek nette-debug
shranimo skrivni žeton,
npr. secret1234
, in na ta način aktiviramo razvojni način za programerje, ki dostopajo z določenega IP naslova in
imajo hkrati v piškotku omenjeni žeton:
$this->configurator->setDebugMode('secret1234@23.75.345.200');
Razvojni način lahko tudi popolnoma izklopimo, tudi za localhost:
$this->configurator->setDebugMode(false);
Pozor, vrednost true
vklopi razvojni način na trdo, kar se nikoli ne sme zgoditi na produkcijskem strežniku.
Orodje za razhroščevanje Tracy
Za enostavno razhroščevanje še vklopimo odlično orodje Tracy. V razvojnem načinu vizualizira napake in v produkcijskem načinu napake beleži v navedeno mapo:
$this->configurator->enableTracy($this->rootDir . '/log');
Začasne datoteke
Nette uporablja predpomnilnik za DI vsebnik, RobotLoader, predloge itd. Zato je treba nastaviti pot do mape, kamor se bo predpomnilnik shranjeval:
$this->configurator->setTempDirectory($this->rootDir . '/temp');
Na Linuxu ali macOS nastavite mapama log/
in temp/
pravice za pisanje.
RobotLoader
Praviloma bomo želeli samodejno nalagati razrede s pomočjo RobotLoaderja, zato ga moramo zagnati in mu pustiti, da nalaga razrede iz mape,
kjer se nahaja Bootstrap.php
(tj. __DIR__
), in vseh podmap:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Alternativni pristop je, da pustimo razrede nalagati samo prek Composerja ob upoštevanju PSR-4.
Časovni pas
Prek konfiguratorja lahko nastavite privzeti časovni pas.
$this->configurator->setTimeZone('Europe/Prague');
Konfiguracija DI vsebnika
Del zagonskega procesa je ustvarjanje DI vsebnika ali tovarne objektov, kar je srce celotne aplikacije. Gre pravzaprav za PHP razred, ki ga Nette generira in shrani v mapo s predpomnilnikom. Tovarna izdeluje ključne objekte aplikacije in s pomočjo konfiguracijskih datotek ji naročamo, kako naj jih ustvarja in nastavlja, s čimer vplivamo na obnašanje celotne aplikacije.
Konfiguracijske datoteke se običajno zapisujejo v formatu NEON. V ločenem poglavju boste izvedeli, kaj vse je mogoče konfigurirati.
V razvojnem načinu se vsebnik samodejno posodablja ob vsaki spremembi kode ali konfiguracijskih datotek. V produkcijskem načinu se generira samo enkrat in spremembe se zaradi maksimizacije zmogljivosti ne preverjajo.
Konfiguracijske datoteke naložimo s pomočjo addConfig()
:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
Če želimo dodati več konfiguracijskih datotek, lahko funkcijo addConfig()
pokličemo večkrat.
$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');
}
Ime cli.php
ni napaka, konfiguracija je lahko zapisana tudi v PHP datoteki, ki jo vrne kot polje.
Prav tako lahko dodamo druge konfiguracijske datoteke v odsek includes
.
Če se v konfiguracijskih datotekah pojavijo elementi z enakimi ključi, bodo prepisani ali v primeru polj združeni. Kasneje vključena datoteka
ima višjo prioriteto kot prejšnja. Datoteka, v kateri je naveden odsek includes
, ima višjo prioriteto kot v njej
vključene datoteke.
Statični parametri
Parametre, uporabljene v konfiguracijskih datotekah, lahko definiramo v odseku parameters
in jih tudi
posredujemo (ali prepišemo) z metodo addStaticParameters()
(ima alias addParameters()
). Pomembno je,
da različne vrednosti parametrov povzročijo generiranje dodatnih DI vsebnikov, torej dodatnih razredov.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
Na parameter projectId
se lahko v konfiguraciji sklicujemo z običajnim zapisom %projectId%
.
Dinamični parametri
V vsebnik lahko dodamo tudi dinamične parametre, katerih različne vrednosti za razliko od statičnih parametrov ne povzročijo generiranja novih DI vsebnikov.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
Preprosto lahko tako dodamo npr. okoljske spremenljivke, na katere se nato lahko v konfiguraciji sklicujemo z zapisom
%env.variable%
.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Privzeti parametri
V konfiguracijskih datotekah lahko uporabite te statične parametre:
%appDir%
je absolutna pot do mape z datotekoBootstrap.php
%wwwDir%
je absolutna pot do mape z vhodno datotekoindex.php
%tempDir%
je absolutna pot do mape za začasne datoteke%vendorDir%
je absolutna pot do mape, kamor Composer namešča knjižnice%rootDir%
je absolutna pot do korenskega direktorija projekta%debugMode%
označuje, ali je aplikacija v načinu za razhroščevanje%consoleMode%
označuje, ali je zahtevek prišel prek ukazne vrstice
Uvožene storitve
Zdaj gremo globlje. Čeprav je smisel DI vsebnika izdelovati objekte, lahko izjemoma nastane potreba, da v vsebnik vstavimo
obstoječi objekt. To storimo tako, da storitev definiramo z zastavico imported: true
.
services:
myservice:
type: App\Model\MyCustomService
imported: true
In v bootstrapu v vsebnik vstavimo objekt:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Različna okolja
Ne bojte se prilagoditi razreda Bootstrap svojim potrebam. Metodi bootWebApplication()
lahko dodate parametre za
razlikovanje spletnih projektov. Ali pa lahko dopolnimo druge metode, na primer bootTestEnvironment()
, ki
inicializira okolje za enotne teste, bootConsoleApplication()
za skripte, klicane iz ukazne vrstice itd.
public function bootTestEnvironment(): Nette\DI\Container
{
Tester\Environment::setup(); // inicializacija Nette Testerja
$this->setupContainer();
return $this->configurator->createContainer();
}
public function bootConsoleApplication(): Nette\DI\Container
{
$this->configurator->setDebugMode(false);
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}