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
{
public static function boot(): Configurator
{
$appDir = dirname(__DIR__);
$configurator = new Configurator;
//$configurator->setDebugMode('secret@23.75.345.200');
$configurator->enableTracy($appDir . '/log');
$configurator->setTempDirectory($appDir . '/temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
$configurator->addConfig($appDir . '/config/common.neon');
return $configurator;
}
}
index.php
Nel caso delle applicazioni web, il file iniziale è index.php
, che si trova nella cartella pubblica
www/
. Permette alla classe Bootstrap
di inizializzare l'ambiente e restituisce la classe
$configurator
che crea il contenitore DI. Quindi ottiene il servizio Application
, che esegue
l'applicazione web:
// inizializzare l'ambiente + ottenere l'oggetto Configuratore
$configurator = App\Bootstrap::boot();
// creare un contenitore DI
$container = $configurator->createContainer();
// Il contenitore DI crea un oggetto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// avvia l'applicazione Nette
$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()
:
$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.
$configurator->setDebugMode('secret1234@23.75.345.200');
Possiamo anche disattivare completamente la modalità sviluppatore, anche per localhost:
$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:
$configurator->enableTracy($appDir . '/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:
$configurator->setTempDirectory($appDir . '/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:
$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.
$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()
:
$configurator->addConfig($appDir . '/config/common.neon');
Il metodo addConfig()
può essere richiamato più volte per aggiungere più file.
$configurator->addConfig($appDir . '/config/common.neon');
$configurator->addConfig($appDir . '/config/local.neon');
if (PHP_SAPI === 'cli') {
$configurator->addConfig($appDir . '/config/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.
$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.
$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.
$configurator->addDynamicParameters([
'env' => getenv(),
]);
Parametri predefiniti
È possibile utilizzare i seguenti parametri statici nei file di configurazione:
%appDir%
è il percorso assoluto della directory del fileBootstrap.php
%wwwDir%
è il percorso assoluto della directory contenente il file di ingressoindex.php
%tempDir%
è il percorso assoluto della directory per i file temporanei%vendorDir%
è il percorso assoluto della directory in cui Composer installa le librerie%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:
$configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Ambienti diversi
Sentitevi liberi di personalizzare la classe Bootstrap
in base alle vostre esigenze. Si possono aggiungere
parametri al metodo boot()
per differenziare i progetti web, oppure aggiungere altri metodi, come
bootForTests()
, che inizializza l'ambiente per i test unitari, bootForCli()
per gli script chiamati
dalla riga di comando e così via.
public static function bootForTests(): Configurator
{
$configurator = self::boot();
Tester\Environment::setup(); // Nette Tester initialization
return $configurator;
}