Rozwiązywanie problemów

Nie mogę uruchomić Nette, wyświetla białą stronę.

  • Spróbuj umieścić ini_set('display_errors', '1'); error_reporting(E_ALL); w pliku index.php zaraz po declare(strict_types=1);, to wymusi wyświetlanie błędów
  • Jeśli nadal widzisz biały ekran, prawdopodobnie wystąpił błąd w ustawieniach serwera i możesz znaleźć przyczynę w dzienniku serwera. Dla pewności sprawdź, czy PHP w ogóle działa, próbując wypisać coś za pomocą echo 'test';
  • Jeśli widzisz Błąd serwera: Przepraszamy! …, przejdź do następnej sekcji:

Error 500 Błąd serwera: Przepraszamy! …

Ta strona błędu jest wyświetlana przez Nette w trybie produkcyjnym. Jeśli zobaczysz ją na swoim komputerze deweloperskim, przełącz się na tryb deweloperski, a Tracy wyświetli szczegółowy raport.

Przyczynę błędu można zawsze znaleźć w katalogu log/. Jeśli jednak komunikat o błędzie zawiera frazę Tracy is unable to log error, należy najpierw ustalić, dlaczego błędy nie mogą być rejestrowane. Można to zrobić na przykład poprzez tymczasowe przełączenie do trybu deweloperskiego i zezwolenie Tracy na rejestrowanie wszystkiego po uruchomieniu:

// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // Twój adres IP
$configurator->enableTracy($appDir . '/log');
\Tracy\Debugger::log('hello');

Tracy poinformuje, dlaczego nie może rejestrować. Przyczyną mogą być niewystarczające uprawnienia do zapisu w katalogu log/.

Jedną z najczęstszych przyczyn błędu 500 jest nieaktualna pamięć podręczna. Podczas gdy Nette inteligentnie aktualizuje pamięć podręczną automatycznie w trybie deweloperskim, w trybie produkcyjnym koncentruje się na maksymalizacji wydajności, a czyszczenie pamięci podręcznej po każdej modyfikacji kodu zależy od Ciebie. Spróbuj usunąć temp/cache.

Błąd 404, routing nie działa

Kiedy wszystkie strony (oprócz strony głównej) zwracają błąd 404, wygląda to na problem z konfiguracją serwera dla ładnych adresów URL.

Jak wyłączyć pamięć podręczną podczas programowania?

Nette jest inteligentny i nie trzeba w nim wyłączać buforowania. Podczas programowania automatycznie aktualizuje pamięć podręczną za każdym razem, gdy nastąpi zmiana w szablonie lub konfiguracji kontenera DI. Co więcej, tryb deweloperski jest aktywowany przez automatyczne wykrywanie, więc zwykle nie ma potrzeby konfigurowania czegokolwiek lub tylko adresu IP.

Podczas debugowania routera zalecamy wyłączenie pamięci podręcznej przeglądarki, w której mogą być przechowywane na przykład przekierowania: otwórz Narzędzia deweloperskie (Ctrl+Shift+I lub Cmd+Option+I) i w panelu Sieć zaznacz pole, aby wyłączyć pamięć podręczną.

Błąd #[\ReturnTypeWillChange] attribute should be used

Ten błąd pojawia się, jeśli zaktualizowałeś PHP do wersji 8.1, ale używasz Nette, która nie jest z nim kompatybilna. Rozwiązaniem jest więc aktualizacja Nette do nowszej wersji za pomocą composer update. Nette wspiera PHP 8.1 od wersji 3.0. Jeśli używasz starszej wersji (możesz to sprawdzić zaglądając na stronę composer.json), zaktualizuj Nette lub pozostań przy PHP 8.0.

Ustawianie uprawnień do katalogów

Jeśli tworzysz na macOS lub Linuxie (lub innym systemie opartym na Uniksie), będziesz musiał ustawić uprawnienia do zapisu na serwerze WWW. Załóżmy, że twoja aplikacja znajduje się na domyślnym /var/www/html (Fedora, CentOS, RHEL).

cd /var/www/html/MY_PROJECT
chmod -R a+rw temp log

W niektórych systemach Linux (Fedora, CentOS, …) SELinux jest domyślnie włączony. Należy odpowiednio zmodyfikować polityki SELinux i ustawić właściwy kontekst bezpieczeństwa SELinux dla folderów temp i log. Dla temp i log ustaw typ kontekstu na httpd_sys_rw_content_t, dla reszty aplikacji (a zwłaszcza dla folderu app) wystarczy httpd_sys_content_t. Na serwerze należy uruchomić:

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/

Następnie musimy włączyć boolean SELinux httpd_can_network_connect_db, który jest domyślnie wyłączony i który pozwoli Nette połączyć się z bazą danych przez sieć. Wykorzystamy do tego polecenie setsebool i użyjemy opcji -P, aby zmiana była trwała, czyli nie będzie żadnych nieprzyjemnych niespodzianek po restarcie serwera:

setsebool -P httpd_can_network_connect_db on

Jak zmienić lub usunąć www z adresu URL ?

Katalog www/ używany w przykładowych projektach Nette jest katalogiem publicznym lub document-root projektu. Jest to jedyny katalog, którego zawartość jest dostępna dla przeglądarki. I zawiera plik index.php, punkt wejścia uruchamiający aplikację internetową napisaną w Nette.

Aby aplikacja działała na hostingu, należy w konfiguracji hostingu ustawić document-root na ten katalog. Lub, jeśli hosting ma przygotowany folder o innej nazwie dla katalogu publicznego (na przykład web, public_html, itp.), po prostu zmień nazwę www/.

Rozwiązaniem nie jest uniemożliwienie dostępu do wszystkich folderów z wyjątkiem www/ za pomocą reguł w pliku .htaccess lub w routerze. Jeśli twój hosting nie pozwala na ustawienie katalogu głównego dokumentu w podkatalogu (tj. tworzenie katalogów na poziomie wyższym niż katalog publiczny), powinieneś poszukać innej usługi hostingowej. W przeciwnym razie narazisz się na poważne zagrożenia bezpieczeństwa. Byłoby to jak mieszkanie w mieszkaniu, w którym drzwi wejściowe nie mogą być zamknięte i są zawsze szeroko otwarte.

Jak założyć serwer dla ładnych adresów URL?

Apache: należy włączyć i ustawić reguły mod_rewrite w pliku .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]

Jeśli napotkasz problemy, upewnij się, że:

Jeśli ustawiasz aplikację w podfolderze, być może będziesz musiał odkomentować linię dla ustawienia RewriteBase i ustawić ją na właściwy folder.

nginx: należy ustawić przekierowanie za pomocą dyrektywy try_files wewnątrz bloku location / w konfiguracji serwera.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args JEST WAŻNE!
}

Blok location może pojawić się tylko raz w bloku server dla każdej ścieżki systemu plików. Jeśli masz już w swojej konfiguracji location /, dodaj do niej dyrektywę try_files.

Sprawdź, czy .htaccess działa.

Najprostszym sposobem na sprawdzenie czy Apache używa lub ignoruje twój plik .htaccess jest jego celowe złamanie. Umieść linię Test na początku pliku i teraz, jeśli odświeżysz stronę w przeglądarce, powinieneś zobaczyć Internal Server Error.

Jeśli widzisz ten błąd, to właściwie dobrze! Oznacza to, że Apache przetwarza plik .htaccess i napotyka błąd, który tam umieściliśmy. Usuń linię Test.

Jeśli nie widzisz Internal Server Error, oznacza to, że twoja konfiguracja Apache'a ignoruje plik .htaccess. Ogólnie rzecz biorąc, Apache ignoruje go z powodu brakującej dyrektywy konfiguracyjnej AllowOverride All.

Jeśli sam hostujesz, łatwo to naprawić. Otwórz httpd.conf lub apache.conf w edytorze tekstu, znajdź odpowiednią sekcję <Directory> i dodaj/zmień dyrektywę:

<Directory "/var/www/htdocs"> # path to your document root
    AllowOverride All
    ...

Jeśli twoja witryna jest hostowana w innym miejscu, sprawdź w swoim panelu sterowania, czy możesz włączyć tam .htaccess. Jeśli nie, skontaktuj się z dostawcą usług hostingowych, aby zrobić to dla ciebie.

Sprawdź, czy mod_rewrite jest włączone.

Jeśli sprawdziłeś, że .htaccess działa, możesz sprawdzić, czy rozszerzenie mod_rewrite jest włączone. Umieść linię RewriteEngine On na początku pliku .htaccess i odśwież stronę w przeglądarce. Jeśli zobaczysz Internal Server Error, oznacza to, że mod_rewrite nie jest włączony. Istnieje wiele sposobów, aby go włączyć. Zobacz Stack Overflow, gdzie można to zrobić na różne sposoby w różnych konfiguracjach.

Nette generuje linki z tym samym protokołem co sama strona. W ten sposób na stronie https://foo i odwrotnie. Jeśli jesteś za odwrotnym proxy, które usuwa HTTPS (na przykład w Docker), to musisz ustawić proxy w konfiguracji, aby wykrywanie protokołu działało poprawnie.

Jeśli używasz Nginx jako proxy, musisz mieć ustawione przekierowanie w ten sposób:

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 nebo hostname serveru/kontejneru, kde běží aplikace
}

Musisz również określić IP proxy i, jeśli dotyczy, zakres IP sieci lokalnej, w której uruchamiasz infrastrukturę:

http:
	proxy: IP-proxy/IP-range

Używanie znaków { } w JavaScript

Znaki { a } służą do pisania znaczników Latte. Wszystko co następuje po znaku { s výjimkou mezery a uvozovky. Pokud tedy potřebujete vypsat přímo znak { jest brane jako znacznik (często np. w JavaScript), można umieścić spację (lub inny pusty znak) po znaku {. Pozwala to uniknąć tłumaczenia go jako tagu.

Jeśli musisz wyprowadzić te znaki w sytuacji, w której tekst byłby rozumiany jako znacznik, możesz użyć specjalnych znaczników do wyprowadzenia tych znaków – {l} dla { a {r} dla }.

{je značka}
{ není značka }
{l}není značka{r}

Wiadomość Presenter::getContext() is deprecated

Nette jest zdecydowanie pierwszym frameworkiem PHP, który przeszedł na wstrzykiwanie zależności i doprowadził programistów do konsekwentnego używania go, od samych prezenterów. Jeśli prezenter potrzebuje zależności, będzie się o nią upominał. Z drugiej strony sposób, w którym przekazujemy cały kontener DI do klasy, a ona bezpośrednio wyciąga z niego zależności, jest uważany za antipattern (nazywa się to service locator). Ten sposób był używany w Nette 0.x przed pojawieniem się dependency injection, a jego pozostałością jest metoda Presenter::getContext(), dawno temu oznaczona jako deprecated.

Jeśli przeportujesz bardzo starą aplikację do Nette, może się okazać, że nadal używa ona tej metody. Tak więc od wersji 3.1 nette/application napotkasz ostrzeżenie Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, od wersji 4.0 napotkasz błąd, że metoda nie istnieje.

Czystym rozwiązaniem jest oczywiście przebudowa aplikacji, aby przekazać zależności za pomocą zastrzyku zależności. Jako obejście, możesz dodać własną metodę getContext() do swojego prezentera bazowego i obejść komunikat:

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;
	}
}
wersja: 4.0