Nette Documentation Preview

syntax
Solución de problemas
*********************


Nette no funciona, se muestra una página en blanco
--------------------------------------------------
- Pruebe a poner `ini_set('display_errors', '1'); error_reporting(E_ALL);` detrás de `declare(strict_types=1);` en el archivo `index.php` para forzar la visualización de los errores.
- Si sigue viendo una pantalla en blanco, probablemente haya un error en la configuración del servidor y encontrará el motivo en el log del servidor. Para asegurarse, compruebe si PHP funciona siquiera intentando imprimir algo con `echo 'test';`.
- Si ve el error *Server Error: We're sorry! …*, continúe con la sección siguiente:


Error 500 *Server Error: We're sorry! …*
----------------------------------------
Esta página de error la muestra Nette en modo de producción. Si la ve en su máquina de desarrollo, [cambie al modo de desarrollador |application:bootstrapping#Modo de desarrollo y modo de producción] y Tracy le mostrará un informe detallado.

El motivo del error lo encontrará siempre en el log del directorio `log/`. Pero si en el mensaje de error aparece la frase `Tracy is unable to log error`, averigüe primero por qué no se pueden registrar los errores. Puede hacerlo, por ejemplo, [cambiando |application:bootstrapping#Modo de desarrollo y modo de producción] temporalmente al modo de desarrollador y dejando que Tracy registre cualquier cosa tras arrancar:

```php
// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // su dirección IP
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');
```

Tracy le dirá por qué no puede registrar. La causa pueden ser [permisos insuficientes |#Establecer los permisos de los directorios] para escribir en el directorio `log/`.

Uno de los motivos más habituales del error 500 es una caché desactualizada. Mientras que en modo de desarrollo Nette actualiza la caché automáticamente y de forma inteligente, en modo de producción se centra en el máximo rendimiento y borrar la caché tras cada modificación del código es responsabilidad suya. Pruebe a borrar `temp/cache`.


Error 404, el enrutamiento no funciona
--------------------------------------
Cuando todas las páginas (salvo la de inicio) devuelven un error 404, parece un problema de configuración del servidor para las [URL bonitas |#¿Cómo configurar el servidor para URL bonitas?].


Los cambios en las plantillas o en la configuración no se reflejan
------------------------------------------------------------------
"He modificado la plantilla o la configuración, pero la web sigue mostrando la versión antigua." Este comportamiento se da en [modo de producción |application:bootstrapping#Modo de desarrollo y modo de producción], que, por motivos de rendimiento, no comprueba los cambios en los archivos y mantiene la caché generada anteriormente.

Para no tener que borrar la caché a mano en el servidor de producción tras cada modificación, habilite el modo de desarrollo para su dirección IP en el archivo `Bootstrap.php`:

```php
$this->configurator->setDebugMode('su.direccion.ip');
```


¿Cómo desactivar la caché durante el desarrollo?
------------------------------------------------
Nette es inteligente y no necesita desactivar la caché en él. Durante el desarrollo actualiza automáticamente la caché siempre que hay un cambio en la plantilla o en la configuración del contenedor DI. Además, el modo de desarrollo se activa por autodetección, así que normalmente no hace falta configurar nada, [o solo la dirección IP |application:bootstrapping#Modo de desarrollo y modo de producción].

Al depurar el router recomendamos desactivar la caché del navegador, donde pueden quedar guardadas, por ejemplo, las redirecciones: abra las herramientas para desarrolladores (Ctrl+Shift+I o Cmd+Option+I) y en el panel Network marque la casilla para desactivar la caché.


Error `#[\ReturnTypeWillChange] attribute should be used`
---------------------------------------------------------
Este error aparece si ha actualizado PHP a la versión 8.1 pero usa una versión de Nette que no es compatible con ella. La solución es actualizar Nette a una versión más reciente con `composer update`. Nette soporta PHP 8.1 desde la versión 3.0. Si usa una versión anterior (compruebe su `composer.json`), [actualice Nette |migrations:] o quédese con PHP 8.0.


Establecer los permisos de los directorios
------------------------------------------
Si desarrolla en macOS o Linux (o en cualquier otro sistema basado en Unix), tendrá que configurar los permisos de escritura para el servidor web. Suponiendo que su aplicación esté en el directorio predeterminado `/var/www/html` (Fedora, CentOS, RHEL):

```shell
cd /var/www/html/MI_PROYECTO
chmod -R a+rw temp log
```

En algunos sistemas Linux (Fedora, CentOS, ...) puede que SELinux esté habilitado de forma predeterminada. Puede que tenga que actualizar las políticas de SELinux o establecer las rutas de los directorios `temp` y `log` con el contexto de seguridad de SELinux correcto. A los directorios `temp` y `log` hay que asignarles el contexto `httpd_sys_rw_content_t`; para el resto de la aplicación, sobre todo la carpeta `app`, bastará con el contexto `httpd_sys_content_t`. Ejecute en el servidor como root:

```shell
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MI_PROYECTO/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MI_PROYECTO/temp(/.*)?'
restorecon -Rv /var/www/html/MI_PROYECTO/
```

Además hay que habilitar el booleano de SELinux `httpd_can_network_connect_db` para permitir que Nette se conecte a la base de datos por la red. De forma predeterminada está deshabilitado. Para ello se puede usar el comando `setsebool`, y si se indica la opción `-P`, este ajuste será persistente tras los reinicios:

```shell
setsebool -P httpd_can_network_connect_db on
```


¿Cómo cambiar o quitar el directorio `www` de la URL?
-----------------------------------------------------
El directorio `www/` que se usa en los proyectos de ejemplo de Nette representa el directorio público, o document-root, del proyecto. Es el único directorio cuyo contenido es accesible desde el navegador. Contiene el archivo `index.php`, el punto de entrada que arranca la aplicación web de Nette.

Para ejecutar la aplicación en un hosting hay que configurar correctamente el document-root. Tiene dos opciones:
1. Establecer en la configuración del hosting el document-root a este directorio.
2. Si el hosting tiene una carpeta ya preparada (p. ej. `public_html`), renombre `www/` con ese nombre.

.[warning]
Nunca intente asegurar su aplicación usando solo `.htaccess` o reglas del router para impedir el acceso a otras carpetas.

Si el hosting no permite establecer el document-root a un subdirectorio (es decir, crear directorios un nivel por encima del directorio público), busque otro proveedor. En caso contrario se expondría a un riesgo de seguridad considerable. Sería como vivir en un piso cuya puerta de entrada no se puede cerrar y está siempre abierta de par en par.


¿Cómo configurar el servidor para URL bonitas?
----------------------------------------------
**Apache**: hay que habilitar y configurar las reglas de mod_rewrite en el archivo `.htaccess`:

```apacheconf
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz)$ index.php [L]
```

Si se topa con problemas, asegúrese de que:
- el archivo `.htaccess` está en el directorio document-root (es decir, junto al archivo `index.php`)
- [Apache procesa los archivos `.htaccess` |#Compruebe si .htaccess funciona]
- [mod_rewrite está habilitado |#Compruebe si mod_rewrite está habilitado]

Si instala la aplicación en una subcarpeta, puede que tenga que descomentar la línea del ajuste `RewriteBase` y ponerle la carpeta correcta.

**nginx**: hay que configurar la redirección con la directiva `try_files` dentro del bloque `location /` de la configuración del servidor.

```nginx
location / {
	try_files $uri $uri/ /index.php$is_args$args;  # ¡$is_args$args ES IMPORTANTE!
}
```

El bloque `location` debe aparecer solo una vez para cada ruta del sistema de archivos dentro del bloque `server`. Si ya tiene un bloque `location /` en su configuración, añada la directiva `try_files` al bloque existente.


Compruebe si `.htaccess` funciona
---------------------------------
La forma más sencilla de comprobar si Apache usa o ignora su archivo `.htaccess` es romperlo a propósito. Ponga la línea `Test` al principio del archivo. Ahora, al refrescar la página en el navegador, debería ver un *Internal Server Error*.

Si ve ese error, ¡eso está bien! Significa que Apache analiza el archivo `.htaccess` y se topa con el error que hemos puesto ahí. Elimine la línea `Test`.

Si no ve el *Internal Server Error*, su configuración de Apache ignora el archivo `.htaccess`. Normalmente Apache lo ignora porque falta la directiva de configuración `AllowOverride All`.

Si lo aloja usted mismo, es fácil de arreglar. Abra su `httpd.conf` o `apache.conf` en un editor de texto, localice la sección `<Directory>` correspondiente y añada o cambie esta directiva:

```apacheconf
<Directory "/var/www/htdocs"> # ruta a su document root
    AllowOverride All
    ...
```

Si su sitio está alojado en otro sitio, mire en su panel de control si puede habilitar ahí `.htaccess`. Si no, pida a su proveedor de hosting que lo haga por usted.


Compruebe si `mod_rewrite` está habilitado
------------------------------------------
Si ha verificado que [`.htaccess` funciona |#Compruebe si .htaccess funciona], puede verificar que la extensión mod_rewrite está habilitada. Ponga la línea `RewriteEngine On` al principio del archivo `.htaccess` y refresque la página en el navegador. Si ve un *Internal Server Error*, significa que mod_rewrite no está habilitado. Hay varias formas de habilitarlo. Vea en Stack Overflow las distintas maneras de hacerlo en cada configuración.


Los enlaces se generan sin `https:`
-----------------------------------
Nette genera los enlaces con el mismo protocolo que usa la página actual. Así, en una página `https://foo` genera enlaces que empiezan por `https:`, y al revés. Si está detrás de un proxy inverso que elimina HTTPS (por ejemplo, en Docker), tiene que [configurar el proxy |http:configuration#Proxy HTTP] en la configuración para que la detección del protocolo funcione correctamente.

Si usa Nginx como proxy, tiene que tener la redirección configurada, por ejemplo, así:

```
location / {
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_set_header X-Forwarded-Port  $server_port;
	proxy_pass http://IP-aplicacion:80;  # IP o hostname del servidor/contenedor donde corre la aplicación
}
```

Además hay que indicar en la configuración la IP del proxy y, opcionalmente, el rango de IP de su red local donde ejecuta la infraestructura:

```neon
http:
	proxy: IP-proxy/rango-IP
```


Uso de los caracteres { } en JavaScript
---------------------------------------
Los caracteres `{` y `}` se usan para escribir las etiquetas de Latte. Todo lo que sigue al carácter `{` (salvo un espacio y unas comillas) se considera una etiqueta. Si necesita imprimir directamente el carácter `{` (a menudo en JavaScript), puede poner un espacio (u otro carácter en blanco) justo detrás de `{`. Eso evita que se interprete como una etiqueta.

Si hay que imprimir estos caracteres en una situación en la que el texto se interpretaría como una etiqueta, puede usar etiquetas especiales para imprimirlos: `{l}` para `{` y `{r}` para `}`.

```
{is a tag}
{ is not a tag }
{l}is not a tag{r}
```


Error `Cannot modify header information - headers already sent`
---------------------------------------------------------------

Este error aparece cuando la aplicación intenta enviar una cabecera HTTP (una cookie, una redirección o el inicio de la sesión) en un momento en el que ya se ha enviado alguna salida al navegador. Las cabeceras tienen que preceder siempre al cuerpo de la respuesta.

Hay dos causas posibles: o la salida se escapa demasiado pronto, o la cabecera se envía demasiado tarde.

La salida suele escaparse demasiado pronto por un espacio o una línea en blanco perdidos delante de `<?php`, detrás del `?>` de cierre, o por un BOM que el editor insertó al principio del archivo y no muestra. Por eso nunca termine los archivos PHP con `?>`. Para averiguar qué sitio imprimió primero, use [Tracy\OutputDebugger |tracy:recipes#Localizar el origen de la salida].

La cabecera se envía demasiado tarde normalmente al trabajar con la sesión. Nette arranca la sesión automáticamente la primera vez que lee de ella o escribe en ella, y si eso ocurre solo mientras se renderiza la plantilla, la salida ya va de camino. Por eso, trabaje con la sesión como muy tarde en el método `beforeRender()`, y en los componentes también en los métodos `handle<Signal>()`.

No intente resolver el problema estableciendo [autoStart: true |http:configuration#Sesión]. Eso arranca la sesión para cada visitante, incluidos los robots, y crea innecesariamente una enorme cantidad de archivos en el disco. El valor predeterminado `smart` arranca la sesión solo cuando de verdad hace falta.


Aviso `Presenter::getContext() is deprecated`
---------------------------------------------

Nette fue con diferencia el primer framework de PHP que pasó a la dependency injection y guió a los programadores para usarla de forma consistente, empezando por los propios presenters. Si un presenter necesita una dependencia, [la pide|dependency-injection:passing-dependencies]. Por el contrario, pasar todo el contenedor DI a una clase y que esta saque las dependencias directamente se considera un antipatrón (conocido como patrón service locator). Este enfoque se usaba en Nette 0.x, antes de la llegada de la dependency injection, y el método `Presenter::getContext()`, marcado desde hace mucho como obsoleto, es un resto de aquella época.

Si está portando una aplicación de Nette muy antigua, puede que descubra que todavía usa este método. Desde la versión 3.1 de `nette/application` se encontrará con el aviso `Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection`, y desde la versión 4.0 con un error que dice que el método no existe.

La solución limpia es, por supuesto, refactorizar la aplicación para pasar las dependencias mediante dependency injection. Como solución provisional puede añadir a su presenter base su propio método `getContext()` para esquivar el mensaje:

```php
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
	private Nette\DI\Container $context;

	public function injectContext(Nette\DI\Container $context): void
	{
		$this->context = $context;
	}

	public function getContext(): Nette\DI\Container
	{
		return $this->context;
	}
}
```

Solución de problemas

Nette no funciona, se muestra una página en blanco

  • Pruebe a poner ini_set('display_errors', '1'); error_reporting(E_ALL); detrás de declare(strict_types=1); en el archivo index.php para forzar la visualización de los errores.
  • Si sigue viendo una pantalla en blanco, probablemente haya un error en la configuración del servidor y encontrará el motivo en el log del servidor. Para asegurarse, compruebe si PHP funciona siquiera intentando imprimir algo con echo 'test';.
  • Si ve el error Server Error: We're sorry! …, continúe con la sección siguiente:

Error 500 Server Error: We're sorry! …

Esta página de error la muestra Nette en modo de producción. Si la ve en su máquina de desarrollo, cambie al modo de desarrollador y Tracy le mostrará un informe detallado.

El motivo del error lo encontrará siempre en el log del directorio log/. Pero si en el mensaje de error aparece la frase Tracy is unable to log error, averigüe primero por qué no se pueden registrar los errores. Puede hacerlo, por ejemplo, cambiando temporalmente al modo de desarrollador y dejando que Tracy registre cualquier cosa tras arrancar:

// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // su dirección IP
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');

Tracy le dirá por qué no puede registrar. La causa pueden ser permisos insuficientes para escribir en el directorio log/.

Uno de los motivos más habituales del error 500 es una caché desactualizada. Mientras que en modo de desarrollo Nette actualiza la caché automáticamente y de forma inteligente, en modo de producción se centra en el máximo rendimiento y borrar la caché tras cada modificación del código es responsabilidad suya. Pruebe a borrar temp/cache.

Error 404, el enrutamiento no funciona

Cuando todas las páginas (salvo la de inicio) devuelven un error 404, parece un problema de configuración del servidor para las URL bonitas.

Los cambios en las plantillas o en la configuración no se reflejan

„He modificado la plantilla o la configuración, pero la web sigue mostrando la versión antigua.“ Este comportamiento se da en modo de producción, que, por motivos de rendimiento, no comprueba los cambios en los archivos y mantiene la caché generada anteriormente.

Para no tener que borrar la caché a mano en el servidor de producción tras cada modificación, habilite el modo de desarrollo para su dirección IP en el archivo Bootstrap.php:

$this->configurator->setDebugMode('su.direccion.ip');

¿Cómo desactivar la caché durante el desarrollo?

Nette es inteligente y no necesita desactivar la caché en él. Durante el desarrollo actualiza automáticamente la caché siempre que hay un cambio en la plantilla o en la configuración del contenedor DI. Además, el modo de desarrollo se activa por autodetección, así que normalmente no hace falta configurar nada, o solo la dirección IP.

Al depurar el router recomendamos desactivar la caché del navegador, donde pueden quedar guardadas, por ejemplo, las redirecciones: abra las herramientas para desarrolladores (Ctrl+Shift+I o Cmd+Option+I) y en el panel Network marque la casilla para desactivar la caché.

Error #[\ReturnTypeWillChange] attribute should be used

Este error aparece si ha actualizado PHP a la versión 8.1 pero usa una versión de Nette que no es compatible con ella. La solución es actualizar Nette a una versión más reciente con composer update. Nette soporta PHP 8.1 desde la versión 3.0. Si usa una versión anterior (compruebe su composer.json), actualice Nette o quédese con PHP 8.0.

Establecer los permisos de los directorios

Si desarrolla en macOS o Linux (o en cualquier otro sistema basado en Unix), tendrá que configurar los permisos de escritura para el servidor web. Suponiendo que su aplicación esté en el directorio predeterminado /var/www/html (Fedora, CentOS, RHEL):

cd /var/www/html/MI_PROYECTO
chmod -R a+rw temp log

En algunos sistemas Linux (Fedora, CentOS, …) puede que SELinux esté habilitado de forma predeterminada. Puede que tenga que actualizar las políticas de SELinux o establecer las rutas de los directorios temp y log con el contexto de seguridad de SELinux correcto. A los directorios temp y log hay que asignarles el contexto httpd_sys_rw_content_t; para el resto de la aplicación, sobre todo la carpeta app, bastará con el contexto httpd_sys_content_t. Ejecute en el servidor como root:

semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MI_PROYECTO/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/MI_PROYECTO/temp(/.*)?'
restorecon -Rv /var/www/html/MI_PROYECTO/

Además hay que habilitar el booleano de SELinux httpd_can_network_connect_db para permitir que Nette se conecte a la base de datos por la red. De forma predeterminada está deshabilitado. Para ello se puede usar el comando setsebool, y si se indica la opción -P, este ajuste será persistente tras los reinicios:

setsebool -P httpd_can_network_connect_db on

¿Cómo cambiar o quitar el directorio www de la URL?

El directorio www/ que se usa en los proyectos de ejemplo de Nette representa el directorio público, o document-root, del proyecto. Es el único directorio cuyo contenido es accesible desde el navegador. Contiene el archivo index.php, el punto de entrada que arranca la aplicación web de Nette.

Para ejecutar la aplicación en un hosting hay que configurar correctamente el document-root. Tiene dos opciones:

  1. Establecer en la configuración del hosting el document-root a este directorio.
  2. Si el hosting tiene una carpeta ya preparada (p. ej. public_html), renombre www/ con ese nombre.

Nunca intente asegurar su aplicación usando solo .htaccess o reglas del router para impedir el acceso a otras carpetas.

Si el hosting no permite establecer el document-root a un subdirectorio (es decir, crear directorios un nivel por encima del directorio público), busque otro proveedor. En caso contrario se expondría a un riesgo de seguridad considerable. Sería como vivir en un piso cuya puerta de entrada no se puede cerrar y está siempre abierta de par en par.

¿Cómo configurar el servidor para URL bonitas?

Apache: hay que habilitar y configurar las reglas de mod_rewrite en el archivo .htaccess:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(pdf|js|ico|gif|jpg|png|css|rar|zip|tar\.gz)$ index.php [L]

Si se topa con problemas, asegúrese de que:

Si instala la aplicación en una subcarpeta, puede que tenga que descomentar la línea del ajuste RewriteBase y ponerle la carpeta correcta.

nginx: hay que configurar la redirección con la directiva try_files dentro del bloque location / de la configuración del servidor.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # ¡$is_args$args ES IMPORTANTE!
}

El bloque location debe aparecer solo una vez para cada ruta del sistema de archivos dentro del bloque server. Si ya tiene un bloque location / en su configuración, añada la directiva try_files al bloque existente.

Compruebe si .htaccess funciona

La forma más sencilla de comprobar si Apache usa o ignora su archivo .htaccess es romperlo a propósito. Ponga la línea Test al principio del archivo. Ahora, al refrescar la página en el navegador, debería ver un Internal Server Error.

Si ve ese error, ¡eso está bien! Significa que Apache analiza el archivo .htaccess y se topa con el error que hemos puesto ahí. Elimine la línea Test.

Si no ve el Internal Server Error, su configuración de Apache ignora el archivo .htaccess. Normalmente Apache lo ignora porque falta la directiva de configuración AllowOverride All.

Si lo aloja usted mismo, es fácil de arreglar. Abra su httpd.conf o apache.conf en un editor de texto, localice la sección <Directory> correspondiente y añada o cambie esta directiva:

<Directory "/var/www/htdocs"> # ruta a su document root
    AllowOverride All
    ...

Si su sitio está alojado en otro sitio, mire en su panel de control si puede habilitar ahí .htaccess. Si no, pida a su proveedor de hosting que lo haga por usted.

Compruebe si mod_rewrite está habilitado

Si ha verificado que .htaccess funciona, puede verificar que la extensión mod_rewrite está habilitada. Ponga la línea RewriteEngine On al principio del archivo .htaccess y refresque la página en el navegador. Si ve un Internal Server Error, significa que mod_rewrite no está habilitado. Hay varias formas de habilitarlo. Vea en Stack Overflow las distintas maneras de hacerlo en cada configuración.

Los enlaces se generan sin https:

Nette genera los enlaces con el mismo protocolo que usa la página actual. Así, en una página https://foo genera enlaces que empiezan por https:, y al revés. Si está detrás de un proxy inverso que elimina HTTPS (por ejemplo, en Docker), tiene que configurar el proxy en la configuración para que la detección del protocolo funcione correctamente.

Si usa Nginx como proxy, tiene que tener la redirección configurada, por ejemplo, así:

location / {
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_set_header X-Forwarded-Port  $server_port;
	proxy_pass http://IP-aplicacion:80;  # IP o hostname del servidor/contenedor donde corre la aplicación
}

Además hay que indicar en la configuración la IP del proxy y, opcionalmente, el rango de IP de su red local donde ejecuta la infraestructura:

http:
	proxy: IP-proxy/rango-IP

Uso de los caracteres { } en JavaScript

Los caracteres { y } se usan para escribir las etiquetas de Latte. Todo lo que sigue al carácter { (salvo un espacio y unas comillas) se considera una etiqueta. Si necesita imprimir directamente el carácter { (a menudo en JavaScript), puede poner un espacio (u otro carácter en blanco) justo detrás de {. Eso evita que se interprete como una etiqueta.

Si hay que imprimir estos caracteres en una situación en la que el texto se interpretaría como una etiqueta, puede usar etiquetas especiales para imprimirlos: {l} para { y {r} para }.

{is a tag}
{ is not a tag }
{l}is not a tag{r}

Error Cannot modify header information - headers already sent

Este error aparece cuando la aplicación intenta enviar una cabecera HTTP (una cookie, una redirección o el inicio de la sesión) en un momento en el que ya se ha enviado alguna salida al navegador. Las cabeceras tienen que preceder siempre al cuerpo de la respuesta.

Hay dos causas posibles: o la salida se escapa demasiado pronto, o la cabecera se envía demasiado tarde.

La salida suele escaparse demasiado pronto por un espacio o una línea en blanco perdidos delante de <?php, detrás del ?> de cierre, o por un BOM que el editor insertó al principio del archivo y no muestra. Por eso nunca termine los archivos PHP con ?>. Para averiguar qué sitio imprimió primero, use Tracy\OutputDebugger.

La cabecera se envía demasiado tarde normalmente al trabajar con la sesión. Nette arranca la sesión automáticamente la primera vez que lee de ella o escribe en ella, y si eso ocurre solo mientras se renderiza la plantilla, la salida ya va de camino. Por eso, trabaje con la sesión como muy tarde en el método beforeRender(), y en los componentes también en los métodos handle<Signal>().

No intente resolver el problema estableciendo autoStart: true. Eso arranca la sesión para cada visitante, incluidos los robots, y crea innecesariamente una enorme cantidad de archivos en el disco. El valor predeterminado smart arranca la sesión solo cuando de verdad hace falta.

Aviso Presenter::getContext() is deprecated

Nette fue con diferencia el primer framework de PHP que pasó a la dependency injection y guió a los programadores para usarla de forma consistente, empezando por los propios presenters. Si un presenter necesita una dependencia, la pide. Por el contrario, pasar todo el contenedor DI a una clase y que esta saque las dependencias directamente se considera un antipatrón (conocido como patrón service locator). Este enfoque se usaba en Nette 0.x, antes de la llegada de la dependency injection, y el método Presenter::getContext(), marcado desde hace mucho como obsoleto, es un resto de aquella época.

Si está portando una aplicación de Nette muy antigua, puede que descubra que todavía usa este método. Desde la versión 3.1 de nette/application se encontrará con el aviso Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, y desde la versión 4.0 con un error que dice que el método no existe.

La solución limpia es, por supuesto, refactorizar la aplicación para pasar las dependencias mediante dependency injection. Como solución provisional puede añadir a su presenter base su propio método getContext() para esquivar el mensaje:

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
	private Nette\DI\Container $context;

	public function injectContext(Nette\DI\Container $context): void
	{
		$this->context = $context;
	}

	public function getContext(): Nette\DI\Container
	{
		return $this->context;
	}
}