Nette Documentation Preview

syntax
Bootstrap
*********

<div class=perex>

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

</div>


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:

```php
use Nette\Bootstrap\Configurator;

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

	public function __construct()
	{
		$this->rootDir = dirname(__DIR__);
		// El configurador se encarga de configurar el entorno y los servicios de la aplicación.
		$this->configurator = new Configurator;
		// Establecer el directorio para los archivos temporales generados por Nette (por ejemplo, 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 puede habilitarlo para una dirección IP específica descomentando la siguiente línea:
		// $this->configurator->setDebugMode('secret@23.75.345.200');

		// Habilita Tracy: la última herramienta de depuración "navaja suiza".
		$this->configurator->enableTracy($this->rootDir . '/log');

		// RobotLoader: carga automáticamente todas las clases en el directorio dado
		$this->configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();
	}

	private function setupContainer(): void
	{
		// Carga archivos de configuración
		$this->configurator->addConfig($this->rootDir . '/config/common.neon');
	}
}
```


index.php .[#toc-index-php]
===========================

El archivo inicial para aplicaciones web es `index.php`, ubicado en el directorio público `www/`. Utiliza la clase `Bootstrap` para inicializar el entorno y crear un contenedor DI. A continuación, obtiene el servicio `Application` del contenedor, que lanza la aplicación web:

```php
$bootstrap = new App\Bootstrap;
// Inicializar el entorno + crear un contenedor DI
$container = $bootstrap->bootWebApplication();
// El contenedor DI crea un objeto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Inicia la aplicación Nette y gestiona la petición entrante
$application->run();
```

Como puedes ver, la clase [api: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 .[#toc-development-vs-production-mode]
====================================================================

Nette se comporta de forma diferente dependiendo de si se está ejecutando en un servidor de desarrollo o de producción:

🛠️ Modo Desarrollo:
	- Muestra la barra de depuración de Tracy con información útil (por ejemplo, consultas SQL, tiempo de ejecución, uso de memoria).
	- Muestra una página de error detallada con trazas de llamadas a funciones y contenidos de variables cuando se produce un error.
	- Actualiza automáticamente la caché cuando se modifican las plantillas Latte, los archivos de configuración, etc.


Modo de producción:
	- No muestra ninguna información de depuración; se registran todos los errores.
	- Muestra un `ErrorPresenter` o una página genérica de "Error de servidor" cuando se produce un error.
	- ¡La caché nunca se actualiza automáticamente!
	- Optimizado para velocidad y seguridad.


El modo se determina automáticamente, por lo que en la mayoría de los casos no es necesario configurarlo o cambiarlo manualmente:

- Modo de desarrollo: Activo en localhost (dirección IP `127.0.0.1` o `::1`) a menos que se esté utilizando un proxy (es decir, basándose en sus cabeceras HTTP).
- Modo de producción: Activo en cualquier otro lugar.

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()`:

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

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

También podemos desactivar completamente el modo de desarrollo, incluso para localhost:

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

Para facilitar la depuración, activaremos la gran herramienta [Tracy |tracy:]. En modo desarrollador visualiza los errores y en modo producción los registra en el directorio especificado:

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


Archivos temporales .[#toc-temporary-files]
===========================================

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é:

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

En Linux o macOS, establezca los [permisos de escritura |nette:troubleshooting#Setting directory permissions] para los directorios `log/` y `temp/`.


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

Normalmente, querremos cargar automáticamente las clases usando [RobotLoader |robot-loader:], 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:

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

Una forma alternativa es utilizar únicamente la carga automática de [Composer |best-practices:composer] PSR-4.


Zona horaria .[#toc-timezone]
=============================

Configurator le permite especificar una zona horaria para su aplicación.

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


Configuración del Contenedor DI .[#toc-di-container-configuration]
==================================================================

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 |neon:format]. Puede leer [lo que se puede configurar aquí |nette:configuring].

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

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

El método `addConfig()` se puede llamar varias veces para añadir varios archivos.

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

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ón`includes`  |dependency-injection:configuration#including files] 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 |dependency-injection:configuration#Merging] 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 .[#toc-static-parameters]
----------------------------------------------

Los parámetros utilizados en los archivos de configuración pueden definirse [en la sección `parameters` |dependency-injection:configuration#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.

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

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.

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

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


Parámetros por defecto .[#toc-default-parameters]
-------------------------------------------------

Puede utilizar los siguientes parámetros estáticos en los archivos de configuración:

- `%appDir%` es la ruta absoluta al directorio del archivo `Bootstrap.php`
- `%wwwDir%` es la ruta absoluta al directorio que contiene el archivo de entrada `index.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 .[#toc-imported-services]
----------------------------------------------

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

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

Creamos una nueva instancia y la insertamos en bootstrap:

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


Diferentes entornos .[#toc-different-environments]
==================================================

No dude en personalizar la clase `Bootstrap` según sus necesidades. Puedes añadir parámetros al método `bootWebApplication()` para diferenciar entre proyectos web. Alternativamente, puedes añadir otros métodos, como `bootTestEnvironment()` para inicializar el entorno para pruebas unitarias, `bootConsoleApplication()` para scripts llamados desde la línea de comandos, etc.

```php
public function bootTestEnvironment(): Nette\DI\Container
{
	Tester\Environment::setup(); // Inicialización del comprobador de redes
	$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 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
{
	private Configurator $configurator;
	private string $rootDir;

	public function __construct()
	{
		$this->rootDir = dirname(__DIR__);
		// El configurador se encarga de configurar el entorno y los servicios de la aplicación.
		$this->configurator = new Configurator;
		// Establecer el directorio para los archivos temporales generados por Nette (por ejemplo, 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 puede habilitarlo para una dirección IP específica descomentando la siguiente línea:
		// $this->configurator->setDebugMode('secret@23.75.345.200');

		// Habilita Tracy: la última herramienta de depuración "navaja suiza".
		$this->configurator->enableTracy($this->rootDir . '/log');

		// RobotLoader: carga automáticamente todas las clases en el directorio dado
		$this->configurator->createRobotLoader()
			->addDirectory(__DIR__)
			->register();
	}

	private function setupContainer(): void
	{
		// Carga archivos de configuración
		$this->configurator->addConfig($this->rootDir . '/config/common.neon');
	}
}

index.php

El archivo inicial para aplicaciones web es index.php, ubicado en el directorio público www/. Utiliza la clase Bootstrap para inicializar el entorno y crear un contenedor DI. A continuación, obtiene el servicio Application del contenedor, que lanza la aplicación web:

$bootstrap = new App\Bootstrap;
// Inicializar el entorno + crear un contenedor DI
$container = $bootstrap->bootWebApplication();
// El contenedor DI crea un objeto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
// Inicia la aplicación Nette y gestiona la petición entrante
$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 se comporta de forma diferente dependiendo de si se está ejecutando en un servidor de desarrollo o de producción:

🛠️ Modo Desarrollo
Muestra la barra de depuración de Tracy con información útil (por ejemplo, consultas SQL, tiempo de ejecución, uso de memoria).
Muestra una página de error detallada con trazas de llamadas a funciones y contenidos de variables cuando se produce un error.
Actualiza automáticamente la caché cuando se modifican las plantillas Latte, los archivos de configuración, etc.
Modo de producción
No muestra ninguna información de depuración; se registran todos los errores.
Muestra un ErrorPresenter o una página genérica de „Error de servidor“ cuando se produce un error.
¡La caché nunca se actualiza automáticamente!
Optimizado para velocidad y seguridad.

El modo se determina automáticamente, por lo que en la mayoría de los casos no es necesario configurarlo o cambiarlo manualmente:

  • Modo de desarrollo: Activo en localhost (dirección IP 127.0.0.1 o ::1) a menos que se esté utilizando un proxy (es decir, basándose en sus cabeceras HTTP).
  • Modo de producción: Activo en cualquier otro lugar.

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():

$this->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.

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

También podemos desactivar completamente el modo de desarrollo, incluso para localhost:

$this->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:

$this->configurator->enableTracy($this->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é:

$this->configurator->setTempDirectory($this->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:

$this->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.

$this->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():

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

El método addConfig() se puede llamar varias veces para añadir varios archivos.

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

$this->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.

$this->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.

$this->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 archivo Bootstrap.php
  • %wwwDir% es la ruta absoluta al directorio que contiene el archivo de entrada index.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:

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

Diferentes entornos

No dude en personalizar la clase Bootstrap según sus necesidades. Puedes añadir parámetros al método bootWebApplication() para diferenciar entre proyectos web. Alternativamente, puedes añadir otros métodos, como bootTestEnvironment() para inicializar 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 del comprobador de redes
	$this->setupContainer();
	return $this->configurator->createContainer();
}

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