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

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

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

Ошибка 500 Ошибка сервера: We're sorry! …

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

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

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

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

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

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

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

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

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

При отладке маршрутизатора рекомендуется отключить кэш браузера, в котором, например, могут храниться редиректы: откройте Developer Tools (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 или установить пути к каталогам temp и log с правильным контекстом безопасности SELinux. Каталоги temp и log должны быть установлены в контекст httpd_sys_rw_content_t; для остальной части приложения — в основном папки app — контекста httpd_sys_content_t будет достаточно. Запустите на сервере перечисленные команды от имени 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/

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

setsebool -P httpd_can_network_connect_db on

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

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

Чтобы запустить приложение на хостинге, необходимо в конфигурации хостинга установить document-root в эту директорию. Или, если на хостинге есть готовая папка для публичного каталога с другим именем (например, web, public_html и т.д.), просто переименуйте www/.

Решение не заключается в том, чтобы запретить доступ ко всем папкам, кроме www/, с помощью правил в файле .htaccess или в маршрутизаторе. Если ваш хостинг не позволяет устанавливать корень документа в подкаталог (т. е. создавать каталоги на уровень выше публичного каталога), вам следует поискать другой хостинг. В противном случае вы подвергаете себя значительным рискам безопасности. Это все равно что жить в квартире, где входная дверь не закрывается и всегда нараспашку.

Как настроить сервер для красивых 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 / {
	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"> # path to your document root
    AllowOverride All
    ...

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

Проверьте, включен ли mod_rewrite

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

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

Если вы используете 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} для }.

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

Уведомление Presenter::getContext() is deprecated

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

Если вы портируете очень старое приложение Nette, вы можете обнаружить, что оно все еще использует этот метод. Таким образом, начиная с версии 3.1 nette/application вы столкнетесь с предупреждением 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