Решение проблем
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 is unable to log error
, выясните,
почему ошибки не могут быть зарегистрированы. Это можно сделать,
например, переключившись в
режим разработчика и вызвав Tracy\Debugger::log('hello');
после
$configurator->enableTracy(...)
. Трейси расскажет вам, почему он не может
вести журнал. Обычно причиной является недостаточные разрешения для записи в
каталог log/
.
Если фраза Tracy is unable to log error
отсутствует в сообщении об ошибке
(больше нет), вы можете узнать причину ошибки в журнале в директории
log/
.
Одна из наиболее распространенных причин – устаревший кэш. В то
время как Nette умно автоматически обновляет кэш в режиме разработки, в
производственном режиме он сосредоточен на максимизации
производительности, и очистка кэша после каждой модификации кода
зависит от вас. Попробуйте удалить temp/cache
.
Ошибка
#[\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
или в роутере. Если хостинг не
позволяет вам установить 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]
Чтобы изменить конфигурацию Apache с помощью файлов .htaccess, необходимо включить директиву AllowOverride. Это поведение по умолчанию для Apache.
nginx: директива try_files
должна использоваться в конфигурации
сервера:
location / {
try_files $uri $uri/ /index.php$is_args$args; # $is_args$args важно
}
Блок location
должен быть определен ровно один раз для каждого
пути к файловой системе в блоке server
. Если в вашей конфигурации
уже есть блок location /
, добавьте директиву try_files
в
существующий блок.
Ссылки генерируются без https:
.
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;
}
}