Вирішення проблем

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($rootDir . '/log');
\Tracy\Debugger::log('hello');

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

Однією з найпоширеніших причин помилки 500 є застарілий кеш. У той час як Nette автоматично оновлює кеш у режимі розробки, у виробничому режимі він зосереджується на максимізації продуктивності, і очищення кешу після кожної модифікації коду залежить від вас. Спробуйте видалити temp/cache.

Помилка 404, маршрутизація не працює

Коли всі сторінки (крім головної) повертають помилку 404, це схоже на проблему конфігурації сервера для красивих URL-адрес.

Як відключити кеш під час розробки?

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

Під час налагодження роутера ми рекомендуємо вимкнути кеш браузера, де можуть зберігатися, наприклад, редиректи: відкрийте Інструменти розробника (Ctrl+Shift+I або Cmd+Option+I) і в панелі “Мережа” поставте галочку, щоб вимкнути кеш.

Помилка #[\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 на початок файлу і тепер, якщо ви оновите сторінку в браузері, ви побачите Внутрішня помилка сервера.

Якщо ви бачите цю помилку, це дуже добре! Це означає, що Apache аналізує файл .htaccess, і він зіткнувся з помилкою, яку ми туди вставили. Видаліть рядок Test.

Якщо ви не побачите Внутрішня помилка сервера, то ваші налаштування 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 і оновіть сторінку в браузері. Якщо ви побачите Внутрішня помилка сервера, це означає, що mod_rewrite не ввімкнено. Увімкнути його можна кількома способами. Див. розділ Переповнення стеку, де описано, як це можна зробити за різних налаштувань.

Nette генерує посилання з тим самим протоколом, який використовує поточна сторінка. Таким чином, на сторінці https://foo і навпаки. Якщо ви перебуваєте за 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