Nette Documentation Preview

syntax
Bootstrap
*********

<div class=perex>

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

</div>


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:

```php
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 .[#toc-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:

```php
$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 [api: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 .[#toc-development-vs-production-mode]
=====================================================================

Nette razlikuje med dvema osnovnima načinoma izvajanja zahtevka: razvojnim in produkcijskim. Razvojni način je osredotočen na čim večje udobje programerja, prikazan je Tracy, predpomnilnik se samodejno posodablja ob spreminjanju predlog ali konfiguracije vsebnika DI itd. Produkcijski način je osredotočen na zmogljivost, Tracy beleži le napake, spremembe predlog in drugih datotek pa se ne preverjajo.

Izbira načina poteka s samodejnim zaznavanjem, zato običajno ni treba ničesar ročno konfigurirati ali preklapljati. Način je razvojni, če aplikacija teče na lokalnem gostitelju (tj. naslov IP `127.0.0.1` ali `::1`) in ni prisoten posrednik (tj. njegova glavička HTTP). V nasprotnem primeru deluje v produkcijskem načinu.

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

```php
$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.

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

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

```php
$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 .[#toc-debugging-tool-tracy]
===========================================================

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

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


Začasne datoteke .[#toc-temporary-files]
========================================

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

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

V operacijskem sistemu Linux ali macOS nastavite [dovoljenja za pisanje za |nette:troubleshooting#Setting directory permissions] imenike `log/` in `temp/`.


RobotLoader .[#toc-robotloader]
===============================

Običajno bomo želeli samodejno naložiti razrede z [RobotLoaderjem |robot-loader:], 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:

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

Druga možnost je, da uporabimo samo samodejno nalaganje [Composer |best-practices:composer] PSR-4.


Časovni pas .[#toc-timezone]
============================

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

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


Konfiguracija zabojnika DI .[#toc-di-container-configuration]
=============================================================

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 |neon:format]. [Kaj vse je mogoče konfigurirati |nette:configuring], si lahko preberete [tukaj |nette:configuring].

.[tip]
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()`:

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

Metodo `addConfig()` lahko za dodajanje več datotek pokličete večkrat.

```php
$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 [razdelkom`includes`  |dependency-injection:configuration#including files] naložimo več konfiguracijskih datotek.

Če se v konfiguracijskih datotekah pojavijo elementi z enakimi ključi, se bodo [prepisali ali združili |dependency-injection:configuration#Merging] 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 .[#toc-static-parameters]
--------------------------------------------

Parametre, ki se uporabljajo v konfiguracijskih datotekah, je mogoče opredeliti [v razdelku `parameters` |dependency-injection:configuration#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.

```php
$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 .[#toc-dynamic-parameters]
----------------------------------------------

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.

```php
$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.

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


Privzete parametre .[#toc-default-parameters]
---------------------------------------------

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 .[#toc-imported-services]
------------------------------------------

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`.

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

Ustvarite nov primerek in ga vstavite v bootstrap:

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


Različna okolja .[#toc-different-environments]
==============================================

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.

```php
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();
}
```

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 razlikuje med dvema osnovnima načinoma izvajanja zahtevka: razvojnim in produkcijskim. Razvojni način je osredotočen na čim večje udobje programerja, prikazan je Tracy, predpomnilnik se samodejno posodablja ob spreminjanju predlog ali konfiguracije vsebnika DI itd. Produkcijski način je osredotočen na zmogljivost, Tracy beleži le napake, spremembe predlog in drugih datotek pa se ne preverjajo.

Izbira načina poteka s samodejnim zaznavanjem, zato običajno ni treba ničesar ročno konfigurirati ali preklapljati. Način je razvojni, če aplikacija teče na lokalnem gostitelju (tj. naslov IP 127.0.0.1 ali ::1) in ni prisoten posrednik (tj. njegova glavička HTTP). V nasprotnem primeru deluje v produkcijskem načinu.

Č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();
}