Решение проблем

Nette не работает, отображается белая страница

  • Попробуйте в файл index.php сразу после declare(strict_types=1); вставить ini_set('display_errors', '1'); error_reporting(E_ALL);, это принудительно включит отображение ошибок.
  • Если вы по-прежнему видите белый экран, вероятно, проблема в настройках сервера, и причину можно найти в логе сервера. На всякий случай проверьте, работает ли вообще PHP, попробовав что-нибудь вывести с помощью echo 'test';
  • Если вы видите ошибку Server Error: We're sorry! …, перейдите к следующему разделу:

Ошибка 500 Server Error: We're sorry! …

Эту страницу ошибки отображает Nette в производственном режиме. Если она отображается на вашем компьютере разработчика, переключитесь в режим разработки, и вам отобразится Tracy с подробным сообщением.

Причину ошибки всегда можно найти в логе в каталоге log/. Однако, если в сообщении об ошибке появляется фраза Tracy is unable to log error, сначала выясните, почему ошибки не могут быть залогированы. Сделать это можно, например, временно переключившись в режим разработки и позволив Tracy что-нибудь залогировать после ее запуска:

// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // ваш IP-адрес
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');

Tracy сообщит вам, почему она не может логировать. Причиной могут быть недостаточные права на запись в каталог log/.

Одной из наиболее частых причин ошибки 500 является устаревший кеш. В то время как Nette в режиме разработки умно автоматически обновляет кеш, в производственном режиме он фокусируется на максимизации производительности, и очистка кеша после каждого изменения кода — ваша задача. Попробуйте удалить temp/cache.

Ошибка 404, не работает маршрутизация

Если все страницы (кроме главной) возвращают ошибку 404, похоже, проблема с конфигурацией сервера для красивых URL.

Изменения в шаблонах или конфигурации не отображаются

“Я изменил шаблон или конфигурацию, но сайт по-прежнему отображает старую версию.” Такое поведение происходит в производственном режиме, который из соображений производительности не проверяет изменения в файлах и сохраняет однажды сгенерированный кеш.

Чтобы не приходилось на производственном сервере после каждого изменения вручную удалять кеш, включите режим разработки для вашего IP-адреса в файле Bootstrap.php:

$configurator->setDebugMode('ваш IP-адрес');

Как отключить кеш во время разработки?

Nette умный, и вам не нужно отключать в нем кеширование. Во время разработки он автоматически обновляет кеш при каждом изменении шаблона или конфигурации DI-контейнера. Режим разработки к тому же включается автоопределением, поэтому обычно не нужно ничего настраивать, или только IP-адрес.

При отладке маршрутизатора рекомендуем отключить кеш в браузере, в котором могут быть сохранены, например, перенаправления: откройте Инструменты разработчика (Ctrl+Shift+I или Cmd+Option+I) и на панели Network (Сеть) отметьте отключение кеша.

Ошибка #[\ReturnTypeWillChange] attribute should be used

Эта ошибка появляется, если вы обновили PHP до версии 8.1, но используете Nette, которая с ней не совместима. Решением является обновление Nette до более новой версии с помощью composer update. Nette поддерживает PHP 8.1 начиная с версии 3.0. Если вы используете более старую версию (узнать можно, посмотрев в composer.json), обновите Nette или оставайтесь на PHP 8.0.

Настройка прав доступа к каталогам

Если вы разрабатываете на macOS или Linux (или на любой другой системе на базе Unix), вам нужно будет настроить права на запись для веб-сервера. Предположим, ваше приложение находится в стандартном /var/www/html (Fedora, CentOS, RHEL).

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

На некоторых дистрибутивах Linux (Fedora, CentOS, …) по умолчанию включен SELinux. Вам нужно будет соответствующим образом изменить политики SELinux и установить правильный контекст безопасности SELinux для папок temp и log. Для temp и log установим тип контекста httpd_sys_rw_content_t, для остальной части приложения (и особенно для папки app) будет достаточно httpd_sys_content_t. На сервере выполните:

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/

Далее необходимо включить булево значение SELinux httpd_can_network_connect_db, которое по умолчанию отключено и которое позволит Nette подключаться к базе данных по сети. Для этого используем команду setsebool и с опцией -P сделаем изменение постоянным, т.е. после перезагрузки сервера нас не будет ждать неприятный сюрприз:

setsebool -P httpd_can_network_connect_db on

Как изменить или удалить каталог www из URL?

Каталог www/, используемый в примерах проектов в Nette, представляет собой так называемый публичный каталог или document-root проекта. Это единственный каталог, содержимое которого доступно браузеру. И он содержит файл index.php, входную точку, которая запускает веб-приложение, написанное на Nette.

Для запуска приложения на хостинге необходимо правильно настроить document-root. У вас есть два варианта:

  1. В конфигурации хостинга установить document-root на этот каталог.
  2. Если у хостинга есть предустановленная папка (например, public_html), переименуйте www/ в это название.

Никогда не пытайтесь решать вопросы безопасности только с помощью .htaccess или маршрутизатора, которые бы запрещали доступ к другим папкам.

Если хостинг не позволяет установить document-root в подкаталог (т.е. создавать каталоги на уровень выше публичного каталога), поищите другой. В противном случае вы подвергнетесь значительному риску безопасности. Это было бы как жить в квартире, где входная дверь не закрывается и всегда нараспашку.

Как настроить сервер для красивых URL?

Apache: необходимо включить и настроить правила mod_rewrite в файле .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]

Если возникнут проблемы, убедитесь, что:

Если вы настраиваете приложение в подкаталоге, возможно, вам придется раскомментировать строку для настройки RewriteBase и установить ее на правильную папку.

nginx: необходимо настроить перенаправление с помощью директивы try_files внутри блока location / в конфигурации сервера.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args ВАЖНО!
}

Блок location для каждого пути файловой системы может встречаться в блоке server только один раз. Если у вас уже есть location / в конфигурации, добавьте директиву try_files в него.

Проверка работы .htaccess

Самый простой способ проверить, использует или игнорирует Apache ваш файл .htaccess, — это намеренно его повредить. Вставьте в начало файла строку Test и теперь, если вы обновите страницу в браузере, вы должны увидеть Internal Server Error.

Если вы видите эту ошибку, это на самом деле хорошо! Это означает, что Apache анализирует файл .htaccess и натыкается на ошибку, которую мы туда вставили. Удалите строку Test.

Если Internal Server Error не отображается, ваша настройка Apache игнорирует файл .htaccess. Обычно Apache игнорирует его из-за отсутствующей конфигурационной директивы AllowOverride All.

Если вы хостите его сами, это легко исправить. Откройте файл httpd.conf или apache.conf в текстовом редакторе, найдите соответствующий раздел <Directory> и добавьте/измените эту директиву:

<Directory "/var/www/htdocs"> # путь к вашему document root
    AllowOverride All
    ...

Если ваш сайт размещен в другом месте, посмотрите в панели управления, можете ли вы там включить файл .htaccess. Если нет, обратитесь к своему хостинг-провайдеру, чтобы он сделал это за вас.

Проверка включения mod_rewrite

Если вы убедились, что работает .htaccess, вы можете проверить, включено ли расширение mod_rewrite. Вставьте в начало файла .htaccess строку RewriteEngine On и обновите страницу в браузере. Если отображается Internal Server Error, это означает, что mod_rewrite не включен. Существует несколько способов его включить. Различные способы, как это можно сделать в разных настройках, можно найти на Stack Overflow.

Ссылки генерируются без https:

Nette генерирует ссылки с тем же протоколом, что и сама страница. То есть на странице https://foo генерирует ссылки, начинающиеся с https:, и наоборот. Если вы находитесь за обратным прокси-сервером, который удаляет HTTPS (например, в Docker), то необходимо в конфигурации настроить прокси, чтобы определение протокола работало правильно.

Если вы используете Nginx в качестве прокси, необходимо настроить перенаправление, например, так:

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 или имя хоста сервера/контейнера, где работает приложение
}

Далее необходимо в конфигурацию указать IP прокси и, при необходимости, IP-диапазон вашей локальной сети, где вы разворачиваете инфраструктуру:

http:
	proxy: IP-proxy/IP-range

Использование символов { } в JavaScript

Символы { и } используются для записи тегов Latte. Тегом считается все, что следует за символом {, за исключением пробела и кавычки. Поэтому, если вам нужно вывести непосредственно символ { (часто, например, в JavaScript), вы можете после символа { поставить пробел (или другой пустой символ). Таким образом, вы избежите интерпретации как тега.

Если необходимо вывести эти символы в ситуации, когда текст мог бы быть воспринят как тег, вы можете использовать специальные теги для вывода этих символов – {l} для { и {r} для }.

{это тег}
{ это не тег }
{l}это не тег{r}

Сообщение Presenter::getContext() is deprecated

Nette является, безусловно, первым PHP-фреймворком, который перешел на внедрение зависимостей и побуждал программистов к его последовательному использованию, начиная с самих презентеров. Если презентеру нужна какая-то зависимость, он заявляет о ней. Напротив, подход, когда в класс передается весь DI-контейнер, и он сам извлекает из него зависимости, считается антипаттерном (называется service locator). Этот способ использовался в Nette 0.x еще до появления внедрения зависимостей, и его пережитком является метод Presenter::getContext(), давно помеченный как устаревший (deprecated).

Если вы портируете очень старое приложение для Nette, вы можете столкнуться с тем, что оно все еще использует этот метод. Начиная с версии nette/application 3.1, вы столкнетесь с предупреждением Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, а с версии 4.0 — с ошибкой, что метод не существует.

Чистым решением, разумеется, является переделка приложения таким образом, чтобы зависимости передавались с помощью внедрения зависимостей. В качестве обходного пути вы можете добавить в свой базовый презентер собственный метод getContext() и таким образом обойти сообщение:

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;
	}
}
версия: 4.0