Bootstrap

Bootstrap è il codice di avvio che inizializza l'ambiente, crea un contenitore di dependency injection (DI) e avvia l'applicazione. Discuteremo di:

  • come configurare l'applicazione usando i file NEON
  • come gestire le modalità di produzione e di sviluppo
  • come creare il contenitore DI

Le applicazioni, siano esse basate sul web o su script a riga di comando, iniziano con una qualche forma di inizializzazione dell'ambiente. In tempi antichi, poteva essere un file chiamato include.inc.php a occuparsene, incluso nel file iniziale. Nelle moderne applicazioni Nette, è stato sostituito dalla classe Bootstrap, che come parte dell'applicazione si trova nel file app/Bootstrap.php. Ad esempio, potrebbe avere questo aspetto:

use Nette\Bootstrap\Configurator;

class Bootstrap
{
	private Configurator $configurator;
	private string $rootDir;

	public function __construct()
	{
		$this->rootDir = dirname(__DIR__);
		// Il configuratore è responsabile dell'impostazione dell'ambiente applicativo e dei servizi.
		$this->configurator = new Configurator;
		// Impostare la directory per i file temporanei generati da Nette (ad esempio, i modelli compilati).
		$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 è intelligente e la modalità di sviluppo si attiva automaticamente,
		// oppure si può attivare per un indirizzo IP specifico decommentando la seguente riga:
		// $this->configurator->setDebugMode('secret@23.75.345.200');

		// Abilita Tracy: lo strumento di debug per eccellenza, il "coltellino svizzero".
		$this->configurator->enableTracy($this->rootDir . '/log');

		// RobotLoader: carica automaticamente tutte le classi nella cartella data
		$this->configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();
	}

	private function setupContainer(): void
	{
		// Carica i file di configurazione
		$this->configurator->addConfig($this->rootDir . '/config/common.neon');
	}
}

index.php

Il file iniziale per le applicazioni web è index.php, situato nella cartella pubblica www/. Utilizza la classe Bootstrap per inizializzare l'ambiente e creare un contenitore DI. Quindi, ottiene il servizio Application dal contenitore, che lancia l'applicazione web:

$bootstrap = new App\Bootstrap;
// Inizializzare l'ambiente + creare un contenitore DI
$container = $bootstrap->bootWebApplication();
// Il contenitore DI crea un oggetto NetteApplicationApplication
$application = $container->getByType(Nette\Application\Application::class);
// Avviare l'applicazione Nette e gestire la richiesta in arrivo
$application->run();

Come si può notare, la classe Nette\Bootstrap\Configurator, che ora presenteremo in modo più dettagliato, aiuta a impostare l'ambiente e a creare un contenitore di dependency injection (DI).

Modalità di sviluppo e modalità di produzione

Nette distingue due modalità di base per l'esecuzione di una richiesta: sviluppo e produzione. La modalità di sviluppo è incentrata sul massimo comfort del programmatore, Tracy viene visualizzato, la cache viene aggiornata automaticamente quando si modificano i template o la configurazione del contenitore DI, ecc. La modalità di produzione è incentrata sulle prestazioni, Tracy registra solo gli errori e le modifiche dei modelli e di altri file non vengono controllate.

La selezione della modalità avviene tramite il rilevamento automatico, quindi di solito non è necessario configurare o cambiare qualcosa manualmente. La modalità è di sviluppo se l'applicazione è in esecuzione su localhost (cioè l'indirizzo IP 127.0.0.1 o ::1) e non è presente alcun proxy (cioè la sua intestazione HTTP). Altrimenti, viene eseguita in modalità di produzione.

Se si vuole abilitare la modalità di sviluppo in altri casi, ad esempio per i programmatori che accedono da un indirizzo IP specifico, si può usare setDebugMode():

$this->configurator->setDebugMode('23.75.345.200'); // uno o più indirizzi IP

Consigliamo assolutamente di combinare un indirizzo IP con un cookie. Nel cookie nette-debug verrà memorizzato un token segreto, ad esempio secret1234, e la modalità di sviluppo verrà attivata per i programmatori con questa combinazione di IP e cookie.

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

Possiamo anche disattivare completamente la modalità sviluppatore, anche per localhost:

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

Si noti che il valore true attiva la modalità sviluppatore, cosa che non dovrebbe mai accadere su un server di produzione.

Strumento di debug Tracy

Per facilitare il debug, attiviamo l'ottimo strumento Tracy. In modalità sviluppatore visualizza gli errori e in modalità produzione li registra nella directory specificata:

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

File temporanei

Nette utilizza la cache per il contenitore DI, il RobotLoader, i modelli, ecc. Per questo motivo è necessario impostare il percorso della cartella in cui verrà memorizzata la cache:

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

Su Linux o macOS, impostare i permessi di scrittura per le directory log/ e temp/.

RobotLoader

Di solito, vogliamo caricare automaticamente le classi usando RobotLoader, quindi dobbiamo avviarlo e fargli caricare le classi dalla directory in cui si trova Bootstrap.php (cioè __DIR__) e da tutte le sue sottodirectory:

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

Un modo alternativo è quello di utilizzare solo il caricamento automatico di Composer PSR-4.

Fuso orario

Il configuratore consente di specificare un fuso orario per l'applicazione.

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

Configurazione del contenitore DI

Parte del processo di avvio è la creazione di un contenitore DI, cioè una fabbrica di oggetti, che è il cuore dell'intera applicazione. Si tratta in realtà di una classe PHP generata da Nette e memorizzata in una cartella cache. Il factory produce gli oggetti chiave dell'applicazione e i file di configurazione gli indicano come crearli e configurarli, influenzando così il comportamento dell'intera applicazione.

I file di configurazione sono solitamente scritti nel formato NEON. Qui si può leggere cosa si può configurare.

In modalità di sviluppo, il contenitore viene aggiornato automaticamente ogni volta che si modifica il codice o i file di configurazione. In modalità di produzione, viene generato solo una volta e le modifiche ai file non vengono controllate per massimizzare le prestazioni.

I file di configurazione vengono caricati usando addConfig():

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

Il metodo addConfig() può essere richiamato più volte per aggiungere più file.

$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');
}

Il nome cli.php non è un refuso, la configurazione può anche essere scritta in un file PHP, che la restituisce come array.

In alternativa, si può usare la sezioneincludes per caricare altri file di configurazione.

Se all'interno dei file di configurazione compaiono elementi con le stesse chiavi, questi verranno sovrascritti o uniti nel caso di array. Il file incluso successivamente ha una priorità maggiore rispetto al precedente. Il file in cui è elencata la sezione includes ha una priorità più alta dei file in esso inclusi.

Parametri statici

I parametri usati nei file di configurazione possono essere definiti nella sezione parameters e anche passati (o sovrascritti) dal metodo addStaticParameters() (ha l'alias addParameters()). È importante che valori diversi dei parametri causino la generazione di contenitori DI aggiuntivi, cioè di classi aggiuntive.

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

Nei file di configurazione, possiamo scrivere la solita notazione %projectId% per accedere al parametro chiamato projectId.

Parametri dinamici

Possiamo anche aggiungere parametri dinamici al contenitore; i loro diversi valori, a differenza dei parametri statici, non causeranno la generazione di nuovi contenitori DI.

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

Le variabili d'ambiente possono essere facilmente rese disponibili usando parametri dinamici. Possiamo accedervi tramite %env.variable% nei file di configurazione.

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

Parametri predefiniti

È possibile utilizzare i seguenti parametri statici nei file di configurazione:

  • %appDir% è il percorso assoluto della directory del file Bootstrap.php
  • %wwwDir% è il percorso assoluto della directory contenente il file di ingresso index.php
  • %tempDir% è il percorso assoluto della directory per i file temporanei
  • %vendorDir% è il percorso assoluto della directory in cui Composer installa le librerie
  • %rootDir% è il percorso assoluto della directory principale del progetto
  • %debugMode% indica se l'applicazione è in modalità debug
  • %consoleMode% indica se la richiesta è arrivata attraverso la riga di comando

Servizi importati

Ora stiamo andando più a fondo. Sebbene lo scopo di un contenitore DI sia quello di creare oggetti, eccezionalmente può essere necessario inserire un oggetto esistente nel contenitore. Lo facciamo definendo il servizio con l'attributo imported: true.

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

Creare una nuova istanza e inserirla in bootstrap:

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

Ambienti diversi

Non esitate a personalizzare la classe Bootstrap in base alle vostre esigenze. Si possono aggiungere parametri al metodo bootWebApplication() per differenziare i progetti web. In alternativa, si possono aggiungere altri metodi, come bootTestEnvironment() per inizializzare l'ambiente per i test unitari, bootConsoleApplication() per gli script chiamati dalla riga di comando e così via.

public function bootTestEnvironment(): Nette\DI\Container
{
	Tester\Environment::setup(); // Inizializzazione del tester Nette
	$this->setupContainer();
	return $this->configurator->createContainer();
}

public function bootConsoleApplication(): Nette\DI\Container
{
	$this->configurator->setDebugMode(false);
	$this->initializeEnvironment();
	$this->setupContainer();
	return $this->configurator->createContainer();
}
versione: 4.0