Presenter'lar

Nette'te presenter'ların ve şablonların nasıl yazıldığını inceleyeceğiz. Okuduktan sonra şunları anlayacaksınız:

  • presenter'ların nasıl çalıştığını
  • kalıcı parametrelerin ne olduğunu
  • şablonların nasıl render edildiğini

Presenter'ın bir web uygulamasının belirli bir sayfasını (ana sayfa, e-ticaret sitesindeki bir ürün, giriş formu, site haritası beslemesi vb.) temsil eden bir sınıf olduğunu artık biliyoruz. Bir uygulamada birden binlerce presenter olabilir. Başka framework'lerde bunlara controller da denir.

Genellikle presenter terimiyle, web arayüzleri üretmeye uygun olan ve bu bölümün geri kalanının odağı olacak Nette\Application\UI\Presenter sınıfının bir torununu kastederiz. Genel anlamda presenter, Nette\Application\IPresenter arayüzünü uygulayan herhangi bir nesnedir.

Presenter'ın yaşam döngüsü

Presenter'ın görevi bir isteği işlemek ve bir yanıt döndürmektir (bu bir HTML sayfası, bir görsel, bir yönlendirme vb. olabilir).

Yani önce ona bir istek verilir. Bu doğrudan HTTP isteği değil, HTTP isteğinin router yardımıyla dönüştürüldüğü bir Nette\Application\Request nesnesidir. Bu nesneyle genellikle doğrudan uğraşmayız, çünkü presenter isteğin işlenmesini şimdi inceleyeceğimiz başka metotlara akıllıca devreder.

Presenter'ın yaşam döngüsü

Şema, varsa yukarıdan aşağıya sırayla çağrılan metotların listesini gösterir. Hiçbiri zorunlu değildir; tek bir metodu olmayan tamamen boş bir presenter'ınız olabilir ve üzerine basit bir statik site kurabilirsiniz.

__construct()

Constructor, nesnenin oluşturulduğu anda çağrıldığı için tam olarak presenter'ın yaşam döngüsüne ait değildir. Ancak önemi nedeniyle onu da anıyoruz. Constructor (inject metoduyla birlikte) bağımlılıkları aktarmaya yarar.

Presenter, uygulamanın iş mantığını üstlenmemeli, veritabanına yazmamalı veya ondan okumamalı, hesaplama yapmamalıdır. Bu, model dediğimiz katmandaki sınıfların işidir. Örneğin bir ArticleRepository sınıfı makaleleri yüklemekten ve kaydetmekten sorumlu olabilir. Presenter'ın onunla çalışabilmesi için ona bağımlılık enjeksiyonuyla aktarılması gerekir:

class ArticlePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private ArticleRepository $articles,
	) {
	}
}

startup()

İstek alınır alınmaz startup() metodu çağrılır. Onu özellikleri ilklendirmek, kullanıcı izinlerini denetlemek vb. için kullanabilirsiniz. Bu metodun her zaman üst sınıfını çağırması gerekir: parent::startup().

action<Eylem>(args...)

render<Görünüm>() metoduna benzer. render<Görünüm>() ardından render edilecek belirli bir şablon için veri hazırlamayı amaçlarken, action<Eylem>() bir isteği, ardından mutlaka bir şablon render etmeden işler. Örneğin veriyi işleyebilir, kullanıcının oturumunu açıp kapatabilir vb. ve sonra başka bir yere yönlendirebilir.

Önemli olan, action<Eylem>()'in render<Görünüm>()'den önce çağrılmasıdır. Bu, eylem metodunun içinde isteğin gidişatını değiştirebilmemizi sağlar; örneğin setView('digerGorunum') ile render edilecek şablonu, hatta çağrılacak render<Görünüm>() metodunu değiştirerek.

switch('digerEylem') metoduyla tamamen başka bir eyleme bile geçebilirsiniz. Bu, geçerli metodu keser ve onun yerine yeni eylemin action<Eylem>() ve render<Görünüm>() metotlarını çalıştırır (ve otomatik kanonikleştirmeyi kapatır). İsteğin kendisi devam eder; yalnızca o an çalışan metot kesilir.

Metoda istekten gelen parametreler aktarılır. Bu parametreler için tip belirtmek mümkündür ve önerilir, örneğin actionShow(int $id, ?string $slug = null). id parametresi eksikse veya tam sayı değilse, presenter 404 hatası döndürür ve sonlanır.

handle<Sinyal>(args...)

Bu metot, bileşenlere ayrılmış bölümde öğreneceğimiz sinyalleri işler. Öncelikle bileşenler ve AJAX isteklerinin işlenmesi içindir.

Metoda, action<Eylem>()'de olduğu gibi, tip denetimi dahil, istekten gelen parametreler aktarılır.

beforeRender()

beforeRender metodu, adının da söylediği gibi, her render<Görünüm>() metodundan önce çağrılır. Ortak şablon ayarları, layout'a değişken aktarımı ve benzeri işler için kullanılır.

render<Görünüm>(args...)

Burada şablonu ardından render edilmek üzere hazırlar, ona veri aktarırız vb.

Metoda, action<Eylem>()'de olduğu gibi, tip denetimi dahil, istekten gelen parametreler aktarılır.

public function renderShow(int $id): void
{
	// model'den veriyi al ve şablona aktar
	$this->template->article = $this->articles->getById($id);
}

afterRender()

afterRender metodu, adının yine söylediği gibi, her render<Görünüm>() metodundan sonra çağrılır. Oldukça ender kullanılır.

shutdown()

Presenter'ın yaşam döngüsünün sonunda çağrılır.

Olaylar

Presenter'ın yaşam döngüsünün parçası olarak çağrılan startup(), beforeRender() ve shutdown() metotlarının yanı sıra, otomatik çağrılacak başka fonksiyonlar da tanımlanabilir. Presenter, olaylar denilen şeyleri tanımlar; işleyicilerini $onStartup, $onRender ve $onShutdown dizilerine eklersiniz.

class ArticlePresenter extends Nette\Application\UI\Presenter
{
	public function __construct()
	{
		$this->onStartup[] = function () {
			// ...
		};
	}
}

$onStartup dizisindeki işleyiciler startup() metodundan hemen önce, $onRender işleyicileri beforeRender() ile render<Görünüm>() arasında ve son olarak $onShutdown işleyicileri shutdown()'dan hemen önce çağrılır.

Devam etmeden önce bir öneri: Gördüğünüz gibi bir presenter birden fazla eylemi/görünümü işleyebilir, yani birden fazla render<Görünüm>() metoduna sahip olabilir. Ancak presenter'ları tek veya olabildiğince az eylemle tasarlamanızı öneririz.

Yanıt gönderme

Presenter'ın yanıtı genellikle bir şablonun HTML sayfasına render edilmesidir, ama bir dosya, JSON gönderimi, hatta başka bir sayfaya yönlendirme de olabilir.

Yaşam döngüsünün herhangi bir noktasında, aşağıdaki metotlardan birini kullanarak bir yanıt gönderip presenter'ı aynı anda sonlandırabiliriz:

  • redirect(), redirectPermanent(), redirectUrl() ve forward() bir yönlendirme gerçekleştirir
  • error() presenter'ı bir hata nedeniyle sonlandırır
  • sendJson($data) presenter'ı sonlandırır ve veriyi JSON formatında gönderir
  • sendTemplate() presenter'ı sonlandırır ve şablonu hemen render eder
  • sendResponse($response) presenter'ı sonlandırır ve kendi yanıtınızı gönderir
  • terminate() presenter'ı yanıtsız sonlandırır

Bu metotların her biri, sessiz sonlandırma istisnası Nette\Application\AbortException'ı fırlatarak presenter'ı hemen sonlandırır.

Bu metotlardan hiçbirini çağırmazsanız, presenter otomatik olarak şablonu render etmeye geçer. Neden? Çünkü vakaların %99'unda bir şablon render etmek isteriz, bu yüzden presenter işimizi kolaylaştırmak için bu davranışı varsayılan olarak benimser.

Bağlantı oluşturma

Presenter'ın, başka presenter'lara URL bağlantıları oluşturmaya yarayan bir link() metodu vardır. İlk parametre hedef presenter ve eylemdir, ardından dizi olarak da aktarılabilen argümanlar gelir:

$url = $this->link('Product:show', $id);

$url = $this->link('Product:show', [$id, 'lang' => 'en']);

Şablonda başka presenter'lara ve eylemlere bağlantılar şöyle oluşturulur:

<a n:href="Product:show $id">ürün detayı</a>

Gerçek URL yerine tanıdık Presenter:eylem çiftini yazın ve gerekli parametreleri ekleyin. İşin püf noktası, Latte'ye bu niteliği işlemesini ve gerçek URL'yi üretmesini söyleyen n:href'tir. Nette'te URL'leri hiç düşünmeniz gerekmez, yalnızca presenter'ları ve eylemleri.

Daha fazla bilgiyi URL bağlantıları oluşturma bölümünde bulabilirsiniz.

Yönlendirme

Başka bir presenter'a geçmek için redirect() ve forward() metotları kullanılır. Sözdizimleri link() metodununkine çok benzer.

forward() metodu, HTTP yönlendirmesi olmadan hemen yeni presenter'a geçer:

$this->forward('Product:show');

HTTP kodu 302 ile geçici yönlendirme örneği (geçerli istek yöntemi POST ise 303):

$this->redirect('Product:show', $id);

HTTP kodu 301 ile kalıcı yönlendirme için şunu kullanın:

$this->redirectPermanent('Product:show', $id);

redirectUrl() metoduyla uygulamanın dışındaki başka bir URL'ye yönlendirebilirsiniz. HTTP kodu ikinci parametre olarak belirtilebilir; varsayılan 302'dir (geçerli istek yöntemi POST ise 303).

$this->redirectUrl('https://nette.org');

Yönlendirme, sessiz sonlandırma istisnası denilen Nette\Application\AbortException'ı fırlatarak presenter'ın çalışmasını hemen sonlandırır.

Yönlendirmeden önce Flash mesajları, yani yönlendirmeden sonra şablonda gösterilecek mesajlar gönderilebilir.

Flash mesajları

Bunlar genellikle bir işlemin sonucunu bildiren mesajlardır. Flash mesajlarının önemli bir özelliği, yönlendirmeden sonra da şablonda erişilebilir kalmalarıdır. Gösterildikten sonra 30 saniye daha etkin kalırlar; örneğin kullanıcı bir aktarım hatası yüzünden sayfayı yenilerse mesaj hemen kaybolmaz.

flashMessage() metodunu çağırmanız yeterli, onu şablona aktarmayı presenter üstlenir. İlk parametre mesajın metni, isteğe bağlı ikinci parametre ise tipidir (örneğin error, warning, info). flashMessage() metodu flash mesajın örneğini döndürür, böylece ek bilgiler eklenebilir.

$this->flashMessage('Öğe silindi.');
$this->redirect(/* ... */); // ve yönlendir

Şablonda bu mesajlar $flashes değişkeninde, message (mesaj metni), type (mesaj tipi) ve muhtemelen daha önce sözü geçen kullanıcı bilgilerini içeren stdClass nesneleri olarak sunulur. Onları şöyle render ederiz:

{foreach $flashes as $flash}
	<div class="flash {$flash->type}">{$flash->message}</div>
{/foreach}

Hata 404 vb.

İstek yerine getirilemiyorsa, örneğin göstermek istediğimiz makale veritabanında yoksa, error(string $message = '', int $httpCode = 404) metoduyla 404 hatası fırlatırız.

public function renderShow(int $id): void
{
	$article = $this->articles->getById($id);
	if (!$article) {
		$this->error();
	}
	// ...
}

HTTP hata kodu ikinci parametre olarak aktarılabilir; varsayılan 404'tür. Metot, bir Nette\Application\BadRequestException fırlatarak çalışır; ardından Application denetimi error presenter'a devreder. Bu, oluşan hatayı bildiren bir sayfa göstermekle görevli bir presenter'dır. Error presenter, uygulama yapılandırmasında ayarlanır.

JSON gönderme

sendJson($data) metodu, verilen veriyi JSON'a kodlar, HTTP yanıtı olarak gönderir ve presenter'ı sonlandırır. Örnek:

public function actionData(): void
{
	$data = ['hello' => 'nette'];
	$this->sendJson($data);
}

İsteğin parametreleri

Presenter, ve her bileşen de, parametrelerini HTTP isteğinden alır. Değerlerini getParameter($name) veya getParameters() metotlarıyla elde edebilirsiniz. Değerler dizelerdir veya dize dizileridir, yani doğrudan URL'den alınan ham veridir.

Daha fazla rahatlık için parametrelere özellikler üzerinden erişmenizi öneririz. Onları #[Parameter] niteliğiyle işaretlemeniz yeterlidir:

use Nette\Application\Attributes\Parameter;  // bu satır önemli

class HomePresenter extends Nette\Application\UI\Presenter
{
	#[Parameter]
	public string $theme; // public olmalı
}

Özellik için veri tipini (örneğin string) belirtmenizi öneririz; Nette değeri buna göre otomatik dönüştürür. Parametre değerleri ayrıca doğrulanabilir.

Bağlantı oluştururken parametrenin değerini doğrudan ayarlayabilirsiniz:

<a n:href="Home:default theme: dark">tıkla</a>

Kalıcı parametreler

Kalıcı parametreler, durumu farklı istekler boyunca korumak için kullanılır. Değerleri, bir bağlantıya tıklandıktan sonra da aynı kalır. Oturum verilerinin aksine URL'de aktarılırlar. Ve bu tamamen otomatik gerçekleşir, bu yüzden onları link() veya n:href içinde açıkça belirtmeye gerek yoktur.

Örnek bir kullanım? Çok dilli bir uygulamanız olduğunu düşünün. Geçerli dil, URL'nin her zaman parçası olması gereken bir parametredir. Ama onu her bağlantıya yazmak inanılmaz sıkıcı olurdu. Bu yüzden onu lang kalıcı parametresi yaparsınız ve otomatik olarak taşınır. Şahane!

Nette'te kalıcı parametre oluşturmak son derece basittir. Public bir özellik oluşturup onu nitelikle işaretlemeniz yeterlidir: (önceden /** @persistent */ kullanılıyordu)

use Nette\Application\Attributes\Persistent;  // bu satır önemli

class ProductPresenter extends Nette\Application\UI\Presenter
{
	#[Persistent]
	public string $lang; // public olmalı
}

$this->lang örneğin 'en' değerini taşıyorsa, link() veya n:href ile oluşturulan bağlantılar da lang=en parametresini içerecektir. Ve bağlantıya tıklandıktan sonra $this->lang yine 'en' olacaktır.

Özellik için veri tipini (örneğin string) belirtmenizi öneririz, ayrıca bir varsayılan değer de verebilirsiniz. Parametre değerleri doğrulanabilir.

Kalıcı parametreler genellikle ilgili presenter'ın tüm eylemleri arasında aktarılır. Onları birden fazla presenter arasında da aktarmak için, ya:

  • presenter'ların kalıtım aldığı ortak bir atada
  • ya da presenter'ların kullandığı bir trait'te tanımlanmaları gerekir:
trait LanguageAware
{
	#[Persistent]
	public string $lang;
}

class ProductPresenter extends Nette\Application\UI\Presenter
{
	use LanguageAware;
}

Bağlantı oluştururken kalıcı parametrenin değeri değiştirilebilir:

<a n:href="Product:show $id, lang: cs">Çekçe detay</a>

Ya da sıfırlanabilir, yani URL'den kaldırılabilir. O zaman varsayılan değerini alır:

<a n:href="Product:show $id, lang: null">tıkla</a>

Ortak parametre alanı

İsteğin parametreleri, kalıcı parametreler ve action, render ile handle (sinyal) metotlarının parametreleri tek bir alanı paylaşır; her biri adıyla tanımlanır. Aynı ad birden fazlasında geçerse, hepsi bir ve aynı değere karşılık gelir.

Bu sıkça avantaja çevrilir. Örneğin lang kalıcı parametresi ile bir eylem ya da sinyal metodunun $lang argümanı bir ve aynıdır; kalıcı bir parametrenin geçerli değerini, onu yalnızca metot imzasına yazarak okuyabilirsiniz:

#[Persistent]
public string $lang;

public function handleSearch(string $query, string $lang): void
{
	// $lang, lang kalıcı parametresinin geçerli değerini taşır
}

Bu alan paylaşıldığı için, bilinçli olarak aynı değeri paylaşmalarını istemiyorsanız parametre adlarını benzersiz tutun. Bu, ayrıca isteğin POST gövdesinden de parametre okuyan sinyaller için de geçerlidir; bkz. Sinyaller derinlemesine.

Etkileşimli bileşenler

Presenter'ların yerleşik bir bileşen sistemi vardır. Bileşenler, presenter'lara gömdüğümüz ayrı ve yeniden kullanılabilir birimlerdir. Formlar, datagrid'ler, menüler, kısacası tekrar tekrar kullanmanın anlamlı olduğu her şey olabilirler.

Bileşenler presenter'lara nasıl gömülür ve sonra nasıl kullanılır? Bunu Bileşenler bölümünde öğreneceksiniz. Hatta Hollywood ile neyi ortak yaptıklarını da öğreneceksiniz.

Peki bileşenleri nereden bulurum? Componette üzerinde, framework topluluğundan gönüllülerin katkıda bulunduğu açık kaynak bileşenleri ve Nette için birçok başka eklentiyi bulacaksınız.

Daha derine

Bu bölümde şu ana kadar ele aldıklarımız çoğu kullanım için yeterli olacaktır. Aşağıdaki kısımlar, presenter'lara daha derinlemesine dalmak ve kesinlikle her şeyi bilmek isteyenler içindir.

Parametrelerin doğrulanması

URL'lerden alınan İsteğin parametreleri ve Kalıcı parametreler değerleri özelliklere loadState() metoduyla yazılır. Bu metot ayrıca özellikte belirtilen veri tipinin uyup uymadığını denetler; uymuyorsa 404 hatasıyla yanıt verir ve sayfa gösterilmez.

URL'den gelen parametrelere asla körü körüne güvenmeyin, çünkü kullanıcı onları kolayca değiştirebilir. Örneğin $this->lang dilinin desteklenenler arasında olup olmadığını böyle doğrularız. Bunun uygun bir yolu, sözü geçen loadState() metodunu ezmektir:

class ProductPresenter extends Nette\Application\UI\Presenter
{
	#[Persistent]
	public string $lang;

	public function loadState(array $params): void
	{
		parent::loadState($params); // $this->lang burada ayarlanır
		// ardından kendi değer denetimimiz gelir:
		if (!in_array($this->lang, ['en', 'cs'])) {
			$this->error();
		}
	}
}

İsteğin kaydedilmesi ve geri yüklenmesi

Presenter'ın işlediği istek, presenter'ın getRequest() metodunun döndürdüğü bir Nette\Application\Request nesnesidir.

Geçerli istek oturuma kaydedilebilir, ya da tersine oturumdan geri yüklenip presenter'a yeniden yürüttürülebilir. Bu, örneğin kullanıcı bir formu doldururken oturumunun süresi dolduğunda işe yarar. Veri kaybını önlemek için, giriş sayfasına yönlendirmeden önce geçerli isteği $reqId = $this->storeRequest() ile oturuma kaydederiz. Bu, isteğin tanımlayıcısını kısa bir dize olarak döndürür; onu giriş presenter'ına parametre olarak aktarırız.

Girişten sonra $this->restoreRequest($reqId) metodunu çağırırız; bu metot isteği oturumdan alır. POST istekleri ona iletilir, diğerleri (GET) ise isteğin URL'sine yönlendirilir. Metot, isteğin şu anda oturum açmış olan kullanıcının kendisi tarafından oluşturulduğunu doğrular. Başka bir kullanıcı giriş yaparsa veya anahtar geçersizse hiçbir şey yapmaz ve program her zamanki gibi devam eder.

Önceki sayfaya nasıl dönülür kılavuzuna bakın.

Kanonikleştirme

Presenter'ların, daha iyi SEO'ya (arama motoru optimizasyonuna) katkıda bulunan gerçekten mükemmel bir özelliği vardır. Aynı içeriğin farklı URL'lerde bulunmasını otomatik olarak engellerler. Belirli bir hedefe birden fazla URL gidiyorsa, örneğin /index ve /index?page=1, framework bunlardan birini birincil (kanonik) sayar ve diğerlerini HTTP kodu 301 ile ona yönlendirir. Bu sayede arama motorları sayfalarınızı iki kez indekslemez ve sayfa sıralamanızı seyreltmez.

Bu sürece kanonikleştirme denir. Kanonik URL, router tarafından üretilen, genellikle koleksiyondaki ilk uyan rotanın URL'sidir.

Kanonikleştirme varsayılan olarak etkindir ve $this->autoCanonicalize = false ile kapatılabilir.

AJAX veya POST istekleri sırasında yönlendirme yapılmaz, çünkü bu veri kaybına yol açabilir ya da SEO açısından ek bir değer sunmaz.

Kanonikleştirmeyi canonicalize() metoduyla elle de tetikleyebilirsiniz. link() metoduna benzer şekilde ona presenter'ı, eylemi ve parametreleri verirsiniz. Bir bağlantı üretir ve onu geçerli URL adresiyle karşılaştırır. Farklılarsa üretilen bağlantıya yönlendirir.

public function actionShow(int $id, ?string $slug = null): void
{
	$realSlug = $this->facade->getSlugForId($id);
	// $slug, $realSlug'dan farklıysa yönlendirir
	$this->canonicalize('Product:show', [$id, $realSlug]);
}

SEO dostu URL'ler üretmek için rota filtrelerini canonicalize() ile birleştiren eksiksiz bir desen için Slug'lu güzel URL'ler bölümüne bakın.

Yanıtlar

Presenter'ın döndürdüğü yanıt, Nette\Application\Response arayüzünü uygulayan bir nesnedir. Hazır birkaç yanıt vardır:

Yanıtlar sendResponse() metoduyla gönderilir:

use Nette\Application\Responses;

// Düz metin
$this->sendResponse(new Responses\TextResponse('Hello Nette!'));

// Dosya gönderir
$this->sendResponse(new Responses\FileResponse(__DIR__ . '/invoice.pdf', 'Invoice13.pdf'));

// Callback gönderir
$callback = function (Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) {
	if ($httpResponse->getHeader('Content-Type') === 'text/html') {
		echo '<h1>Hello</h1>';
	}
};
$this->sendResponse(new Responses\CallbackResponse($callback));

Kendi yanıtınızı da yazabilirsiniz. HTTP isteğini ve yanıtını alan tek bir send() metoduna sahip Nette\Application\Response arayüzünü uygulamanız yeterlidir. Bu, örneğin bellekte tutmak istemediğiniz veriyi akışla gönderirken işe yarar:

class CsvResponse implements Nette\Application\Response
{
	public function __construct(
		private string $fileName,
		private iterable $rows,
	) {
	}

	public function send(Nette\Http\IRequest $request, Nette\Http\IResponse $response): void
	{
		$response->setContentType('text/csv', 'utf-8');
		$response->sendAsFile($this->fileName);

		$handle = fopen('php://output', 'w');
		foreach ($this->rows as $row) {
			fputcsv($handle, $row);
		}

		fclose($handle);
	}
}

Sonra onu presenter'da her zamanki gibi gönderirsiniz: $this->sendResponse(new CsvResponse('export.csv', $rows));

HTTP önbelleklemesi

lastModified() metodu, HTTP önbelleklemesinden kolayca yararlanmayı sağlar. Ona içeriğin son değiştirilme tarih ve saatini (marka zamanı, dize veya DateTimeInterface nesnesi olarak), isteğe bağlı olarak bir ETag doğrulayıcısını (içeriğin geçerli sürümünü tanımlayan kısa bir dize, örneğin hash'i) ve bir sona erme süresini verirsiniz. Tarayıcı zaten uyan bir sürüme sahipse, presenter 304 Not Modified yanıtı gönderir ve sonlanır; böylece sayfa gereksiz yere render edilmez veya aktarılmaz:

public function renderArticle(int $id): void
{
	$article = $this->articles->getById($id);
	$this->lastModified($article->updatedAt);
	// ...
}

Şablonun tamamlanması

Presenter bir şablonu render ederken, sendTemplate() metodu render'dan hemen önce completeTemplate()'i çağırır. Bu metot #[TemplateVariable] niteliğiyle işaretlenmiş değişkenleri doldurur ve şablon dosyasını bulur (varsayılan değişkenler, şablon oluşturulurken zaten TemplateFactory tarafından ayarlanır). Tüm görünümlerde ortak değişkenler eklemek veya farklı bir dosya belirlemek için bu protected metodu ezebilirsiniz:

protected function completeTemplate(Nette\Application\UI\Template $template): void
{
	parent::completeTemplate($template);
	$template->siteName = 'Uygulamam';
}

#[Requires] ile erişimi kısıtlama

#[Requires] niteliği, presenter'lara ve metotlarına erişimi kısıtlamak için gelişmiş seçenekler sunar. HTTP metotlarını belirtmek, AJAX isteği zorunlu kılmak, aynı origin'e kısıtlamak ve yalnızca forward yoluyla erişime izin vermek için kullanılabilir. Nitelik hem presenter sınıflarına hem de action<Eylem>(), render<Görünüm>(), handle<Sinyal>() ve createComponent<Ad>() gibi tek tek metotlara uygulanabilir.

Şu kısıtlamaları belirtebilirsiniz:

  • HTTP metotlarına: #[Requires(methods: ['GET', 'POST'])]
  • AJAX isteği zorunluluğu: #[Requires(ajax: true)]
  • yalnızca aynı origin'den erişim: #[Requires(sameOrigin: true)]
  • yalnızca forward yoluyla erişim: #[Requires(forward: true)]
  • belirli eylemlere kısıtlama: #[Requires(actions: 'default')]

3.3 sürümünden beri aynı origin eşleşmesi, tarayıcının Sec-Fetch-Site header'ı kullanılarak doğrulanır (önceden bir SameSite çerezi üzerinden); bu daha güvenilirdir ve şemanın, alan adının ve portun tam eşleşmesini denetler.

Ayrıntıları Requires niteliği nasıl kullanılır kılavuzunda bulabilirsiniz.

HTTP metodunun denetimi

Nette'teki presenter'lar, öncelikle güvenlik nedeniyle, gelen her isteğin HTTP metodunu otomatik doğrular. Varsayılan olarak GET, POST, HEAD, PUT, DELETE, PATCH metotlarına izin verilir.

Ek olarak örneğin OPTIONS metoduna da izin vermek isterseniz #[Requires] niteliğini kullanın (Nette Application v3.2.3'ten beri):

#[Requires(methods: ['GET', 'POST', 'HEAD', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])]
class MyPresenter extends Nette\Application\UI\Presenter
{
}

3.1.13 sürümünden beri doğrulama, istekte belirtilen metodun $presenter->allowedMethods dizisinde bulunup bulunmadığını denetleyen checkHttpMethod() içinde yapılır. 3.2.3 sürümünden itibaren bu yaklaşım #[Requires] lehine kullanımdan kaldırılmıştır. Metodu şöyle ezebilirsiniz:

class MyPresenter extends Nette\Application\UI\Presenter
{
	protected function checkHttpMethod(): void
	{
		$this->allowedMethods[] = 'OPTIONS';
		parent::checkHttpMethod();
	}
}

Şunu vurgulamak önemli: OPTIONS metodunu etkinleştirirseniz, ardından onu presenter'ınızda uygun şekilde işlemeniz gerekir. Bu metot sıklıkla preflight isteği olarak kullanılır; tarayıcı, isteğin CORS (Cross-Origin Resource Sharing) politikasına göre izin verilebilir olup olmadığını belirlemek gerektiğinde asıl istekten önce onu otomatik gönderir. Metodu etkinleştirip doğru yanıtı uygulamazsanız, bu tutarsızlıklara ve olası güvenlik sorunlarına yol açabilir.

Kullanımdan kaldırılan eylemleri işaretleme

#[Deprecated] niteliği; eylemleri, sinyalleri veya tüm presenter'ları kullanımdan kaldırılmış ve ileride silinmek üzere planlanmış diye işaretler. Uygulamanın kullanımdan kaldırılmış bölümlerine bağlantı üretilirken Nette, geliştiricileri uyarmak için bir uyarı fırlatır.

Niteliği ya tüm presenter sınıfına ya da tek tek action<Eylem>(), render<Görünüm>() ve handle<Sinyal>() metotlarına uygulayabilirsiniz.

İleri okuma

versiyon: 4.x