Odpravljanje težav

Nette ne deluje, prikazana je bela stran

  • Poskusite v datoteko index.php za declare(strict_types=1); vstaviti ini_set('display_errors', '1'); error_reporting(E_ALL);, da bi izsilili prikaz napak.
  • Če se še vedno prikazuje bel zaslon, je verjetno prišlo do napake v nastavitvah strežnika, razlog pa boste odkrili v dnevniku strežnika. Če želite biti prepričani, preverite, ali PHP sploh deluje, tako da poskusite nekaj natisniti z uporabo echo 'test';.
  • Če se prikaže napaka Server Error: Spoštovani! …, nadaljujte z naslednjim razdelkom:

Napaka 500 * Napaka strežnika: Opravičujemo se! …*

To stran z napako prikaže Nette v produkcijskem načinu. Če jo vidite v razvojnem računalniku, preklopite v način za razvijalce in Tracy bo prikazal podrobno poročilo.

Razlog za napako lahko vedno najdete v imeniku log/. Če pa je v sporočilu o napaki prikazan stavek Tracy is unable to log error, najprej ugotovite, zakaj napak ni mogoče zabeležiti. To lahko storite na primer tako, da začasno preklopite v razvijalski način in pustite, da Tracy po svojem zagonu zabeleži vse, kar se zgodi:

// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // vaš naslov IP.
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');

Tracy vas bo obvestil, zakaj ne more beležiti napak. Vzrok je morda nezadostna dovoljenja za pisanje v imenik log/.

Eden najpogostejših razlogov za napako 500 je zastarel predpomnilnik. Medtem ko Nette v razvojnem načinu pametno samodejno posodablja predpomnilnik, se v produkcijskem načinu osredotoča na čim večjo zmogljivost, čiščenje predpomnilnika po vsaki spremembi kode pa je odvisno od vas. Poskusite izbrisati temp/cache.

Napaka 404, usmerjanje ne deluje

Če vse strani (razen domače strani) vrnejo napako 404, je videti, da gre za težavo s konfiguracijo strežnika za lepe naslove URL.

Kako onemogočiti predpomnilnik med razvojem?

Nette je pameten in v njem vam ni treba onemogočiti predpomnjenja. Med razvojem samodejno posodablja predpomnilnik, kadar koli se spremeni predlogo ali konfiguracija vsebnika DI. Poleg tega se razvojni način aktivira s samodejnim zaznavanjem, zato običajno ni treba nastavljati ničesar ali le naslova IP.

Pri odpravljanju napak v usmerjevalniku priporočamo, da onemogočite predpomnilnik brskalnika, v katerem so na primer lahko shranjene preusmeritve: odprite Razvojna orodja (Ctrl+Shift+I ali Cmd+Option+I) in na plošči Omrežje označite polje za onemogočanje predpomnilnika.

Napaka #[\ReturnTypeWillChange] attribute should be used

Ta napaka se pojavi, če ste PHP nadgradili na različico 8.1, vendar uporabljate Nette, ki z njo ni združljiv. Rešitev je, da Nette posodobite na novejšo različico z uporabo composer update. Nette podpira PHP 8.1 od različice 3.0. Če uporabljate starejšo različico (to lahko ugotovite z vpogledom v composer.json), nadgradite Nette ali pa ostanite pri PHP 8.0.

Nastavitev dovoljenj za imenik

Če razvijate v operacijskem sistemu MacOS ali Linux (ali katerem koli drugem sistemu, ki temelji na Unixu), morate nastaviti pravice za pisanje v spletni strežnik. Ob predpostavki, da se vaša aplikacija nahaja v privzetem imeniku /var/www/html (Fedora, CentOS, RHEL)

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

V nekaterih sistemih Linux (Fedora, CentOS, …) je lahko SELinux privzeto omogočen. Morda boste morali posodobiti politike SELinuxa ali nastaviti poti do imenikov temp in log s pravilnim varnostnim kontekstom SELinuxa. Direktorja temp in log je treba nastaviti na kontekst httpd_sys_rw_content_t; za preostalo aplikacijo – predvsem mapo app – bo zadostoval kontekst httpd_sys_content_t. V strežniku zaženite kot 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/

Nato je treba omogočiti SELinuxov boolean httpd_can_network_connect_db, da se Nette lahko poveže s podatkovno bazo prek omrežja. Privzeto je onemogočen. Za izvedbo tega opravila lahko uporabite ukaz setsebool, in če je navedena možnost -P, bo ta nastavitev obstojna med ponovnimi zagoni.

setsebool -P httpd_can_network_connect_db on

Kako spremeniti ali odstraniti imenik www z naslova URL?

Imenik www/, ki se uporablja v vzorčnih projektih v Nette, je tako imenovani javni imenik ali dokumentni koren projekta. To je edini imenik, katerega vsebina je dostopna brskalniku. Vsebuje pa tudi datoteko index.php, vstopno točko, ki zažene spletno aplikacijo, napisano v programu Nette.

Če želite zagnati aplikacijo na gostovanju, morate v konfiguraciji gostovanja nastaviti document-root na ta imenik. Če pa ima gostovanje vnaprej pripravljeno mapo za javni imenik z drugačnim imenom (na primer web, public_html itd.), preprosto preimenujte www/.

Rešitev ni** preprečevanje dostopa do vseh map razen www/ s pravili v datoteki .htaccess ali v usmerjevalniku. Če vaše gostovanje ne dovoljuje nastavitve korena dokumenta v podimenik (tj. ustvarjanja imenikov eno raven nad javnim imenikom), morate poiskati drugo storitev gostovanja. V nasprotnem primeru bi se izpostavili velikim varnostnim tveganjem. To bi bilo tako, kot če bi živeli v stanovanju, kjer vhodnih vrat ni mogoče zapreti in so vedno na široko odprta.

Kako konfigurirati strežnik za lepe naslove URL?

Apache: v datoteki .htaccess morate omogočiti in nastaviti pravila mod_rewrite:

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]

Če naletite na težave, se prepričajte, da:

Če aplikacijo nastavljate v podmapi, boste morda morali odkomentirati vrstico za nastavitev RewriteBase in jo nastaviti na pravo mapo.

nginx: v konfiguraciji strežnika je treba uporabiti direktivo try_files:

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args JE POMEMBNO!
}

Blok location mora biti opredeljen natanko enkrat za vsako pot do datotečnega sistema v bloku server. Če v konfiguraciji že imate blok location /, dodajte direktivo try_files v obstoječi blok.

Preizkusite, ali .htaccess deluje

Najpreprostejši način za preverjanje, ali Apache uporablja ali ignorira vašo datoteko .htaccess, je, da jo namerno prekinete. Na začetek datoteke postavite vrstico Test in če zdaj v brskalniku osvežite stran, se bo prikazala Internal Server Error (notranja napaka strežnika).

Če vidite to napako, je to pravzaprav dobro! To pomeni, da Apache analizira datoteko .htaccess in naleti na napako, ki smo jo vstavili vanjo. Odstranite vrstico Test.

Če ne vidite Internal Server Error, vaša namestitev Apache ignorira datoteko .htaccess. Na splošno jo Apache ignorira zaradi manjkajoče konfiguracijske direktive AllowOverride All.

Če gostujete sami, je to dovolj enostavno popraviti. V urejevalniku besedila odprite httpd.conf ali apache.conf in poiščite ustrezno <Directory> razdelek in dodajte/spremenite direktivo:

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

Če vaše spletno mesto gostuje drugje, preverite nadzorno ploščo in preverite, ali lahko tam omogočite .htaccess. Če ne, se obrnite na ponudnika gostovanja, da to stori namesto vas.

Preizkusite, ali je omogočena stran mod_rewrite

Če ste preverili, da .htaccess deluje, lahko preverite, ali je omogočena razširitev mod_rewrite. Na začetek datoteke .htaccess vstavite vrstico RewriteEngine On in osvežite stran v brskalniku. Če se prikaže Internal Server Error, to pomeni, da razširitev mod_rewrite ni omogočena. Obstaja več načinov, kako ga omogočiti. V Stack Overflow si oglejte različne načine, na katere je to mogoče storiti pri različnih nastavitvah.

Nette generira povezave z enakim protokolom, kot ga uporablja trenutna stran. Tako na strani https://foo, in obratno. Če se nahajate za povratnim posredniškim strežnikom, ki odvzema protokol HTTPS (na primer v programu Docker), morate v konfiguraciji nastaviti posredniški strežnik, da bo zaznavanje protokola delovalo pravilno.

Če kot posrednik uporabljate Nginx, morate preusmeritev nastaviti na naslednji način:

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 or hostname of the server/container where the application is running
}

Nato morate določiti posrednika IP in po potrebi območje IP lokalnega omrežja, v katerem izvajate infrastrukturo:

http:
	proxy: IP-proxy/IP-range

Uporaba znakov { } v jeziku JavaScript

Znaki { and } se uporabljajo za pisanje oznak Latte. Vse (razen presledka in narekovajev), ki sledijo { character is considered a tag. If you need to print character { (pogosto v javascriptu), lahko takoj za { postavite presledek (ali drug prazen znak). S tem se izognete interpretaciji kot oznake.

Če je treba te znake izpisati v situaciji, ko bi se razlagali kot oznaka, lahko za izpis teh znakov uporabite posebne oznake – {l} za { and {r} za }.

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

Obvestilo Presenter::getContext() is deprecated

Nette je daleč prvo ogrodje PHP, ki je prešlo na vbrizgavanje odvisnosti in programerje spodbudilo k njegovi dosledni uporabi, začenši s predavatelji. Če predstavnik potrebuje odvisnost, bo zanjo zaprosil. Nasprotno pa način, ko celoten vsebnik DI posredujemo razredu, ta pa iz njega neposredno potegne odvisnosti, velja za antivzorec (imenuje se iskalnik storitev). Ta način se je uporabljal v različici Nette 0.x pred pojavom vbrizgavanja odvisnosti, njegov ostanek pa je metoda Presenter::getContext(), ki je že zdavnaj označena kot zastarela.

Če prenesete zelo staro aplikacijo Nette, boste morda ugotovili, da še vedno uporablja to metodo. Tako boste od različice 3.1 nette/application naleteli na opozorilo Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection, od različice 4.0 pa na napako, da metoda ne obstaja.

Čista rešitev je seveda ta, da aplikacijo preoblikujete tako, da bo odvisnosti posredovala z uporabo vbrizgavanja odvisnosti. Kot obvoznico lahko osnovnemu predstavniku dodate svojo metodo getContext() in tako zaobidete sporočilo:

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;
	}
}
različica: 4.0