Bootstrap

Bootstrap je zagonska koda, ki inicializira okolje, ustvari vsebnik za vbrizgavanje odvisnosti (DI) in zažene aplikacijo. Obravnavali bomo:

  • kako konfigurirati aplikacijo z datotekami NEON
  • kako ravnati s produkcijskim in razvojnim načinom
  • kako ustvariti vsebnik DI

Aplikacije, ne glede na to, ali temeljijo na spletu ali skripti ukazne vrstice, se začnejo z določeno obliko inicializacije okolja. V starih časih je bila za to lahko odgovorna datoteka z imenom npr. include.inc.php, ki je bila vključena v začetno datoteko. V sodobnih aplikacijah Nette jo je nadomestil razred Bootstrap, ki se kot del aplikacije nahaja v datoteki app/Bootstrap.php. Izgleda lahko 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;
		// Nastavite imenik za začasne datoteke, ki jih ustvari Nette (npr. sestavljene 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
	{
		// Program Nette je pameten in razvojni način se vklopi samodejno,
		// lahko pa ga za določen naslov IP omogočite tako, da odkomentirate naslednjo vrstico:
		// $this->configurator->setDebugMode('secret@23.75.345.200');

		// Omogoči Tracy: najboljše orodje za razhroščevanje "švicarskega noža".
		$this->configurator->enableTracy($this->rootDir . '/log');

		// RobotLoader: samodejno naloži vse razrede v danem imeniku
		$this->configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();
	}

	private function setupContainer(): void
	{
		// Nalaganje konfiguracijskih datotek
		$this->configurator->addConfig($this->rootDir . '/config/common.neon');
	}
}

index.php

Začetna datoteka za spletne aplikacije je index.php, ki se nahaja v javnem imeniku www/. Uporablja razred Bootstrap za inicializacijo okolja in ustvarjanje vsebnika DI. Nato iz vsebnika pridobi storitev Application, ki zažene spletno aplikacijo:

$bootstrap = new App\Bootstrap;
// Inicializacija okolja + ustvarjanje vsebnika DI
$container = $bootstrap->bootWebApplication();
// vsebnik DI ustvari objekt Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Zagnati aplikacijo Nette in obdelati vhodno zahtevo
$application->run();

Kot vidite, razred Nette\Bootstrap\Configurator, ki ga bomo zdaj podrobneje predstavili, pomaga pri vzpostavljanju okolja in ustvarjanju vsebnika za vbrizgavanje odvisnosti (DI).

Razvojni in produkcijski način

Nette se obnaša različno, odvisno od tega, ali deluje v razvojnem ali produkcijskem strežniku:

🛠️ Razvojni način
Prikaže Tracyjev razhroščevalni niz z uporabnimi informacijami (npr. poizvedbe SQL, čas izvajanja, poraba pomnilnika).
Prikaže podrobno stran z napakami s sledmi klicev funkcij in vsebino spremenljivk, ko pride do napake.
Samodejno osveži predpomnilnik, ko se spremenijo predloge Latte, konfiguracijske datoteke itd.
🚀 Produkcijski način
Ne prikaže nobenih informacij o odpravljanju napak; vse napake se zabeležijo.
Prikaže stran ErrorPresenter ali splošno stran “Server Error” (Napaka strežnika), ko pride do napake.
Predpomnilnik se nikoli samodejno ne osveži!
Optimizirano za hitrost in varnost.

Način se določi samodejno, zato ga v večini primerov ni treba ročno konfigurirati ali preklapljati:

  • Razvojni način: (IP naslov 127.0.0.1 ali ::1), razen če je v uporabi posrednik (tj. na podlagi glave HTTP).
  • Produkcijski način: Aktivno povsod drugje.

Če želite omogočiti razvojni način v drugih primerih, na primer za programerje, ki dostopajo z določenega naslova IP, lahko uporabite setDebugMode():

$this->configurator->setDebugMode('23.75.345.200'); // enega ali več naslovov IP.

Vsekakor priporočamo kombinacijo naslova IP s piškotkom. V piškotek nette-debug bomo shranili tajni žeton, npr. secret1234, razvojni način pa bo aktiviran za programerje s to kombinacijo IP in piškotka.

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

Razvojni način lahko tudi popolnoma izklopimo, tudi za lokalni gostitelj:

$this->configurator->setDebugMode(false);

Vrednost true vklopi način za razvijalce, kar se na produkcijskem strežniku ne bi smelo zgoditi.

Orodje za razhroščevanje Tracy

Za lažje razhroščevanje bomo vklopili odlično orodje Tracy. V načinu za razvijalce vizualizira napake, v produkcijskem načinu pa napake beleži v določen imenik:

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

Začasne datoteke

Nette uporablja predpomnilnik za vsebnik DI, RobotLoader, predloge itd. Zato je treba nastaviti pot do imenika, v katerem bo shranjen predpomnilnik:

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

V operacijskem sistemu Linux ali macOS nastavite dovoljenja za pisanje za imenike log/ in temp/.

RobotLoader

Običajno bomo želeli samodejno naložiti razrede z RobotLoaderjem, zato ga moramo zagnati in mu omogočiti, da naloži razrede iz imenika, kjer se nahaja Bootstrap.php (tj. __DIR__), in vseh njegovih podimenikov:

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

Druga možnost je, da uporabimo samo samodejno nalaganje Composer PSR-4.

Časovni pas

Configurator vam omogoča, da določite časovni pas za svojo aplikacijo.

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

Konfiguracija zabojnika DI

Del zagonskega postopka je ustvarjanje vsebnika DI, tj. tovarne za predmete, ki je srce celotne aplikacije. To je pravzaprav razred PHP, ki ga ustvari Nette in je shranjen v imeniku predpomnilnika. Tovarna izdeluje ključne objekte aplikacije, konfiguracijske datoteke pa ji dajejo navodila, kako naj jih ustvari in konfigurira, s čimer vplivamo na obnašanje celotne aplikacije.

Konfiguracijske datoteke so običajno zapisane v formatu NEON. Kaj vse je mogoče konfigurirati, si lahko preberete tukaj.

V razvojnem načinu se vsebnik samodejno posodobi vsakič, ko spremenite kodo ali konfiguracijske datoteke. V produkcijskem načinu se ustvari samo enkrat, spremembe datotek pa se ne preverjajo, da bi povečali zmogljivost.

Konfiguracijske datoteke se naložijo z uporabo addConfig():

$this->configurator->addConfig($this->rootDir . '/config/common.neon');

Metodo addConfig() lahko za dodajanje več datotek pokličete 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 tiskarska napaka, konfiguracijo lahko zapišete tudi v datoteko PHP, ki jo vrne kot polje.

Druga možnost je, da z razdelkomincludes naložimo več konfiguracijskih datotek.

Če se v konfiguracijskih datotekah pojavijo elementi z enakimi ključi, se bodo prepisali ali združili v primeru polj. Kasneje vključena datoteka ima višjo prioriteto kot prejšnja. Datoteka, v kateri je naveden razdelek includes, ima višjo prednost kot datoteke, ki so vanjo vključene.

Statični parametri

Parametre, ki se uporabljajo v konfiguracijskih datotekah, je mogoče opredeliti v razdelku parameters in jih tudi posredovati (ali prepisati) z metodo addStaticParameters() (ima vzdevek addParameters()). Pomembno je, da različne vrednosti parametrov povzročijo generiranje dodatnih vsebnikov DI, tj. dodatnih razredov.

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

V konfiguracijskih datotekah lahko zapišemo običajni zapis %projectId% za dostop do parametra z imenom projectId.

Dinamični parametri

Kontejnerju lahko dodamo tudi dinamične parametre, katerih različne vrednosti za razliko od statičnih parametrov ne bodo povzročile generiranja novih DI kontejnerjev.

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

Spremenljivke okolja bi lahko preprosto dali na voljo z dinamičnimi parametri. Do njih lahko dostopamo prek spletne strani %env.variable% v konfiguracijskih datotekah.

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

Privzete parametre

V konfiguracijskih datotekah lahko uporabite naslednje statične parametre:

  • %appDir% je absolutna pot do imenika datoteke Bootstrap.php.
  • %wwwDir% je absolutna pot do imenika, ki vsebuje vstopno datoteko index.php
  • %tempDir% je absolutna pot do imenika za začasne datoteke
  • %vendorDir% je absolutna pot do imenika, v katerega Composer namesti knjižnice
  • %rootDir% je absolutna pot do korenskega imenika projekta
  • %debugMode% označuje, ali je aplikacija v načinu odpravljanja napak
  • %consoleMode% označuje, ali je bila zahteva poslana prek ukazne vrstice

Uvožene storitve

Zdaj se bomo poglobili. Čeprav je namen vsebnika DI ustvarjanje objektov, se lahko izjemoma pojavi potreba po vstavitvi obstoječega objekta v vsebnik. To storimo tako, da definiramo storitev z atributom imported: true.

services:
	myservice:
		type: App\Model\MyCustomService
		imported: true

Ustvarite nov primerek in ga vstavite v bootstrap:

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

Različna okolja

Ne oklevajte, če želite razred Bootstrap prilagoditi svojim potrebam. Metodi bootWebApplication() lahko dodate parametre za razlikovanje med spletnimi projekti. Lahko pa dodate tudi druge metode, na primer bootTestEnvironment() za inicializacijo okolja za teste enote, bootConsoleApplication() za skripte, ki se kličejo iz ukazne vrstice, in tako naprej.

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();
}
različica: 4.0