Bootstrap
Bootstrap es el código de arranque que inicializa el entorno, crea el contenedor de inyección de dependencias (DI) y ejecuta la aplicación. Hablaremos de:
- cómo se configura usando archivos NEON
- cómo distinguir entre modo de producción y desarrollo
- cómo crear un contenedor DI
Las aplicaciones, ya sean web o scripts ejecutados desde la línea de comandos, comienzan su ejecución con alguna forma de
inicialización del entorno. En tiempos pasados, esto solía estar a cargo de un archivo llamado, por ejemplo,
include.inc.php
, que el archivo inicial incluía. En las aplicaciones Nette modernas, ha sido reemplazado por la
clase Bootstrap
, que como parte de la aplicación se encuentra en el archivo app/Bootstrap.php
. Puede
verse, por ejemplo, así:
use Nette\Bootstrap\Configurator;
class Bootstrap
{
private Configurator $configurator;
private string $rootDir;
public function __construct()
{
$this->rootDir = dirname(__DIR__);
// El configurador es responsable de configurar el entorno de la aplicación y los servicios.
$this->configurator = new Configurator;
// Establece el directorio para los archivos temporales generados por Nette (p. ej., plantillas compiladas)
$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 es inteligente y el modo de desarrollo se activa automáticamente,
// o puedes habilitarlo para una dirección IP específica descomentando la siguiente línea:
// $this->configurator->setDebugMode('secret@23.75.345.200');
// Activa Tracy: la "navaja suiza" definitiva para la depuración.
$this->configurator->enableTracy($this->rootDir . '/log');
// RobotLoader: carga automáticamente todas las clases en el directorio seleccionado
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
}
private function setupContainer(): void
{
// Carga los archivos de configuración
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
index.php
El archivo inicial en el caso de las aplicaciones web es index.php
, que se encuentra en el directorio público
www/
. Este solicita a la clase Bootstrap que inicialice el entorno y cree el contenedor DI. Luego, obtiene de él el
servicio Application
, que ejecuta la aplicación web:
$bootstrap = new App\Bootstrap;
// Inicialización del entorno + creación del contenedor DI
$container = $bootstrap->bootWebApplication();
// El contenedor DI crea un objeto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Ejecución de la aplicación Nette y procesamiento de la petición entrante
$application->run();
Como se puede ver, la clase Nette\Bootstrap\Configurator ayuda con la configuración del entorno y la creación del contenedor de inyección de dependencias (DI), que ahora presentaremos con más detalle.
Modo de desarrollo vs producción
Nette se comporta de manera diferente dependiendo de si se ejecuta en un servidor de desarrollo o de producción:
- 🛠️ Modo de desarrollo (Development)
- Muestra la barra de depuración de Tracy con información útil (consultas SQL, tiempo de ejecución, memoria utilizada)
- En caso de error, muestra una página de error detallada con llamadas a funciones y contenido de variables
- Actualiza automáticamente la caché al cambiar las plantillas Latte, modificar archivos de configuración, etc.
- 🚀 Modo de producción (Production)
- No muestra ninguna información de depuración, todos los errores se registran en el log
- En caso de error, muestra ErrorPresenter o una página genérica “Server Error”
- ¡La caché nunca se actualiza automáticamente!
- Optimizado para velocidad y seguridad
La elección del modo se realiza por autodetección, por lo que generalmente no es necesario configurar nada ni cambiar manualmente:
- modo de desarrollo: en localhost (dirección IP
127.0.0.1
o::1
) si no hay proxy presente (es decir, su cabecera HTTP) - modo de producción: en cualquier otro lugar
Si queremos habilitar el modo de desarrollo también en otros casos, por ejemplo, para programadores que acceden desde una
dirección IP específica, usamos setDebugMode()
:
$this->configurator->setDebugMode('23.75.345.200'); // también se puede indicar un array de direcciones IP
Definitivamente recomendamos combinar la dirección IP con una cookie. Guardamos un token secreto en la cookie
nette-debug
, por ejemplo, secret1234
, y de esta manera activamos el modo de desarrollo para los
programadores que acceden desde una dirección IP específica y que además tienen el token mencionado en la cookie:
$this->configurator->setDebugMode('secret1234@23.75.345.200');
También podemos desactivar completamente el modo de desarrollo, incluso para localhost:
$this->configurator->setDebugMode(false);
Atención, el valor true
activa el modo de desarrollo de forma permanente, lo cual nunca debe ocurrir en un
servidor de producción.
Herramienta de depuración Tracy
Para facilitar la depuración, también activaremos la excelente herramienta Tracy. En el modo de desarrollo, visualiza los errores y en el modo de producción, registra los errores en el directorio especificado:
$this->configurator->enableTracy($this->rootDir . '/log');
Archivos temporales
Nette utiliza caché para el contenedor DI, RobotLoader, plantillas, etc. Por lo tanto, es necesario establecer la ruta al directorio donde se almacenará la caché:
$this->configurator->setTempDirectory($this->rootDir . '/temp');
En Linux o macOS, establezca permisos de escritura para los
directorios log/
y temp/
.
RobotLoader
Generalmente, querremos cargar clases automáticamente usando RobotLoader,
por lo que debemos iniciarlo y hacer que cargue clases desde el directorio donde se encuentra Bootstrap.php
(es
decir, __DIR__
), y todos los subdirectorios:
$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
Un enfoque alternativo es dejar que las clases se carguen solo a través de Composer cumpliendo con PSR-4.
Zona horaria
A través del configurador, puede establecer la zona horaria predeterminada.
$this->configurator->setTimeZone('Europe/Prague');
Configuración del contenedor DI
Parte del proceso de arranque es la creación del contenedor DI o fábrica de objetos, que es el corazón de toda la aplicación. En realidad, es una clase PHP que Nette genera y guarda en el directorio de caché. La fábrica produce los objetos clave de la aplicación y, mediante archivos de configuración, le instruimos cómo debe crearlos y configurarlos, influyendo así en el comportamiento de toda la aplicación.
Los archivos de configuración generalmente se escriben en formato NEON. En un capítulo aparte, aprenderá qué se puede configurar.
En el modo de desarrollo, el contenedor se actualiza automáticamente cada vez que se cambia el código o los archivos de configuración. En el modo de producción, se genera solo una vez y los cambios no se verifican para maximizar el rendimiento.
Cargamos los archivos de configuración usando addConfig()
:
$this->configurator->addConfig($this->rootDir . '/config/common.neon');
Si queremos agregar más archivos de configuración, podemos llamar a la función addConfig()
varias veces.
$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');
}
El nombre cli.php
no es un error tipográfico, la configuración también puede estar escrita en un archivo PHP
que la devuelve como un array.
También podemos agregar otros archivos de configuración en la sección
includes
.
Si aparecen elementos con las mismas claves en los archivos de configuración, se sobrescribirán o, en el caso de arrays, se fusionarán. El archivo cargado
posteriormente tiene mayor prioridad que el anterior. El archivo en el que se indica la sección includes
tiene mayor
prioridad que los archivos incluidos en él.
Parámetros estáticos
Los parámetros utilizados en los archivos de configuración se pueden definir en la sección parameters
y también
se pueden pasar (o sobrescribir) con el método addStaticParameters()
(tiene el alias addParameters()
).
Es importante que diferentes valores de parámetros provoquen la generación de contenedores DI adicionales, es decir, clases
adicionales.
$this->configurator->addStaticParameters([
'projectId' => 23,
]);
Al parámetro projectId
se puede hacer referencia en la configuración con la notación habitual
%projectId%
.
Parámetros dinámicos
También podemos agregar parámetros dinámicos al contenedor, cuyos diferentes valores, a diferencia de los parámetros estáticos, no provocan la generación de nuevos contenedores DI.
$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
De esta manera, podemos agregar fácilmente, por ejemplo, variables de entorno, a las que luego se puede hacer referencia en la
configuración con la notación %env.variable%
.
$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
Parámetros predeterminados
En los archivos de configuración, puede utilizar estos parámetros estáticos:
%appDir%
es la ruta absoluta al directorio con el archivoBootstrap.php
%wwwDir%
es la ruta absoluta al directorio con el archivo de entradaindex.php
%tempDir%
es la ruta absoluta al directorio para archivos temporales%vendorDir%
es la ruta absoluta al directorio donde Composer instala las librerías%rootDir%
es la ruta absoluta al directorio raíz del proyecto%debugMode%
indica si la aplicación está en modo de depuración%consoleMode%
indica si la petición llegó a través de la línea de comandos
Servicios importados
Ahora vamos más profundo. Aunque el propósito del contenedor DI es fabricar objetos, excepcionalmente puede surgir la
necesidad de insertar un objeto existente en el contenedor. Hacemos esto definiendo el servicio con el indicador
imported: true
.
services:
myservice:
type: App\Model\MyCustomService
imported: true
Y en bootstrap insertamos el objeto en el contenedor:
$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
Entorno diferente
No dude en modificar la clase Bootstrap según sus necesidades. Puede agregar parámetros al método
bootWebApplication()
para distinguir proyectos web. O podemos agregar otros métodos, por ejemplo,
bootTestEnvironment()
, que inicializa el entorno para pruebas unitarias, bootConsoleApplication()
para
scripts llamados desde la línea de comandos, etc.
public function bootTestEnvironment(): Nette\DI\Container
{
Tester\Environment::setup(); // inicialización de Nette Tester
$this->setupContainer();
return $this->configurator->createContainer();
}
public function bootConsoleApplication(): Nette\DI\Container
{
$this->configurator->setDebugMode(false);
$this->initializeEnvironment();
$this->setupContainer();
return $this->configurator->createContainer();
}