Résolution des problèmes

Nette ne fonctionne pas, une page blanche s'affiche

  • Essayez d'insérer ini_set('display_errors', '1'); error_reporting(E_ALL); dans le fichier index.php juste après declare(strict_types=1);, cela forcera l'affichage des erreurs.
  • Si vous voyez toujours un écran blanc, il y a probablement une erreur dans la configuration du serveur et la raison sera révélée dans le journal du serveur. Pour être sûr, vérifiez si PHP fonctionne du tout en essayant d'afficher quelque chose avec echo 'test';.
  • Si vous voyez l'erreur Server Error: We're sorry! …, passez à la section suivante :

Erreur 500 Server Error: We're sorry! …

Cette page d'erreur est affichée par Nette en mode production. Si elle s'affiche sur votre ordinateur de développement, passez en mode développement et Tracy s'affichera avec un message détaillé.

La raison de l'erreur se trouve toujours dans le journal du répertoire log/. Cependant, si le message d'erreur contient la phrase Tracy is unable to log error, déterminez d'abord pourquoi les erreurs ne peuvent pas être journalisées. Vous pouvez le faire, par exemple, en passant temporairement en mode développement et en laissant Tracy journaliser n'importe quoi après son démarrage :

// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // votre adresse IP
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');

Tracy vous dira pourquoi elle ne peut pas journaliser. La cause peut être des permissions insuffisantes pour écrire dans le répertoire log/.

L'une des raisons les plus courantes de l'erreur 500 est un cache obsolète. Alors que Nette en mode développement met intelligemment à jour le cache automatiquement, en mode production, il se concentre sur la maximisation des performances et la suppression du cache, après chaque modification du code, est de votre responsabilité. Essayez de supprimer temp/cache.

Erreur 404, le routage ne fonctionne pas

Lorsque toutes les pages (sauf la page d'accueil) retournent une erreur 404, cela ressemble à un problème de configuration du serveur pour les jolies URL.

Les modifications dans les templates ou la configuration ne sont pas prises en compte

“J'ai modifié le template ou la configuration, mais le site affiche toujours l'ancienne version.” Ce comportement se produit en mode production, qui, pour des raisons de performances, ne vérifie pas les modifications dans les fichiers et conserve le cache généré une fois.

Pour ne pas avoir à supprimer manuellement le cache sur le serveur de production après chaque modification, activez le mode développement pour votre adresse IP dans le fichier Bootstrap.php :

$this->configurator->setDebugMode('votre.ip.adresse');

Comment désactiver le cache pendant le développement ?

Nette est intelligent et vous n'avez pas besoin d'y désactiver la mise en cache. Pendant le développement, il met automatiquement à jour le cache à chaque modification du template ou de la configuration du conteneur DI. De plus, le mode développement s'active par autodétection, il n'est donc généralement pas nécessaire de configurer quoi que ce soit, ou juste l'adresse IP.

Lors du débogage du routeur, nous vous recommandons de désactiver le cache du navigateur, dans lequel peuvent être stockées par exemple des redirections : ouvrez les Outils de développement (Ctrl+Shift+I ou Cmd+Option+I) et dans le panneau Réseau (Network), cochez la désactivation du cache.

Erreur #[\ReturnTypeWillChange] attribute should be used

Cette erreur apparaît si vous avez mis à jour PHP vers la version 8.1, mais que vous utilisez une version de Nette qui n'est pas compatible avec elle. La solution est donc de mettre à jour Nette vers une version plus récente à l'aide de composer update. Nette prend en charge PHP 8.1 à partir de la version 3.0. Si vous utilisez une version plus ancienne (vérifiez dans composer.json), mettez à niveau Nette ou restez avec PHP 8.0.

Configuration des permissions de répertoire

Si vous développez sur macOS ou Linux (ou tout autre système basé sur Unix), vous devrez configurer les permissions d'écriture pour le serveur web. Supposons que votre application se trouve dans le répertoire par défaut /var/www/html (Fedora, CentOS, RHEL).

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

Sur certains systèmes Linux (Fedora, CentOS, …), SELinux est activé par défaut. Vous devrez ajuster les politiques SELinux de manière appropriée et définir le contexte de sécurité SELinux correct pour les dossiers temp et log. Pour temp et log, nous définirons le type de contexte httpd_sys_rw_content_t, pour le reste de l'application (et surtout pour le dossier app), httpd_sys_content_t suffira. Sur le serveur, exécutez :

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

Ensuite, il est nécessaire d'activer le booléen SELinux httpd_can_network_connect_db, qui est désactivé par défaut et qui permettra à Nette de se connecter à la base de données via le réseau. Nous utiliserons pour cela la commande setsebool et avec l'option -P, nous effectuerons le changement de manière permanente, c'est-à-dire qu'après un redémarrage du serveur, nous n'aurons pas de mauvaise surprise :

setsebool -P httpd_can_network_connect_db on

Comment changer ou supprimer le répertoire www de l'URL ?

Le répertoire www/ utilisé dans les projets d'exemple de Nette représente ce qu'on appelle le répertoire public ou document-root du projet. C'est le seul répertoire dont le contenu est accessible au navigateur. Et il contient le fichier index.php, le point d'entrée qui lance l'application web écrite en Nette.

Pour faire fonctionner l'application sur un hébergement, il est nécessaire que le document-root soit correctement configuré. Vous avez deux options :

  1. Dans la configuration de l'hébergement, définissez le document-root sur ce répertoire
  2. Si l'hébergement a un dossier préparé (par exemple public_html), renommez www/ avec ce nom

N'essayez jamais de résoudre la sécurité uniquement à l'aide de .htaccess ou du routeur, qui empêcheraient l'accès aux autres dossiers.

Si l'hébergement ne permet pas de définir le document-root dans un sous-répertoire (c'est-à-dire de créer des répertoires un niveau au-dessus du répertoire public), cherchez un autre hébergeur. Vous prendriez sinon un risque de sécurité considérable. Ce serait comme vivre dans un appartement où la porte d'entrée ne peut pas être fermée et reste toujours grande ouverte.

Comment configurer le serveur pour les jolies URL ?

Apache: il est nécessaire d'activer et de configurer les règles mod_rewrite dans le fichier .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 vous rencontrez des problèmes, assurez-vous que :

Si vous configurez l'application dans un sous-dossier, vous devrez peut-être décommenter la ligne pour définir RewriteBase et la définir sur le dossier correct.

nginx: il faut configurer la redirection à l'aide de la directive try_files à l'intérieur du bloc location / dans la configuration du serveur.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args EST IMPORTANT !
}

Le bloc location pour chaque chemin de système de fichiers ne peut apparaître qu'une seule fois dans le bloc server. Si vous avez déjà location / dans votre configuration, ajoutez-y la directive try_files.

Vérification que .htaccess fonctionne

La manière la plus simple de tester si Apache utilise ou ignore votre fichier .htaccess, est de le corrompre intentionnellement. Insérez la ligne Test au début du fichier et maintenant, si vous actualisez la page dans le navigateur, vous devriez voir Internal Server Error.

Si cette erreur s'affiche, c'est en fait une bonne chose ! Cela signifie qu'Apache analyse le fichier .htaccess et rencontre l'erreur que nous y avons insérée. Supprimez la ligne Test.

Si Internal Server Error ne s'affiche pas, votre configuration Apache ignore le fichier .htaccess. Généralement, Apache l'ignore en raison de l'absence de la directive de configuration AllowOverride All.

Si vous l'hébergez vous-même, cela peut être facilement corrigé. Ouvrez le fichier httpd.conf ou apache.conf dans un éditeur de texte, recherchez la section <Directory> appropriée et ajoutez/modifiez cette directive :

<Directory "/var/www/htdocs"> # chemin vers votre document root
    AllowOverride All
    ...

Si votre site est hébergé ailleurs, consultez votre panneau de contrôle pour voir si vous pouvez y activer le fichier .htaccess. Sinon, contactez votre fournisseur d'hébergement, pour qu'il le fasse pour vous.

Vérification que mod_rewrite est activé

Si vous avez vérifié que .htaccess fonctionne, vous pouvez vérifier si l'extension mod_rewrite est activée. Insérez la ligne RewriteEngine On au début du fichier .htaccess et actualisez la page dans le navigateur. Si Internal Server Error s'affiche, cela signifie que mod_rewrite n'est pas activé. Il existe plusieurs façons de l'activer. Vous trouverez différentes manières de le faire dans différentes configurations sur Stack Overflow.

Les liens sont générés sans https:

Nette génère des liens avec le même protocole que la page elle-même. C'est-à-dire que sur la page https://foo, il génère des liens commençant par https: et inversement. Si vous êtes derrière un proxy inverse qui supprime HTTPS (par exemple dans Docker), il faut alors configurer le proxy, pour que la détection du protocole fonctionne correctement.

Si vous utilisez Nginx comme proxy, il faut avoir configuré la redirection par exemple comme ceci :

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-application:80;  # IP ou hostname du serveur/conteneur où tourne l'application
}

Ensuite, il faut indiquer dans la configuration l'IP du proxy et éventuellement la plage IP de votre réseau local où vous exploitez l'infrastructure :

http:
	proxy: IP-proxy/IP-range

Utilisation des caractères { } en JavaScript

Les caractères { et } sont utilisés pour écrire les balises Latte. Est considéré comme une balise tout ce qui suit le caractère { à l'exception d'un espace et d'un guillemet. Si vous avez donc besoin d'afficher directement le caractère { (souvent par exemple en JavaScript), vous pouvez mettre un espace (ou un autre caractère vide) après le caractère {. Cela évite la traduction en tant que balise.

S'il est nécessaire d'afficher ces caractères dans une situation où le texte serait interprété comme une balise, vous pouvez utiliser des balises spéciales pour afficher ces caractères – {l} pour { et {r} pour }.

{est une balise}
{ n'est pas une balise }
{l}n'est pas une balise{r}

Message Presenter::getContext() is deprecated

Nette est de loin le premier framework PHP à être passé à l'injection de dépendances et a conduit les programmeurs à l'utiliser de manière cohérente, dès les presenters eux-mêmes. Si un presenter a besoin d'une dépendance, il la demande. Au contraire, la voie consistant à passer l'ensemble du conteneur DI à la classe, et celle-ci en extrait directement les dépendances, est considérée comme un antipattern (appelé service locator). Cette méthode était utilisée dans Nette 0.x avant l'arrivée de l'injection de dépendances et son vestige est la méthode Presenter::getContext(), marquée comme obsolète depuis longtemps.

Si vous portez une très ancienne application Nette, il se peut qu'elle utilise encore cette méthode. À partir de la version 3.1 de nette/application, vous rencontrerez l'avertissement Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, et à partir de la version 4.0, l'erreur indiquant que la méthode n'existe pas.

La solution propre est bien sûr de refondre l'application pour qu'elle passe les dépendances via l'injection de dépendances. Comme solution de contournement, vous pouvez ajouter votre propre méthode getContext() à votre presenter de base et ainsi contourner le message :

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

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

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