Dépannage

Nette ne fonctionne pas, une page blanche s'affiche

  • Essayez de mettre ini_set('display_errors', '1'); error_reporting(E_ALL); après declare(strict_types=1); dans le fichier index.php pour forcer l'affichage des erreurs.
  • Si vous voyez toujours un écran blanc, il y a probablement une erreur dans la configuration du serveur et vous découvrirez la raison dans le journal du serveur. Pour être sûr, vérifiez que PHP fonctionne en essayant d'imprimer quelque chose en utilisant echo 'test';.
  • Si vous voyez une erreur Server Error : Nous sommes désolés ! …, passez à la section suivante :

Erreur 500 Erreur du serveur : Nous sommes désolés ! …

Cette page d'erreur est affichée par Nette en mode production. Si vous la voyez sur votre machine de développement, passez en mode développeur et Tracy s'affichera avec un rapport détaillé.

Vous pouvez toujours trouver la raison de l'erreur dans le répertoire log/. Cependant, si le message d'erreur affiche la phrase Tracy is unable to log error, déterminez d'abord pourquoi les erreurs ne peuvent pas être enregistrées. Vous pouvez le faire, par exemple, en passant temporairement en mode développeur et en laissant Tracy enregistrer n'importe quoi après son lancement :

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

Tracy vous informera de la raison pour laquelle il ne peut pas enregistrer. La cause peut être un manque de droits d' écriture dans le répertoire log/.

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

Erreur 404, le routage ne fonctionne pas

Lorsque toutes les pages (sauf la page d'accueil) renvoient une erreur 404, il semble qu'il y ait un problème de configuration du serveur pour les jolies URL.

Les modifications apportées aux modèles ou à la configuration ne sont pas prises en compte

"J'ai modifié le modèle ou la configuration, mais le site web affiche toujours l'ancienne version. Ce comportement se produit en mode production qui, pour des raisons de performance, ne vérifie pas les modifications de fichiers et maintient un cache généré précédemment.

Pour éviter de vider 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('your.ip.address');

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

Nette est intelligent et il n'est pas nécessaire de désactiver la mise en cache. Pendant le développement, il met automatiquement à jour le cache chaque fois qu'il y a un changement dans le modèle ou la configuration du conteneur DI. De plus, le mode développement est activé par auto-détection, il n'y a donc généralement pas besoin de configurer quoi que ce soit, ou juste l'adresse IP.

Lorsque vous déboguez le routeur, nous vous recommandons de désactiver le cache du navigateur, où, par exemple, les redirections peuvent être stockées : ouvrez Developer Tools (Ctrl+Shift+I ou Cmd+Option+I) et dans le panneau Network, cochez la case pour désactiver le cache.

Erreur #[\ReturnTypeWillChange] attribute should be used

Cette erreur se produit si vous avez mis à niveau PHP vers la version 8.1 mais que vous utilisez Nette, qui n'est pas compatible avec cette version. La solution est donc de mettre à jour Nette vers une version plus récente en utilisant composer update. Nette supporte PHP 8.1 depuis la version 3.0. Si vous utilisez une version plus ancienne (vous pouvez le savoir en consultant composer.json), mettez à jour Nette ou restez avec PHP 8.0.

Configuration des autorisations de répertoire

Si vous développez sous macOS ou Linux (ou tout autre système basé sur Unix), vous devez configurer les privilèges d'écriture sur le serveur web. En supposant 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 peut être activé par défaut. Vous devrez peut-être mettre à jour les stratégies SELinux, ou définir les chemins des répertoires temp et log avec le contexte de sécurité SELinux correct. Les répertoires temp et log doivent être définis avec le contexte httpd_sys_rw_content_t; pour le reste de l'application – principalement le dossier app – le contexte httpd_sys_content_t sera suffisant. Exécutez sur le serveur en tant que root :

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, le booléen SELinux httpd_can_network_connect_db doit être activé pour permettre à Nette de se connecter à la base de données sur le réseau. Par défaut, il est désactivé. La commande setsebool peut être utilisée pour effectuer cette tâche, et si l'option -P est spécifiée, ce paramètre sera persistant lors des redémarrages.

setsebool -P httpd_can_network_connect_db on

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

Le répertoire www/ utilisé dans les exemples de projets de Nette est le répertoire public ou la racine du document du projet. C'est le seul répertoire dont le contenu est accessible au navigateur. Il contient le fichier index.php, le point d'entrée qui permet de démarrer une application web écrite en Nette.

Pour exécuter l'application sur l'hébergement, vous devez définir le document-root sur ce répertoire dans la configuration de l'hébergement. Ou, si l'hébergement a un dossier prédéfini pour le répertoire public avec un nom différent (par exemple web, public_html etc.), renommez simplement www/.

La solution n'est pas d'empêcher l'accès à tous les dossiers sauf www/ en utilisant des règles dans le fichier .htaccess ou dans le routeur. Si votre hébergement ne permet pas de placer la racine du document dans un sous-répertoire (c'est-à-dire de créer des répertoires un niveau au-dessus du répertoire public), vous devriez chercher un autre service d'hébergement. Dans le cas contraire, vous vous exposeriez à des risques de sécurité importants. Ce serait comme vivre dans un appartement dont la porte d'entrée ne peut être fermée et reste toujours grande ouverte.

Comment configurer un serveur pour de belles URL ?

Apache : vous devez activer et définir 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, il se peut que vous deviez décommenter la ligne pour le paramètre RewriteBase et la définir sur le bon dossier.

nginx : la directive try_files doit être utilisée dans la configuration du serveur :

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

Le bloc location doit être défini exactement une fois pour chaque chemin du système de fichiers dans le bloc server. Si vous avez déjà un bloc location / dans votre configuration, ajoutez la directive try_files dans le bloc existant.

Tester si .htaccess fonctionne

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

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

Si vous ne voyez pas d'erreur Internal Server Error, votre configuration Apache ignore le fichier .htaccess. En général, Apache l'ignore à cause de la directive de configuration manquante AllowOverride All.

Si vous l'hébergez vous-même, c'est assez facile à résoudre. Ouvrez votre httpd.conf ou apache.conf dans un éditeur de texte, localisez la section correspondante et ajoutez/modifiez la directive. <Directory> et ajoutez/modifiez la directive :

<Directory "/var/www/htdocs"> # path to your document root
    AllowOverride All
    ...

Si votre site est hébergé ailleurs, vérifiez dans votre panneau de contrôle si vous pouvez activer .htaccess. Si ce n'est pas le cas, contactez votre hébergeur pour qu'il le fasse pour vous.

Tester si mod_rewrite est activé

Si vous avez vérifié que .htaccess fonctionne, vous pouvez vérifier que l'extension mod_rewrite est activée. Placez la ligne RewriteEngine On au début du fichier .htaccess et rafraîchissez la page dans votre navigateur. Si vous voyez une Internal Server Error, cela signifie que l'extension mod_rewrite n'est pas activée. Il existe plusieurs façons de l'activer. Consultez Stack Overflow pour connaître les différentes façons de procéder selon les configurations.

Nette génère des liens avec le même protocole que celui utilisé par la page actuelle. Ainsi, sur la page https://foo et vice versa. Si vous vous trouvez derrière un reverse proxy HTTPS (par exemple, dans Docker), vous devez mettre en place un proxy dans la configuration pour que la détection du protocole fonctionne correctement.

Si vous utilisez Nginx comme proxy, vous devez configurer la redirection de la manière suivante :

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-aplikace:80;  # IP ou nom d'hôte du serveur/conteneur où s'exécute l'application
}

Ensuite, vous devez spécifier le proxy IP et, le cas échéant, la plage IP de votre réseau local où vous exécutez l'infrastructure :

http:
	proxy: IP-proxy/IP-range

Utilisation des caractères { } en JavaScript

Les caractères { and } sont utilisés pour écrire les balises Latte. Tout ce qui suit (sauf l'espace et le guillemet) { character is considered a tag. If you need to print character { (souvent en JavaScript), vous pouvez mettre un espace (ou un autre caractère vide) juste après {. De cette façon, vous évitez de l'interpréter comme une balise.

S'il est nécessaire d'imprimer ces caractères dans une situation où ils seraient interprétés comme une balise, vous pouvez utiliser des balises spéciales pour imprimer ces caractères – {l} pour { and {r} pour }.

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

Remarque Presenter::getContext() is deprecated

Nette est de loin le premier framework PHP à avoir adopté l'injection de dépendances et à avoir incité les programmeurs à l'utiliser systématiquement, en commençant par les présentateurs. Si un présentateur a besoin d'une dépendance, il la demandera. En revanche, la façon dont nous passons l'ensemble du conteneur DI à une classe pour qu'elle en tire directement les dépendances est considérée comme un anti-modèle (cela s'appelle un localisateur de services). Cette méthode était utilisée dans Nette 0.x avant l'avènement de l'injection de dépendances, et sa relique est la méthode Presenter::getContext(), depuis longtemps marquée comme dépréciée.

Si vous portez une très vieille application Nette, vous découvrirez peut-être qu'elle utilise encore cette méthode. Ainsi, depuis la version 3.1 de nette/application vous rencontrerez l'avertissement Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, depuis la version 4.0 vous rencontrerez l'erreur que la méthode n'existe pas.

La solution propre, bien sûr, est de reconcevoir l'application pour passer les dépendances en utilisant l'injection de dépendances. Comme solution de rechange, vous pouvez ajouter votre propre méthode getContext() à votre présentateur de base et contourner le message :

abstract 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