Nette Documentation Preview

syntax
Sorun Giderme
*************


Nette Çalışmıyor, Beyaz Sayfa Görünüyor
---------------------------------------
- Hataların gösterilmesini zorlamak için `index.php` dosyasında `declare(strict_types=1);` satırından sonra `ini_set('display_errors', '1'); error_reporting(E_ALL);` yazmayı deneyin.
- Hâlâ beyaz ekran görüyorsanız, muhtemelen sunucu yapılandırmasında bir hata vardır ve nedenini sunucu günlüğünde bulacaksınız. Emin olmak için `echo 'test';` ile bir şey yazdırmayı deneyerek PHP'nin hiç çalışıp çalışmadığını denetleyin.
- *Server Error: We're sorry! …* hatasını görüyorsanız, bir sonraki bölümle devam edin:


Hata 500 *Server Error: We're sorry! …*
---------------------------------------
Bu hata sayfasını Nette üretim kipinde gösterir. Onu geliştirme makinenizde görüyorsanız, [geliştirici kipine geçin |application:bootstrapping#Geliştirme modu ve üretim modu]; Tracy ayrıntılı bir rapor gösterecek.

Hatanın nedenini her zaman `log/` dizinindeki günlükte bulabilirsiniz. Ancak hata mesajında `Tracy is unable to log error` ifadesi geçiyorsa, önce hataların neden günlüklenemediğini saptayın. Bunu örneğin geçici olarak geliştirici kipine [geçip |application:bootstrapping#Geliştirme modu ve üretim modu] Tracy'yi başladıktan sonra bir şey günlüklemeye bırakarak yapabilirsiniz:

```php
// Bootstrap.php
$configurator->setDebugMode('23.75.345.200'); // sizin IP adresiniz
$configurator->enableTracy($rootDir . '/log');
\Tracy\Debugger::log('hello');
```

Tracy size neden günlükleyemediğini söyleyecek. Nedeni, `log/` dizinine yazmak için [yetersiz izinler |#Dizin İzinlerini Ayarlama] olabilir.

500 hatasının en sık nedenlerinden biri eskimiş önbellektir. Nette, geliştirme kipinde önbelleği akıllıca otomatik güncellerken, üretim kipinde başarımı en üst düzeye çıkarmaya odaklanır ve her kod değişikliğinden sonra önbelleği temizlemek sizin sorumluluğunuzdadır. `temp/cache` dizinini silmeyi deneyin.


Hata 404, Yönlendirme Çalışmıyor
--------------------------------
Tüm sayfalar (ana sayfa dışında) 404 hatası döndürüyorsa, bu [güzel URL'ler |#Güzel URL'ler İçin Sunucu Nasıl Yapılandırılır?] için bir sunucu yapılandırma sorununa benziyor.


Şablonlardaki ya da Yapılandırmadaki Değişiklikler Yansımıyor
-------------------------------------------------------------
"Şablonu ya da yapılandırmayı değiştirdim, ama web sitesi hâlâ eski sürümü gösteriyor." Bu davranış, başarım nedeniyle dosya değişikliklerini denetlemeyen ve daha önce üretilmiş önbelleği koruyan [üretim kipinde |application:bootstrapping#Geliştirme modu ve üretim modu] ortaya çıkar.

Üretim sunucusunda her değişiklikten sonra önbelleği elle temizlemekten kaçınmak için, `Bootstrap.php` dosyasında kendi IP adresiniz için geliştirme kipini etkinleştirin:

```php
$this->configurator->setDebugMode('sizin.ip.adresiniz');
```


Geliştirme Sırasında Önbellek Nasıl Kapatılır?
----------------------------------------------
Nette akıllıdır ve onda önbelleğe almayı kapatmanıza gerek yoktur. Geliştirme sırasında, şablonda ya da DI container yapılandırmasında bir değişiklik olduğunda önbelleği otomatik günceller. Üstelik geliştirme kipi otomatik algılamayla etkinleşir, dolayısıyla genellikle hiçbir şeyi yapılandırmaya gerek kalmaz, [ya da yalnızca IP adresini |application:bootstrapping#Geliştirme modu ve üretim modu].

Router'ı hata ayıklarken, örneğin yönlendirmelerin saklanabildiği tarayıcı önbelleğini kapatmanızı öneririz: Geliştirici Araçları'nı açın (Ctrl+Shift+I ya da Cmd+Option+I) ve Network panelinde önbelleği kapatan kutuyu işaretleyin.


`#[\ReturnTypeWillChange] attribute should be used` Hatası
----------------------------------------------------------
Bu hata, PHP'yi 8.1 sürümüne yükselttiyseniz ama Nette'in onunla uyumlu olmayan bir sürümünü kullanıyorsanız ortaya çıkar. Çözüm, `composer update` ile Nette'i daha yeni bir sürüme güncellemektir. Nette, 3.0 sürümünden beri PHP 8.1'i destekler. Daha eski bir sürüm kullanıyorsanız (`composer.json` dosyanızı denetleyin), [Nette'i yükseltin |migrations:] ya da PHP 8.0'da kalın.


Dizin İzinlerini Ayarlama
-------------------------
macOS ya da Linux'ta (ya da Unix tabanlı başka bir sistemde) geliştiriyorsanız, web sunucusu için yazma yetkilerini yapılandırmanız gerekir. Uygulamanızın varsayılan `/var/www/html` dizininde bulunduğunu varsayarsak (Fedora, CentOS, RHEL):

```shell
cd /var/www/html/PROJEM
chmod -R a+rw temp log
```

Bazı Linux sistemlerinde (Fedora, CentOS, ...) SELinux varsayılan olarak etkin olabilir. SELinux ilkelerini güncellemeniz ya da `temp` ve `log` dizinlerinin yollarını doğru SELinux güvenlik bağlamıyla ayarlamanız gerekebilir. `temp` ve `log` dizinleri `httpd_sys_rw_content_t` bağlamına ayarlanmalıdır; uygulamanın geri kalanı için, başlıca `app` klasörü için, `httpd_sys_content_t` bağlamı yeterli olacaktır. Sunucuda root olarak çalıştırın:

```shell
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/PROJEM/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/PROJEM/temp(/.*)?'
restorecon -Rv /var/www/html/PROJEM/
```

Ardından, Nette'in veritabanına ağ üzerinden bağlanmasına izin vermek için `httpd_can_network_connect_db` SELinux boolean değerinin etkinleştirilmesi gerekir. Varsayılan olarak kapalıdır. Bu iş için `setsebool` komutu kullanılabilir; `-P` seçeneği belirtilirse bu ayar yeniden başlatmalar arasında kalıcı olur:

```shell
setsebool -P httpd_can_network_connect_db on
```


URL'den `www` Dizini Nasıl Değiştirilir ya da Kaldırılır?
---------------------------------------------------------
Nette'in örnek projelerinde kullanılan `www/` dizini, projenin genel dizinini yani document-root'unu temsil eder. İçeriğine tarayıcıdan erişilebilen tek dizin odur. Nette web uygulamasını başlatan giriş noktası olan `index.php` dosyasını içerir.

Uygulamayı bir hosting hizmetinde çalıştırmak için document-root'u doğru yapılandırmanız gerekir. İki seçeneğiniz var:
1. Hosting yapılandırmasında document-root'u bu dizine ayarlayın.
2. Hosting'in önceden hazırlanmış bir klasörü varsa (örneğin `public_html`), `www/` dizinini bu adla yeniden adlandırın.

.[warning]
Uygulamanızı, diğer klasörlere erişimi engellemek için yalnızca `.htaccess` ya da router kurallarını kullanarak güvenli kılmaya asla çalışmayın.

Hosting hizmeti document-root'u bir alt dizine ayarlamaya izin vermiyorsa (yani genel dizinin bir düzey üstünde dizin oluşturmaya), başka bir sağlayıcı arayın. Aksi hâlde ciddi bir güvenlik riskiyle karşı karşıya kalırsınız. Bu, ön kapısı kapanmayan ve hep ardına kadar açık duran bir dairede yaşamak gibi olurdu.


Güzel URL'ler İçin Sunucu Nasıl Yapılandırılır?
-----------------------------------------------
**Apache**: `.htaccess` dosyasında mod_rewrite kurallarını etkinleştirip yapılandırmanız gerekir:

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

Sorunlarla karşılaşırsanız şunlardan emin olun:
- `.htaccess` dosyası document-root dizininde bulunuyor (yani `index.php` dosyasının yanında)
- [Apache `.htaccess` dosyalarını işliyor |#.htaccess Çalışıyor mu Sınayın]
- [mod_rewrite etkin |#mod_rewrite Etkin mi Sınayın]

Uygulamayı bir alt klasöre kuruyorsanız, `RewriteBase` ayarının satırını yorumdan çıkarıp doğru klasöre ayarlamanız gerekebilir.

**nginx**: Yönlendirmenin, sunucu yapılandırmasındaki `location /` bloğunun içinde `try_files` yönergesiyle yapılandırılması gerekir.

```nginx
location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args ÖNEMLİDİR!
}
```

`location` bloğu, `server` bloğu içinde her dosya sistemi yolu için yalnızca bir kez görünmelidir. Yapılandırmanızda zaten bir `location /` bloğu varsa, `try_files` yönergesini var olan bloğa ekleyin.


`.htaccess` Çalışıyor mu Sınayın
--------------------------------
Apache'nin `.htaccess` dosyanızı kullanıp kullanmadığını ya da yok sayıp saymadığını sınamanın en basit yolu, onu bilerek bozmaktır. Dosyanın başına `Test` satırını koyun. Şimdi sayfayı tarayıcıda yenilerseniz *Internal Server Error* görmelisiniz.

Bu hatayı görüyorsanız, bu aslında iyi! Bu, Apache'nin `.htaccess` dosyasını ayrıştırdığı ve oraya koyduğumuz hatayla karşılaştığı anlamına gelir. `Test` satırını kaldırın.

*Internal Server Error* görmüyorsanız, Apache kurulumunuz `.htaccess` dosyasını yok sayıyor demektir. Apache onu genellikle `AllowOverride All` yapılandırma yönergesi eksik olduğu için yok sayar.

Sunucuyu kendiniz barındırıyorsanız, düzeltmek yeterince kolaydır. `httpd.conf` ya da `apache.conf` dosyanızı bir metin düzenleyicide açın, ilgili `<Directory>` bölümünü bulun ve şu yönergeyi ekleyin/değiştirin:

```apacheconf
<Directory "/var/www/htdocs"> # document root'unuzun yolu
    AllowOverride All
    ...
```

Siteniz başka bir yerde barındırılıyorsa, `.htaccess` dosyasını orada etkinleştirip etkinleştiremeyeceğinizi görmek için denetim panelinize bakın. Yapamıyorsanız, sizin için yapması amacıyla hosting sağlayıcınızla iletişime geçin.


`mod_rewrite` Etkin mi Sınayın
------------------------------
[`.htaccess` dosyasının çalıştığını |#.htaccess Çalışıyor mu Sınayın] doğruladıysanız, mod_rewrite uzantısının etkin olduğunu da doğrulayabilirsiniz. `.htaccess` dosyasının başına `RewriteEngine On` satırını koyun ve sayfayı tarayıcıda yenileyin. *Internal Server Error* görüyorsanız, bu mod_rewrite'ın etkin olmadığı anlamına gelir. Onu etkinleştirmenin birkaç yolu vardır. Farklı kurulumlarda bunun nasıl yapılabileceğine ilişkin çeşitli yollar için Stack Overflow'a bakın.


Bağlantılar `https:` Olmadan Üretiliyor
---------------------------------------
Nette, bağlantıları geçerli sayfanın kullandığı protokolle üretir. Yani `https://foo` sayfasında `https:` ile başlayan bağlantılar üretir, tersi de geçerlidir. HTTPS'i sonlandıran bir ters vekil sunucunun (örneğin Docker'da) arkasındaysanız, protokol algılamasının doğru çalışması için yapılandırmada bir [vekil sunucu ayarlamanız |http:configuration#HTTP Proxy] gerekir.

Vekil sunucu olarak Nginx kullanıyorsanız, yönlendirmeyi örneğin şöyle ayarlamanız gerekir:

```
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://uygulama-IP:80;  # uygulamanın çalıştığı sunucunun/konteynerin IP'si ya da hostname'i
}
```

Ayrıca yapılandırmada vekil sunucunun IP'sini ve isteğe bağlı olarak altyapıyı çalıştırdığınız yerel ağınızın IP aralığını belirtmeniz gerekir:

```neon
http:
	proxy: vekil-IP/IP-aralığı
```


JavaScript'te { } Karakterlerinin Kullanımı
-------------------------------------------
`{` ve `}` karakterleri Latte etiketleri yazmak için kullanılır. `{` karakterinden sonra gelen her şey (boşluk ve tırnak işareti dışında) bir etiket sayılır. `{` karakterini doğrudan yazdırmanız gerekiyorsa (sıklıkla JavaScript'te), `{` hemen ardına bir boşluk (ya da başka bir boşluk karakteri) koyabilirsiniz. Bu, onun etiket olarak yorumlanmasını engeller.

Bu karakterleri, metnin etiket olarak yorumlanacağı bir durumda yazdırmak gerekiyorsa, bu karakterleri çıktılamak için özel etiketleri kullanabilirsiniz: `{` için `{l}` ve `}` için `{r}`.

```
{bu bir etikettir}
{ bu bir etiket değildir }
{l}bu bir etiket değildir{r}
```


`Cannot modify header information - headers already sent` Hatası
----------------------------------------------------------------

Bu hata, uygulama bir HTTP başlığı (bir çerez, bir yönlendirme ya da oturumun başlatılması) göndermeye çalıştığında ve o anda tarayıcıya zaten bir çıktı gönderilmişse ortaya çıkar. Başlıklar her zaman yanıtın gövdesinden önce gelmelidir.

İki olası neden vardır: ya çıktı çok erken gider ya da başlık çok geç gönderilir.

Çıktı genellikle `<?php` öncesindeki ya da kapatan `?>` sonrasındaki başıboş bir boşluk veya boş satır yüzünden ya da düzenleyicinin dosyanın başına eklediği ve göstermediği bir BOM yüzünden çok erken gider. Bu yüzden PHP dosyalarını asla `?>` ile bitirmeyin. Hangi yerin önce yazdırdığını bulmak için [Tracy\OutputDebugger |tracy:recipes#Çıktının Kaynağını Bulma] kullanın.

Başlık genellikle oturumla çalışırken çok geç gönderilir. Nette, oturumdan ilk kez okuduğunuzda ya da ona yazdığınızda oturumu otomatik başlatır; bu yalnızca şablon render edilirken olursa, çıktı çoktan yola çıkmıştır. Bu yüzden oturumla en geç `beforeRender()` metodunda, bileşenlerde ayrıca `handle<Signal>()` metotlarında çalışın.

Sorunu [autoStart: true |http:configuration#Oturum] ayarıyla çözmeye çalışmayın. Bu, robotlar dahil her ziyaretçi için oturumu başlatır ve diskte gereksiz yere çok sayıda dosya oluşturur. Varsayılan `smart` değeri, oturumu yalnızca gerçekten gerektiğinde başlatır.


`Presenter::getContext() is deprecated` Uyarısı
-----------------------------------------------

Nette, dependency injection'a geçen ilk PHP framework'üydü ve programcıları onu tutarlı biçimde, doğrudan presenter'lardan başlayarak kullanmaya yönlendirdi. Bir presenter'ın bir bağımlılığa gereksinimi varsa, [onu ister|dependency-injection:passing-dependencies]. Tersine, DI container'ın tamamını bir sınıfa aktarıp bağımlılıkları doğrudan oradan çekmesini sağlamak bir antipattern sayılır (service locator deseni olarak bilinir). Bu yaklaşım, dependency injection ortaya çıkmadan önce Nette 0.x'te kullanılıyordu ve uzun süredir deprecated olarak işaretli `Presenter::getContext()` metodu o dönemden kalma bir kalıntıdır.

Çok eski bir Nette uygulamasını taşıyorsanız, onun hâlâ bu metodu kullandığını görebilirsiniz. `nette/application` 3.1 sürümünden beri `Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection` uyarısıyla, 4.0 sürümünden beri ise metodun var olmadığını bildiren bir hatayla karşılaşırsınız.

Temiz çözüm elbette uygulamayı, bağımlılıkları dependency injection ile aktaracak şekilde yeniden düzenlemektir. Geçici bir çözüm olarak, mesajı atlatmak için temel presenter'ınıza kendi `getContext()` metodunuzu ekleyebilirsiniz:

```php
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
	private Nette\DI\Container $context;

	public function injectContext(Nette\DI\Container $context): void
	{
		$this->context = $context;
	}

	public function getContext(): Nette\DI\Container
	{
		return $this->context;
	}
}
```

Sorun Giderme

Nette Çalışmıyor, Beyaz Sayfa Görünüyor

  • Hataların gösterilmesini zorlamak için index.php dosyasında declare(strict_types=1); satırından sonra ini_set('display_errors', '1'); error_reporting(E_ALL); yazmayı deneyin.
  • Hâlâ beyaz ekran görüyorsanız, muhtemelen sunucu yapılandırmasında bir hata vardır ve nedenini sunucu günlüğünde bulacaksınız. Emin olmak için echo 'test'; ile bir şey yazdırmayı deneyerek PHP'nin hiç çalışıp çalışmadığını denetleyin.
  • Server Error: We're sorry! … hatasını görüyorsanız, bir sonraki bölümle devam edin:

Hata 500 Server Error: We're sorry! …

Bu hata sayfasını Nette üretim kipinde gösterir. Onu geliştirme makinenizde görüyorsanız, geliştirici kipine geçin; Tracy ayrıntılı bir rapor gösterecek.

Hatanın nedenini her zaman log/ dizinindeki günlükte bulabilirsiniz. Ancak hata mesajında Tracy is unable to log error ifadesi geçiyorsa, önce hataların neden günlüklenemediğini saptayın. Bunu örneğin geçici olarak geliştirici kipine geçip Tracy'yi başladıktan sonra bir şey günlüklemeye bırakarak yapabilirsiniz:

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

Tracy size neden günlükleyemediğini söyleyecek. Nedeni, log/ dizinine yazmak için yetersiz izinler olabilir.

500 hatasının en sık nedenlerinden biri eskimiş önbellektir. Nette, geliştirme kipinde önbelleği akıllıca otomatik güncellerken, üretim kipinde başarımı en üst düzeye çıkarmaya odaklanır ve her kod değişikliğinden sonra önbelleği temizlemek sizin sorumluluğunuzdadır. temp/cache dizinini silmeyi deneyin.

Hata 404, Yönlendirme Çalışmıyor

Tüm sayfalar (ana sayfa dışında) 404 hatası döndürüyorsa, bu güzel URL'ler için bir sunucu yapılandırma sorununa benziyor.

Şablonlardaki ya da Yapılandırmadaki Değişiklikler Yansımıyor

„Şablonu ya da yapılandırmayı değiştirdim, ama web sitesi hâlâ eski sürümü gösteriyor.“ Bu davranış, başarım nedeniyle dosya değişikliklerini denetlemeyen ve daha önce üretilmiş önbelleği koruyan üretim kipinde ortaya çıkar.

Üretim sunucusunda her değişiklikten sonra önbelleği elle temizlemekten kaçınmak için, Bootstrap.php dosyasında kendi IP adresiniz için geliştirme kipini etkinleştirin:

$this->configurator->setDebugMode('sizin.ip.adresiniz');

Geliştirme Sırasında Önbellek Nasıl Kapatılır?

Nette akıllıdır ve onda önbelleğe almayı kapatmanıza gerek yoktur. Geliştirme sırasında, şablonda ya da DI container yapılandırmasında bir değişiklik olduğunda önbelleği otomatik günceller. Üstelik geliştirme kipi otomatik algılamayla etkinleşir, dolayısıyla genellikle hiçbir şeyi yapılandırmaya gerek kalmaz, ya da yalnızca IP adresini.

Router'ı hata ayıklarken, örneğin yönlendirmelerin saklanabildiği tarayıcı önbelleğini kapatmanızı öneririz: Geliştirici Araçları'nı açın (Ctrl+Shift+I ya da Cmd+Option+I) ve Network panelinde önbelleği kapatan kutuyu işaretleyin.

#[\ReturnTypeWillChange] attribute should be used Hatası

Bu hata, PHP'yi 8.1 sürümüne yükselttiyseniz ama Nette'in onunla uyumlu olmayan bir sürümünü kullanıyorsanız ortaya çıkar. Çözüm, composer update ile Nette'i daha yeni bir sürüme güncellemektir. Nette, 3.0 sürümünden beri PHP 8.1'i destekler. Daha eski bir sürüm kullanıyorsanız (composer.json dosyanızı denetleyin), Nette'i yükseltin ya da PHP 8.0'da kalın.

Dizin İzinlerini Ayarlama

macOS ya da Linux'ta (ya da Unix tabanlı başka bir sistemde) geliştiriyorsanız, web sunucusu için yazma yetkilerini yapılandırmanız gerekir. Uygulamanızın varsayılan /var/www/html dizininde bulunduğunu varsayarsak (Fedora, CentOS, RHEL):

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

Bazı Linux sistemlerinde (Fedora, CentOS, …) SELinux varsayılan olarak etkin olabilir. SELinux ilkelerini güncellemeniz ya da temp ve log dizinlerinin yollarını doğru SELinux güvenlik bağlamıyla ayarlamanız gerekebilir. temp ve log dizinleri httpd_sys_rw_content_t bağlamına ayarlanmalıdır; uygulamanın geri kalanı için, başlıca app klasörü için, httpd_sys_content_t bağlamı yeterli olacaktır. Sunucuda root olarak çalıştırın:

semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/PROJEM/log(/.*)?'
semanage fcontext -at httpd_sys_rw_content_t '/var/www/html/PROJEM/temp(/.*)?'
restorecon -Rv /var/www/html/PROJEM/

Ardından, Nette'in veritabanına ağ üzerinden bağlanmasına izin vermek için httpd_can_network_connect_db SELinux boolean değerinin etkinleştirilmesi gerekir. Varsayılan olarak kapalıdır. Bu iş için setsebool komutu kullanılabilir; -P seçeneği belirtilirse bu ayar yeniden başlatmalar arasında kalıcı olur:

setsebool -P httpd_can_network_connect_db on

URL'den www Dizini Nasıl Değiştirilir ya da Kaldırılır?

Nette'in örnek projelerinde kullanılan www/ dizini, projenin genel dizinini yani document-root'unu temsil eder. İçeriğine tarayıcıdan erişilebilen tek dizin odur. Nette web uygulamasını başlatan giriş noktası olan index.php dosyasını içerir.

Uygulamayı bir hosting hizmetinde çalıştırmak için document-root'u doğru yapılandırmanız gerekir. İki seçeneğiniz var:

  1. Hosting yapılandırmasında document-root'u bu dizine ayarlayın.
  2. Hosting'in önceden hazırlanmış bir klasörü varsa (örneğin public_html), www/ dizinini bu adla yeniden adlandırın.

Uygulamanızı, diğer klasörlere erişimi engellemek için yalnızca .htaccess ya da router kurallarını kullanarak güvenli kılmaya asla çalışmayın.

Hosting hizmeti document-root'u bir alt dizine ayarlamaya izin vermiyorsa (yani genel dizinin bir düzey üstünde dizin oluşturmaya), başka bir sağlayıcı arayın. Aksi hâlde ciddi bir güvenlik riskiyle karşı karşıya kalırsınız. Bu, ön kapısı kapanmayan ve hep ardına kadar açık duran bir dairede yaşamak gibi olurdu.

Güzel URL'ler İçin Sunucu Nasıl Yapılandırılır?

Apache: .htaccess dosyasında mod_rewrite kurallarını etkinleştirip yapılandırmanız gerekir:

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]

Sorunlarla karşılaşırsanız şunlardan emin olun:

Uygulamayı bir alt klasöre kuruyorsanız, RewriteBase ayarının satırını yorumdan çıkarıp doğru klasöre ayarlamanız gerekebilir.

nginx: Yönlendirmenin, sunucu yapılandırmasındaki location / bloğunun içinde try_files yönergesiyle yapılandırılması gerekir.

location / {
	try_files $uri $uri/ /index.php$is_args$args;  # $is_args$args ÖNEMLİDİR!
}

location bloğu, server bloğu içinde her dosya sistemi yolu için yalnızca bir kez görünmelidir. Yapılandırmanızda zaten bir location / bloğu varsa, try_files yönergesini var olan bloğa ekleyin.

.htaccess Çalışıyor mu Sınayın

Apache'nin .htaccess dosyanızı kullanıp kullanmadığını ya da yok sayıp saymadığını sınamanın en basit yolu, onu bilerek bozmaktır. Dosyanın başına Test satırını koyun. Şimdi sayfayı tarayıcıda yenilerseniz Internal Server Error görmelisiniz.

Bu hatayı görüyorsanız, bu aslında iyi! Bu, Apache'nin .htaccess dosyasını ayrıştırdığı ve oraya koyduğumuz hatayla karşılaştığı anlamına gelir. Test satırını kaldırın.

Internal Server Error görmüyorsanız, Apache kurulumunuz .htaccess dosyasını yok sayıyor demektir. Apache onu genellikle AllowOverride All yapılandırma yönergesi eksik olduğu için yok sayar.

Sunucuyu kendiniz barındırıyorsanız, düzeltmek yeterince kolaydır. httpd.conf ya da apache.conf dosyanızı bir metin düzenleyicide açın, ilgili <Directory> bölümünü bulun ve şu yönergeyi ekleyin/değiştirin:

<Directory "/var/www/htdocs"> # document root'unuzun yolu
    AllowOverride All
    ...

Siteniz başka bir yerde barındırılıyorsa, .htaccess dosyasını orada etkinleştirip etkinleştiremeyeceğinizi görmek için denetim panelinize bakın. Yapamıyorsanız, sizin için yapması amacıyla hosting sağlayıcınızla iletişime geçin.

mod_rewrite Etkin mi Sınayın

.htaccess dosyasının çalıştığını doğruladıysanız, mod_rewrite uzantısının etkin olduğunu da doğrulayabilirsiniz. .htaccess dosyasının başına RewriteEngine On satırını koyun ve sayfayı tarayıcıda yenileyin. Internal Server Error görüyorsanız, bu mod_rewrite'ın etkin olmadığı anlamına gelir. Onu etkinleştirmenin birkaç yolu vardır. Farklı kurulumlarda bunun nasıl yapılabileceğine ilişkin çeşitli yollar için Stack Overflow'a bakın.

Bağlantılar https: Olmadan Üretiliyor

Nette, bağlantıları geçerli sayfanın kullandığı protokolle üretir. Yani https://foo sayfasında https: ile başlayan bağlantılar üretir, tersi de geçerlidir. HTTPS'i sonlandıran bir ters vekil sunucunun (örneğin Docker'da) arkasındaysanız, protokol algılamasının doğru çalışması için yapılandırmada bir vekil sunucu ayarlamanız gerekir.

Vekil sunucu olarak Nginx kullanıyorsanız, yönlendirmeyi örneğin şöyle ayarlamanız gerekir:

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://uygulama-IP:80;  # uygulamanın çalıştığı sunucunun/konteynerin IP'si ya da hostname'i
}

Ayrıca yapılandırmada vekil sunucunun IP'sini ve isteğe bağlı olarak altyapıyı çalıştırdığınız yerel ağınızın IP aralığını belirtmeniz gerekir:

http:
	proxy: vekil-IP/IP-aralığı

JavaScript'te { } Karakterlerinin Kullanımı

{ ve } karakterleri Latte etiketleri yazmak için kullanılır. { karakterinden sonra gelen her şey (boşluk ve tırnak işareti dışında) bir etiket sayılır. { karakterini doğrudan yazdırmanız gerekiyorsa (sıklıkla JavaScript'te), { hemen ardına bir boşluk (ya da başka bir boşluk karakteri) koyabilirsiniz. Bu, onun etiket olarak yorumlanmasını engeller.

Bu karakterleri, metnin etiket olarak yorumlanacağı bir durumda yazdırmak gerekiyorsa, bu karakterleri çıktılamak için özel etiketleri kullanabilirsiniz: { için {l} ve } için {r}.

{bu bir etikettir}
{ bu bir etiket değildir }
{l}bu bir etiket değildir{r}

Cannot modify header information - headers already sent Hatası

Bu hata, uygulama bir HTTP başlığı (bir çerez, bir yönlendirme ya da oturumun başlatılması) göndermeye çalıştığında ve o anda tarayıcıya zaten bir çıktı gönderilmişse ortaya çıkar. Başlıklar her zaman yanıtın gövdesinden önce gelmelidir.

İki olası neden vardır: ya çıktı çok erken gider ya da başlık çok geç gönderilir.

Çıktı genellikle <?php öncesindeki ya da kapatan ?> sonrasındaki başıboş bir boşluk veya boş satır yüzünden ya da düzenleyicinin dosyanın başına eklediği ve göstermediği bir BOM yüzünden çok erken gider. Bu yüzden PHP dosyalarını asla ?> ile bitirmeyin. Hangi yerin önce yazdırdığını bulmak için Tracy\OutputDebugger kullanın.

Başlık genellikle oturumla çalışırken çok geç gönderilir. Nette, oturumdan ilk kez okuduğunuzda ya da ona yazdığınızda oturumu otomatik başlatır; bu yalnızca şablon render edilirken olursa, çıktı çoktan yola çıkmıştır. Bu yüzden oturumla en geç beforeRender() metodunda, bileşenlerde ayrıca handle<Signal>() metotlarında çalışın.

Sorunu autoStart: true ayarıyla çözmeye çalışmayın. Bu, robotlar dahil her ziyaretçi için oturumu başlatır ve diskte gereksiz yere çok sayıda dosya oluşturur. Varsayılan smart değeri, oturumu yalnızca gerçekten gerektiğinde başlatır.

Presenter::getContext() is deprecated Uyarısı

Nette, dependency injection'a geçen ilk PHP framework'üydü ve programcıları onu tutarlı biçimde, doğrudan presenter'lardan başlayarak kullanmaya yönlendirdi. Bir presenter'ın bir bağımlılığa gereksinimi varsa, onu ister. Tersine, DI container'ın tamamını bir sınıfa aktarıp bağımlılıkları doğrudan oradan çekmesini sağlamak bir antipattern sayılır (service locator deseni olarak bilinir). Bu yaklaşım, dependency injection ortaya çıkmadan önce Nette 0.x'te kullanılıyordu ve uzun süredir deprecated olarak işaretli Presenter::getContext() metodu o dönemden kalma bir kalıntıdır.

Çok eski bir Nette uygulamasını taşıyorsanız, onun hâlâ bu metodu kullandığını görebilirsiniz. nette/application 3.1 sürümünden beri Nette\Application\UI\Presenter::getContext() is deprecated, use dependency injection uyarısıyla, 4.0 sürümünden beri ise metodun var olmadığını bildiren bir hatayla karşılaşırsınız.

Temiz çözüm elbette uygulamayı, bağımlılıkları dependency injection ile aktaracak şekilde yeniden düzenlemektir. Geçici bir çözüm olarak, mesajı atlatmak için temel presenter'ınıza kendi getContext() metodunuzu ekleyebilirsiniz:

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
	private Nette\DI\Container $context;

	public function injectContext(Nette\DI\Container $context): void
	{
		$this->context = $context;
	}

	public function getContext(): Nette\DI\Container
	{
		return $this->context;
	}
}