Sunum Yapanlar

Nette sunumların ve şablonların nasıl yazılacağını öğreneceğiz. Okuduktan sonra öğreneceksiniz:

  • sunum yapan ki̇şi̇ nasil çalişir
  • kalıcı parametreler nedir
  • şablon nasıl oluşturulur

Bir sunucunun, ana sayfa; e-mağazadaki ürün; oturum açma formu; site haritası beslemesi vb. gibi bir web uygulamasının belirli bir sayfasını temsil eden bir sınıf olduğunuzaten biliyoruz. Uygulama bir ila binlerce sunucuya sahip olabilir. Diğer çerçevelerde, kontrolörler olarak da bilinirler.

Genellikle, sunucu terimi, web arayüzleri için uygun olan ve bu bölümün geri kalanında tartışacağımız Nette\Application\UI\Presenter sınıfının bir torununu ifade eder. Genel anlamda, bir sunucu Nette\Application\IPresenter arayüzünü uygulayan herhangi bir nesnedir.

Sunucunun Yaşam Döngüsü

Sunucunun görevi, isteği işlemek ve bir yanıt (bir HTML sayfası, görüntü, yönlendirme vb. olabilir) döndürmektir.

Yani başlangıçta bir istek var. Bu doğrudan bir HTTP isteği değil, HTTP isteğinin bir yönlendirici kullanılarak dönüştürüldüğü bir Nette\Application\Request nesnesidir. Genellikle bu nesneyle temas etmeyiz, çünkü sunucu isteğin işlenmesini akıllıca özel yöntemlere devreder, şimdi bunları göreceğiz.

Sunucunun yaşam döngüsü

Şekilde, eğer varsa, yukarıdan aşağıya doğru sırayla çağrılan yöntemlerin bir listesi gösterilmektedir. Hiçbirinin var olmasına gerek yoktur, tek bir yöntem olmadan tamamen boş bir sunucuya sahip olabilir ve üzerinde basit bir statik web oluşturabiliriz.

__construct()

Yapıcı tam olarak sunucunun yaşam döngüsüne ait değildir, çünkü nesnenin yaratıldığı anda çağrılır. Ancak öneminden dolayı bundan bahsediyoruz. Yapıcı ( inject yöntemiyle birlikte) bağımlılıkları aktarmak için kullanılır.

Sunucu, uygulamanın iş mantığıyla ilgilenmemeli, veritabanına yazmamalı ve veritabanından okumamalı, hesaplamalar yapmamalı vb. Bu, model olarak adlandırdığımız bir katmandaki sınıfların görevidir. Örneğin ArticleRepository sınıfı makalelerin yüklenmesinden ve kaydedilmesinden sorumlu olabilir. Sunucunun bunu kullanabilmesi için bağımlılık enjeksiyonu kullanılarak geçirilir:

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

startup()

İstek alındıktan hemen sonra startup () yöntemi çağrılır. Bunu özellikleri başlatmak, kullanıcı ayrıcalıklarını kontrol etmek vb. için kullanabilirsiniz. Her zaman parent::startup() atasının çağrılması gerekir.

action<Action>(args...)

Yönteme benzer şekilde render<View>(). O sırada render<View>() 'de daha sonra işlenecek olan belirli bir şablon için veri hazırlamak üzere tasarlanmıştır. action<Action>() Bir istek, şablon oluşturmayı takip etmeden işlenir. Örneğin, veriler işlenir, bir kullanıcı oturum açar veya kapatır vb. ve ardından başka bir yere yönlendirir.

Bu önemlidir action<Action>() daha önce çağrılır render<View>()Bu nedenle, içinde muhtemelen yaşam döngüsünün bir sonraki seyrini değiştirebiliriz, yani oluşturulacak şablonu ve ayrıca yöntemi değiştirebiliriz render<View>() setView('otherView') kullanılarak çağrılacaktır.

İstekten gelen parametreler yönteme aktarılır. Parametreler için tür belirtmek mümkündür ve önerilir, örneğin actionShow(int $id, ?string $slug = null) – id parametresi eksikse veya tamsayı değilse, sunum yapan kişi 404 hatası döndürür ve işlemi sonlandırır.

handle<Signal>(args...)

Bu yöntem, Bileşenler bölümünde tartışacağımız sözde sinyalleri işler. Esas olarak bileşenler ve AJAX isteklerinin işlenmesi için tasarlanmıştır.

Parametreler, aşağıdaki örnekte olduğu gibi yönteme geçirilir action<Action>()tip kontrolü de dahil olmak üzere.

beforeRender()

beforeRender yöntemi, adından da anlaşılacağı gibi, her yöntemden önce çağrılır render<View>(). Ortak şablon yapılandırması, düzen için değişkenlerin geçirilmesi vb. için kullanılır.

render<View>(args...)

Şablonu sonraki işleme için hazırladığımız, ona veri aktardığımız vb. yer.

Parametreler, aşağıdaki örnekte olduğu gibi yönteme geçirilir action<Action>()tip kontrolü de dahil olmak üzere.

public function renderShow(int $id): void
{
	// modelden veri alıyoruz ve bunu şablona aktarıyoruz
	$this->template->article = $this->articles->getById($id);
}

afterRender()

afterRender yöntemi, adından da anlaşılacağı gibi, her render<View>() yöntem. Oldukça nadiren kullanılır.

shutdown()

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

Devam etmeden önce iyi bir tavsiye. Gördüğünüz gibi, sunum yapan kişi daha fazla eylemi/görüntüyü işleyebilir, yani daha fazla metoda sahip olabilir render<View>(). Ancak sunum yapanların bir veya mümkün olduğunca az eylemle tasarlanmasını öneriyoruz.

Yanıt Gönderme

Sunucunun yanıtı genellikle HTML sayfasıyla şablonu işlemektir, ancak bir dosya, JSON göndermek veya hatta başka bir sayfaya yönlendirmek de olabilir.

Yaşam döngüsü sırasında herhangi bir zamanda, bir yanıt göndermek ve aynı zamanda sunum yapan kişiden çıkmak için aşağıdaki yöntemlerden herhangi birini kullanabilirsiniz:

Bu yöntemlerden herhangi birini çağırmazsanız, sunum yapan kişi otomatik olarak şablonu oluşturmaya devam edecektir. Neden mi? Çünkü vakaların %99'unda bir şablon çizmek isteriz, bu nedenle sunum yapan kişi bu davranışı varsayılan olarak alır ve işimizi kolaylaştırmak ister.

Presenter, diğer presenter'lara URL bağlantıları oluşturmak için kullanılan link() yöntemine sahiptir. İlk parametre hedef sunumcu ve eylemdir, ardından dizi olarak geçirilebilen argümanlar gelir:

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

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

Şablonda diğer sunumculara ve eylemlere aşağıdaki gibi bağlantılar oluşturuyoruz:

<a n:href="Product:show $id">product detail</a>

Gerçek URL yerine tanıdık Presenter:action çiftini yazmanız ve parametreleri eklemeniz yeterlidir. İşin püf noktası, bu özelliğin Latte tarafından işleneceğini ve gerçek bir URL oluşturacağını söyleyen n:href adresidir. Nette'de URL'ler hakkında hiç düşünmek zorunda değilsiniz, sadece sunucular ve eylemler hakkında.

Daha fazla bilgi için Bağlantı Oluşturma bölümüne bakın.

Yeniden Yönlendirme

redirect() ve forward() yöntemleri, link() yöntemine çok benzer bir sözdizimine sahip olan başka bir sunucuya atlamak için kullanılır.

forward() HTTP yeniden yönlendirmesi olmadan hemen yeni sunucuya geçer:

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

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

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

HTTP kodu 301 ile kalıcı yeniden yönlendirme elde etmek için kullanın:

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

redirectUrl() yöntemini kullanarak uygulama dışında başka bir URL'ye yönlendirme yapabilirsiniz. HTTP kodu ikinci parametre olarak belirtilebilir; varsayılan değer 302'dir (veya geçerli istek yöntemi POST ise 303'tür):

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

Yeniden yönlendirme, Nette\Application\AbortException sessiz sonlandırma istisnasını fırlatarak sunum yapan kişinin yaşam döngüsünü derhal sonlandırır.

Yönlendirmeden önce, yönlendirmeden sonra şablonda görüntülenecek bir flash mesaj, mesajlar göndermek mümkündür.

Flaş Mesajlar

Bunlar genellikle bir işlemin sonucu hakkında bilgi veren mesajlardır. Flash mesajların önemli bir özelliği, yeniden yönlendirmeden sonra bile şablonda mevcut olmalarıdır. Görüntülendikten sonra bile 30 saniye daha canlı kalırlar – örneğin, kullanıcının istemeden sayfayı yenilemesi durumunda – mesaj kaybolmaz.

Sadece flashMessage() yöntemini çağırın ve presenter mesajı şablona aktarmakla ilgilenecektir. İlk bağımsız değişken mesajın metnidir ve isteğe bağlı ikinci bağımsız değişken mesajın türüdür (hata, uyarı, bilgi vb.). flashMessage() yöntemi, daha fazla bilgi eklememize izin vermek için bir flash mesajı örneği döndürür.

$this->flashMessage('Item was removed.');
$this->redirect(/* ... */);

Şablonda, bu mesajlar $flashes değişkeninde message (mesaj metni), type (mesaj türü) özelliklerini içeren ve daha önce bahsedilen kullanıcı bilgilerini içerebilen stdClass nesneleri olarak mevcuttur. Bunları aşağıdaki gibi çiziyoruz:

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

Hata 404 vb.

Örneğin görüntülemek istediğimiz makale veritabanında bulunmadığı için isteği yerine getiremediğimizde, HTTP hatası 404'ü temsil eden error(?string $message = null, int $httpCode = 404) yöntemini kullanarak 404 hatasını atacağız:

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

HTTP hata kodu ikinci parametre olarak geçirilebilir, varsayılan 404'tür. Yöntem, Nette\Application\BadRequestException istisnasını fırlatarak çalışır ve ardından Application kontrolü hata sunucusuna geçirir. Bu, görevi hata hakkında bilgi veren bir sayfa görüntülemek olan bir sunumcudur. Hata sunucusu uygulama yapılandırmasında ayarlanır.

JSON Gönderme

JSON biçiminde veri gönderen ve sunum yapan kişiden çıkan eylem yöntemi örneği:

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

İstek Parametreleri

Sunucu ve her bileşen, parametrelerini HTTP isteğinden alır. Değerleri getParameter($name) yöntemi veya getParameters() kullanılarak alınabilir. Değerler dizeler veya dizelerin dizileridir, esasen doğrudan URL'den elde edilen ham verilerdir.

Daha fazla kolaylık için, parametreleri özellikler aracılığıyla erişilebilir hale getirmenizi öneririz. Bunları basitçe şu şekilde açıklayın #[Parameter] nitelik:

use Nette\Application\Attributes\Parameter;  // bu hat önemli

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

Özellikler için veri türünü belirtmenizi öneririz (örneğin, string). Nette daha sonra değeri buna göre otomatik olarak dökecektir. Parametre değerleri de doğrulanabilir.

Bir bağlantı oluştururken, parametreler için değeri doğrudan ayarlayabilirsiniz:

<a n:href="Home:default theme: dark">click</a>

Kalıcı Parametreler

Kalıcı parametreler, farklı istekler arasında durumu korumak için kullanılır. Bir bağlantı tıklandıktan sonra bile değerleri aynı kalır. Oturum verilerinin aksine, URL'de aktarılırlar. Bu tamamen otomatiktir, bu nedenle bunları link() veya n:href adresinde açıkça belirtmeye gerek yoktur.

Kullanım örneği? Çok dilli bir uygulamanız var. Gerçek dil, her zaman URL'nin bir parçası olması gereken bir parametredir. Ancak bunu her bağlantıya dahil etmek inanılmaz derecede sıkıcı olacaktır. Bu yüzden onu lang adında kalıcı bir parametre yaparsınız ve kendi kendini taşır. Harika!

Kalıcı bir parametre oluşturmak Nette son derece kolaydır. Sadece bir public özellik oluşturun ve şu nitelikle etiketleyin: (daha önce /** @persistent */ kullanılıyordu)

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

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

$this->lang, 'en' gibi bir değere sahipse, link() veya n:href kullanılarak oluşturulan bağlantılar da lang=en parametresini içerecektir. Ve bağlantı tıklandığında, yine $this->lang = 'en' olacaktır.

Özellikler için veri türünü eklemenizi öneririz (örn. string) ve ayrıca varsayılan bir değer de ekleyebilirsiniz. Parametre değerleri doğrulanabilir.

Kalıcı parametreler varsayılan olarak belirli bir sunum yapan kişinin tüm eylemleri arasında aktarılır. Bunları birden fazla sunum yapan kişi arasında geçirmek için tanımlamanız gerekir:

  • Sunum yapanların miras aldığı ortak bir atada
  • sunum yapanların kullandığı özellikte:
trait LanguageAware
{
	#[Persistent]
	public string $lang;
}

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

Bir bağlantı oluştururken kalıcı bir parametrenin değerini değiştirebilirsiniz:

<a n:href="Product:show $id, lang: cs">detail in Czech</a>

Ya da reset edilebilir, yani URL'den kaldırılabilir. Daha sonra varsayılan değerini alacaktır:

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

İnteraktif Bileşenler

Sunucular yerleşik bir bileşen sistemine sahiptir. Bileşenler, sunucuların içine yerleştirdiğimiz ayrı yeniden kullanılabilir birimlerdir. Bunlar formlar, datagridler, menüler, aslında tekrar tekrar kullanılması mantıklı olan her şey olabilir.

Bileşenler sunum aracına nasıl yerleştirilir ve daha sonra nasıl kullanılır? Bu konu Bileşenler bölümünde açıklanmaktadır. Hatta bunların Hollywood ile ne ilgisi olduğunu bile öğreneceksiniz.

Bazı Bileşenleri Nereden Alabilirim? Componette sayfasında, Nette Framework topluluğu tarafından yapılan ve paylaşılan bazı açık kaynaklı bileşenleri ve Nette için diğer eklentileri bulabilirsiniz.

Daha Derine Gitmek

Bu bölümde şimdiye kadar gösterdiklerimiz muhtemelen yeterli olacaktır. Aşağıdaki satırlar, sunum yapanlarla derinlemesine ilgilenen ve her şeyi bilmek isteyenlere yöneliktir.

Parametrelerin Doğrulanması

URL'lerden alınan istek parametr eleri ve kalıcı parametrelerin değerleri loadState() metodu tarafından özelliklere yazılır. Ayrıca özellikte belirtilen veri tipinin eşleşip eşleşmediğini kontrol eder, aksi takdirde 404 hatası ile yanıt verir ve sayfa görüntülenmez.

URL'de kullanıcı tarafından kolayca üzerine yazılabilecekleri için parametrelere asla körü körüne güvenmeyin. Örneğin, $this->lang adresinin desteklenen diller arasında olup olmadığını bu şekilde kontrol ederiz. Bunu yapmanın iyi bir yolu, yukarıda bahsedilen loadState() yöntemini geçersiz kılmaktır:

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

	public function loadState(array $params): void
	{
		parent::loadState($params); // burada $this->lang ayarlanır
		// kullanıcı değeri kontrolünü takip eder:
		if (!in_array($this->lang, ['en', 'cs'])) {
			$this->error();
		}
	}
}

Talebi Kaydetme ve Geri Yükleme

Sunum yapan kişinin ele aldığı istek bir Nette\Application\Request nesnesidir ve sunum yapan kişinin getRequest() yöntemi tarafından döndürülür.

Geçerli isteği bir oturuma kaydedebilir veya oturumdan geri yükleyebilir ve sunum yapan kişinin bunu tekrar yürütmesine izin verebilirsiniz. Bu, örneğin bir kullanıcı bir formu doldurduğunda ve oturum açma süresi dolduğunda kullanışlıdır. Verileri kaybetmemek için, oturum açma sayfasına yönlendirmeden önce, kısa bir dize biçiminde bir tanımlayıcı döndüren ve oturum açma sunucusuna parametre olarak ileten $reqId = $this->storeRequest() adresini kullanarak geçerli isteği oturuma kaydederiz.

Oturum açtıktan sonra, isteği oturumdan alan ve ona ileten $this->restoreRequest($reqId) yöntemini çağırıyoruz. Yöntem, isteğin şu anda oturum açmış olan kullanıcıyla aynı kullanıcı tarafından oluşturulduğunu doğrular. Başka bir kullanıcı giriş yaparsa veya anahtar geçersizse, hiçbir şey yapmaz ve program devam eder.

Daha önceki bir sayfaya nasıl dönülür yemek kitabına bakın.

Kanonizasyon

Sunucular SEO'yu (internette aranabilirliğin optimizasyonu) geliştiren gerçekten harika bir özelliğe sahiptir. Farklı URL'lerde yinelenen içeriğin varlığını otomatik olarak önlerler. Birden fazla URL belirli bir hedefe yönlendiriyorsa, örneğin /index ve /index?page=1, çerçeve bunlardan birini birincil (kanonik) olarak belirler ve diğerlerini HTTP kodu 301 kullanarak ona yönlendirir. Bu sayede arama motorları sayfaları iki kez indekslemez ve sayfa sıralamalarını zayıflatmaz.

Bu işleme kanonizasyon denir. Kanonik URL, genellikle koleksiyondaki ilk uygun rota olan yönlendirici tarafından oluşturulan URL'dir.

Kanonizasyon varsayılan olarak açıktır ve $this->autoCanonicalize = false adresinden kapatılabilir.

Yeniden yönlendirme bir AJAX veya POST isteği ile gerçekleşmez çünkü veri kaybına neden olur veya SEO katma değeri olmaz.

Ayrıca, link() yöntemi gibi sunum yapan kişiyi, eylemleri ve parametreleri bağımsız değişken olarak alan canonicalize() yöntemini kullanarak kanonlaştırmayı manuel olarak da çağırabilirsiniz. Bir bağlantı oluşturur ve bunu geçerli URL ile karşılaştırır. Farklıysa, oluşturulan bağlantıya yönlendirir.

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

Etkinlikler

Sunum yapan kişinin yaşam döngüsünün bir parçası olarak çağrılan startup(), beforeRender() ve shutdown() yöntemlerine ek olarak, otomatik olarak çağrılacak başka işlevler de tanımlanabilir. Sunum yapan kişi sözde olayları tanımlar ve siz de bunların 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() yönteminden hemen önce, ardından $onRender ile beforeRender() arasında çağrılır. render<View>() ve son olarak shutdown() adresinden hemen önce $onShutdown.

Yanıtlar

Sunucu tarafından döndürülen yanıt, Nette\Application\Response arayüzünü uygulayan bir nesnedir. Bir dizi hazır yanıt vardır:

Yanıtlar sendResponse() yöntemi ile gönderilir:

use Nette\Application\Responses;

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

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

// Bir geri arama 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));

Erişim Kısıtlaması Kullanımı #[Requires]

Bu #[Requires] özniteliği, sunum yapanlara ve yöntemlerine erişimi kısıtlamak için gelişmiş seçenekler sağlar. HTTP yöntemlerini belirtmek, AJAX istekleri gerektirmek, erişimi aynı kaynakla sınırlamak ve erişimi yalnızca yönlendirme ile kısıtlamak için kullanılabilir. Öznitelik, sunum yapan sınıfların yanı sıra aşağıdaki gibi bireysel yöntemlere de uygulanabilir action<Action>(), render<View>(), handle<Signal>()ve createComponent<Name>().

Bu kısıtlamaları belirtebilirsiniz:

  • HTTP yöntemleri üzerinde: #[Requires(methods: ['GET', 'POST'])]
  • AJAX isteği gerektiriyor: #[Requires(ajax: true)]
  • yalnızca aynı kaynaktan erişim: #[Requires(sameOrigin: true)]
  • yalnızca yönlendirme yoluyla erişim: #[Requires(forward: true)]
  • belirli eylemlere ilişkin kısıtlamalar: #[Requires(actions: 'default')]

Ayrıntılar için, bkz Nasıl kullanılır Requires öznitelik.

HTTP Yöntem Kontrolü

Nette'de sunum yapanlar, öncelikle güvenlik nedenleriyle gelen her isteğin HTTP yöntemini otomatik olarak doğrular. Varsayılan olarak GET, POST, HEAD, PUT, DELETE, PATCH yöntemlerine izin verilir.

OPTIONS gibi ek yöntemleri etkinleştirmek istiyorsanız #[Requires] özniteliği (Nette Uygulaması v3.2'den):

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

Sürüm 3.1'de doğrulama, istekte belirtilen yöntemin $presenter->allowedMethods dizisine dahil edilip edilmediğini kontrol eden checkHttpMethod() içinde gerçekleştirilir. Bunun gibi bir yöntem ekleyin:

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

OPTIONS yöntemini etkinleştirirseniz, bunu sunucunuzda da düzgün bir şekilde ele almanız gerektiğini vurgulamak çok önemlidir. Bu yöntem genellikle, tarayıcıların CORS (Cross-Origin Resource Sharing) politikası açısından isteğe izin verilip verilmediğini belirlemek için gerekli olduğunda asıl istekten önce otomatik olarak gönderdiği bir ön kontrol isteği olarak kullanılır. Bu yönteme izin verir ancak uygun bir yanıt uygulamazsanız, tutarsızlıklara ve potansiyel güvenlik sorunlarına yol açabilir.

Daha Fazla Okuma

versiyon: 4.0