Bootstrap
Bootstrap es el código de arranque que inicializa el entorno, crea un contenedor de inyección de dependencias (DI) e inicia la aplicación. Vamos a discutir:
- cómo configurar su aplicación utilizando archivos NEON
- cómo manejar los modos de producción y desarrollo
- cómo crear el contenedor DI
Las aplicaciones, ya sean basadas en web o en scripts de línea de comandos, comienzan por algún tipo de inicialización del
entorno. En la antigüedad, podía ser un archivo llamado por ejemplo include.inc.php
el que se encargaba de esto, y
se incluía en el archivo inicial. En las aplicaciones Nette modernas, ha sido sustituido por la clase Bootstrap
, que
como parte de la aplicación se puede encontrar en el app/Bootstrap.php
. Por ejemplo, podría tener este aspecto:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
public static function boot(): Configurator
{
$rootDir = dirname(__DIR__);
$configurator = new Configurator;
//$configurator->setDebugMode('secret@23.75.345.200');
$configurator->enableTracy($rootDir . '/log');
$configurator->setTempDirectory($rootDir . '/temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
$configurator->addConfig($rootDir . '/config/common.neon');
return $configurator;
}
}
index.php
En el caso de las aplicaciones web, el archivo inicial es index.php
, que se encuentra en el directorio público
www/
. Permite a la clase Bootstrap
inicializar el entorno y devolver el $configurator
que
crea el contenedor DI. Luego obtiene el servicio Application
, que ejecuta la aplicación web:
// initialize the environment + get Configurator object
$configurator = App\Bootstrap::boot();
// create a DI container
$container = $configurator->createContainer();
// DI container creates a Nette\Application\Application object
$application = $container->getByType(Nette\Application\Application::class);
// start Nette application
$application->run();
Como puedes ver, la clase Nette\Bootstrap\Configurator, que ahora presentaremos con más detalle, ayuda a configurar el entorno y a crear un contenedor de inyección de dependencias (DI).
Modo Desarrollo vs Producción
Nette distingue entre dos modos básicos en los que se ejecuta una petición: desarrollo y producción. El modo de desarrollo está enfocado a la máxima comodidad del programador, se visualiza Tracy, la caché se actualiza automáticamente al cambiar las plantillas o la configuración del contenedor DI, etc. El modo de producción está enfocado al rendimiento, Tracy sólo registra los errores y no se comprueban los cambios de plantillas y otros ficheros.
La selección del modo se hace por autodetección, por lo que normalmente no hay necesidad de configurar o cambiar nada
manualmente. El modo es desarrollo si la aplicación se ejecuta en localhost (es decir, la dirección IP 127.0.0.1
o
::1
) y no hay proxy presente (es decir, su cabecera HTTP). De lo contrario, se ejecuta en modo de producción.
Si desea habilitar el modo de desarrollo en otros casos, por ejemplo, para los programadores que acceden desde una dirección
IP específica, puede utilizar setDebugMode()
:
$configurator->setDebugMode('23.75.345.200'); // one or more IP addresses
Recomendamos encarecidamente combinar una dirección IP con una cookie. Almacenaremos un token secreto en la cookie
nette-debug
, por ejemplo secret1234
, y el modo de desarrollo se activará para los programadores con
esta combinación de IP y cookie.
$configurator->setDebugMode('secret1234@23.75.345.200');
También podemos desactivar completamente el modo de desarrollo, incluso para localhost:
$configurator->setDebugMode(false);
Nótese que el valor true
activa el modo desarrollador por fuerza, lo que nunca debería ocurrir en un servidor de
producción.
Herramienta de depuración Tracy
Para facilitar la depuración, activaremos la gran herramienta Tracy. En modo desarrollador visualiza los errores y en modo producción los registra en el directorio especificado:
$configurator->enableTracy($rootDir . '/log');
Archivos temporales
Nette utiliza la caché para el contenedor DI, RobotLoader, plantillas, etc. Por lo tanto es necesario establecer la ruta al directorio donde se almacenará la caché:
$configurator->setTempDirectory($rootDir . '/temp');
En Linux o macOS, establezca los permisos
de escritura para los directorios log/
y temp/
.
RobotLoader
Normalmente, querremos cargar automáticamente las clases usando RobotLoader, así que tenemos que iniciarlo y dejar que cargue las clases desde
el directorio donde se encuentra Bootstrap.php
(es decir, __DIR__
) y todos sus subdirectorios:
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Una forma alternativa es utilizar únicamente la carga automática de Composer PSR-4.
Zona horaria
Configurator le permite especificar una zona horaria para su aplicación.
$configurator->setTimeZone('Europe/Prague');
Configuración del Contenedor DI
Parte del proceso de arranque es la creación de un contenedor DI, es decir, una fábrica de objetos, que es el corazón de toda la aplicación. En realidad es una clase PHP generada por Nette y almacenada en un directorio caché. La fábrica produce objetos clave de la aplicación y los archivos de configuración le indican cómo crearlos y configurarlos, y así influimos en el comportamiento de toda la aplicación.
Los ficheros de configuración suelen estar escritos en formato NEON. Puede leer lo que se puede configurar aquí.
En el modo de desarrollo, el contenedor se actualiza automáticamente cada vez que cambia el código o los archivos de configuración. En el modo de producción, se genera sólo una vez y los cambios en los archivos no se comprueban para maximizar el rendimiento.
Los archivos de configuración se cargan utilizando addConfig()
:
$configurator->addConfig($rootDir . '/config/common.neon');
El método addConfig()
se puede llamar varias veces para añadir varios archivos.
$configurator->addConfig($rootDir . '/config/common.neon');
$configurator->addConfig($rootDir . '/config/services.neon');
if (PHP_SAPI === 'cli') {
$configurator->addConfig($rootDir . '/config/cli.php');
}
El nombre cli.php
no es una errata, la configuración también se puede escribir en un archivo PHP, que la
devuelve como un array.
Alternativamente, podemos utilizar la secciónincludes
para
cargar más archivos de configuración.
Si aparecen elementos con las mismas claves dentro de los archivos de configuración, se sobrescribirán o fusionarán en el caso de
los arrays. El fichero incluido más tarde tiene una prioridad mayor que el anterior. El fichero en el que aparece la sección
includes
tiene mayor prioridad que los ficheros incluidos en él.
Parámetros estáticos
Los parámetros utilizados en los archivos de configuración pueden definirse en la sección parameters
y
también pasarse (o sobrescribirse) por el método addStaticParameters()
(tiene el alias
addParameters()
). Es importante que los diferentes valores de los parámetros provoquen la generación de
contenedores DI adicionales, es decir, clases adicionales.
$configurator->addStaticParameters([
'projectId' => 23,
]);
En los archivos de configuración, podemos escribir la notación habitual %projectId%
para acceder al parámetro
denominado projectId
.
Parámetros dinámicos
También podemos añadir parámetros dinámicos al contenedor, sus diferentes valores, a diferencia de los parámetros estáticos, no provocarán la generación de nuevos contenedores DI.
$configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
Las variables de entorno podrían estar fácilmente disponibles utilizando parámetros dinámicos. Podemos acceder a ellas a
través de %env.variable%
en archivos de configuración.
$configurator->addDynamicParameters([
'env' => getenv(),
]);
Parámetros por defecto
Puede utilizar los siguientes parámetros estáticos en los archivos de configuración:
%appDir%
es la ruta absoluta al directorio del archivoBootstrap.php
%wwwDir%
es la ruta absoluta al directorio que contiene el archivo de entradaindex.php
%tempDir%
es la ruta absoluta al directorio para los archivos temporales%vendorDir%
es la ruta absoluta al directorio donde Composer instala las bibliotecas%rootDir%
es la ruta absoluta al directorio raíz del proyecto%debugMode%
indica si la aplicación está en modo depuración%consoleMode%
indica si la solicitud llegó a través de la línea de comandos
Servicios importados
Ahora vamos a profundizar más. Aunque el propósito de un contenedor DI es crear objetos, excepcionalmente puede existir la
necesidad de insertar un objeto existente en el contenedor. Esto lo hacemos definiendo el servicio con el atributo
imported: true
.
services:
myservice:
type: App\Model\MyCustomService
imported: true
Creamos una nueva instancia y la insertamos en bootstrap:
$configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Diferentes entornos
Siéntete libre de personalizar la clase Bootstrap
para adaptarla a tus necesidades. Puedes añadir parámetros al
método boot()
para diferenciar proyectos web, o añadir otros métodos, como bootForTests()
, que
inicializa el entorno para pruebas unitarias, bootForCli()
para scripts llamados desde la línea de
comandos, etc.
public static function bootForTests(): Configurator
{
$configurator = self::boot();
Tester\Environment::setup(); // Nette Tester initialization
return $configurator;
}