Nette Documentation Preview

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


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 в производственном режиме. Если она отображается на вашем компьютере разработчика, [переключитесь в режим разработки |application:bootstrapping#Режим разработки vs режим production], и вам отобразится Tracy с подробным сообщением.

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

```php
// 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 |#Как настроить сервер для красивых URL].


Изменения в шаблонах или конфигурации не отображаются
-----------------------------------------------------
"Я изменил шаблон или конфигурацию, но сайт по-прежнему отображает старую версию." Такое поведение происходит в [производственном режиме |application:bootstrapping#Режим разработки vs режим production], который из соображений производительности не проверяет изменения в файлах и сохраняет однажды сгенерированный кеш.

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

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


Как отключить кеш во время разработки?
--------------------------------------
Nette умный, и вам не нужно отключать в нем кеширование. Во время разработки он автоматически обновляет кеш при каждом изменении шаблона или конфигурации DI-контейнера. Режим разработки к тому же включается автоопределением, поэтому обычно не нужно ничего настраивать, [или только IP-адрес |application:bootstrapping#Режим разработки vs режим production].

При отладке маршрутизатора рекомендуем отключить кеш в браузере, в котором могут быть сохранены, например, перенаправления: откройте Инструменты разработчика (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 |migrations:en] или оставайтесь на PHP 8.0.


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

```shell
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`. На сервере выполните:

```shell
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` сделаем изменение постоянным, т.е. после перезагрузки сервера нас не будет ждать неприятный сюрприз:

```shell
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/` в это название.

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

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


Как настроить сервер для красивых URL?
--------------------------------------
**Apache**: необходимо включить и настроить правила mod_rewrite в файле `.htaccess`:

```apacheconf
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]
```

Если возникнут проблемы, убедитесь, что:
- файл `.htaccess` находится в каталоге document-root (то есть рядом с файлом `index.php`)
- [Apache обрабатывает файлы `.htaccess` |#Проверка работы .htaccess]
- [включен mod_rewrite |#Проверка включения mod rewrite]

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

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

```nginx
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>` и добавьте/измените эту директиву:

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

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


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


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

Если вы используете 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-диапазон вашей локальной сети, где вы разворачиваете инфраструктуру:

```neon
http:
	proxy: IP-proxy/IP-range
```


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

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

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


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

Nette является, безусловно, первым PHP-фреймворком, который перешел на внедрение зависимостей и побуждал программистов к его последовательному использованию, начиная с самих презентеров. Если презентеру нужна какая-то зависимость, он [заявляет о ней|dependency-injection:passing-dependencies]. Напротив, подход, когда в класс передается весь 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()` и таким образом обойти сообщение:

```php
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;
	}
}
```


{{leftbar: www:@menu-common}}

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

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;
	}
}