Nette Documentation Preview

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


Nette не работает, отображается белая страница .[#toc-nette-is-not-working-white-page-is-displayed]
---------------------------------------------------------------------------------------------------
- Попробуйте поставить `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! ...* .[#toc-error-500-server-error-we-re-sorry]
----------------------------------------------------------------------------------------
Эта страница ошибки отображается Nette в производственном режиме. Если вы видите ее на машине разработчика, [переключитесь в режим разработчика |application:bootstrap#Development-vs-Production-Mode].

Если сообщение об ошибке содержит `Tracy is unable to log error`, выясните, почему ошибки не могут быть зарегистрированы. Это можно сделать, например, [переключившись |application:bootstrap#Development-vs-Production-Mode] в режим разработчика и вызвав `Tracy\Debugger::log('hello');` после `$configurator->enableTracy(...)`. Трейси расскажет вам, почему он не может вести журнал.
Обычно причиной является [недостаточные разрешения |#Setting-Directory-Permissions] для записи в каталог `log/`.

Если фраза `Tracy is unable to log error` отсутствует в сообщении об ошибке (больше нет), вы можете узнать причину ошибки в журнале в директории `log/`.

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


Ошибка `#[\ReturnTypeWillChange] attribute should be used` .[#toc-error-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.


Установка прав доступа к каталогам .[#toc-setting-directory-permissions]
------------------------------------------------------------------------
Если вы разрабатываете на 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 или установить пути к каталогам `temp` и `log` с правильным контекстом безопасности SELinux. Каталоги `temp` и `log` должны быть установлены в контекст `httpd_sys_rw_content_t`; для остальной части приложения — в основном папки `app` — контекста `httpd_sys_content_t` будет достаточно. Запустите на сервере перечисленные команды от имени root:

```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? .[#toc-how-to-change-or-remove-www-directory-from-url]
-----------------------------------------------------------------------------------------------------
Директория `www/`, используемая в примерах проектов в Nette, является так называемой публичной директорией или корнем проекта. Это единственный каталог, содержимое которого доступно браузеру. В нем находится файл `index.php` - точка входа, с которой начинается веб-приложение, написанное на Nette.

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

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


Как настроить сервер для красивых URL? .[#toc-how-to-configure-a-server-for-nice-urls]
--------------------------------------------------------------------------------------
**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]
```

Чтобы изменить конфигурацию Apache с помощью файлов .htaccess, необходимо включить директиву AllowOverride. Это поведение по умолчанию для Apache.

**nginx**: директива `try_files` должна использоваться в конфигурации сервера:

```nginx
location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args важно
}
```

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


Ссылки генерируются без `https:`. .[#toc-links-are-generated-without-https]
---------------------------------------------------------------------------
Nette генерирует ссылки с тем же протоколом, который использует текущая страница. Таким образом, на странице `https://foo` генерируются ссылки, начинающиеся с `https:` и наоборот.
Если вы находитесь за HTTPS-стриминговым обратным прокси (например, в Docker), то вам нужно [set up a proxy|http:configuration#HTTP-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 диапазон вашей локальной сети, где вы запускаете инфраструктуру:

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


Использование символов { } в JavaScript .[#toc-use-of-characters-in-javascript]
-------------------------------------------------------------------------------
Символы `{` и `}` используются для записи тегов Latte. Всё (кроме пробела и кавычек), следующее за символом `{`, считается тегом. Если вам нужно вывести символ `{` (часто встречается в JavaScript), вы можете поставить пробел (или другой пустой символ) сразу после `{`. Таким образом вы избежите интерпретации его как метки.

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

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


Уведомление `Presenter::getContext() is deprecated` .[#toc-notice-presenter-getcontext-is-deprecated]
-----------------------------------------------------------------------------------------------------

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

```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 не работает, отображается белая страница

  • Попробуйте поставить 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 в существующий блок.

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