Tek Gönderi Sayfası

Blogumuza, belirli bir gönderinin içeriğini gösterecek bir sayfa daha ekleyelim.

Belirli bir gönderiyi alıp şablona aktaracak yeni bir render metodu oluşturmamız gerekiyor. Bu metodu HomePresenter içine koymak pek derli toplu olmaz; çünkü konu ana sayfa değil tek bir gönderi. Öyleyse yeni bir PostPresenter sınıfı oluşturup onu app/Presentation/Post/ dizinine koyalım. Bu presenter'ın da bir veritabanı bağlantısına ihtiyacı olacak, dolayısıyla veritabanı bağlantısını isteyecek yapıcıyı ekleyeceğiz.

PostPresenter şöyle görünebilir:

<?php
namespace App\Presentation\Post;

use Nette;
use Nette\Application\UI\Form;

final class PostPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	public function renderShow(int $id): void
	{
		$this->template->post = $this->database
			->table('posts')
			->get($id);
	}
}

Presenter eşlemesi yapılandırmasına bağlı olan doğru App\Presentation\Post isim alanını belirtmeyi unutmamalıyız.

renderShow metodu bir argüman ister: gösterilecek gönderinin ID'si. Sonra gönderiyi veritabanından yükler ve şablona aktarır.

Home/default.latte şablonuna Post:show eylemine bir bağlantı ekliyoruz:

...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...

{link} etiketi, Post:show eylemine işaret eden bir URL adresi üretir. Ayrıca gönderi ID'sini argüman olarak aktarır.

Aynı şey bir n:attribute ile derli toplu biçimde yazılabilir:

...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...

n:href niteliği {link} etiketine benzer.

Ancak Post:show eyleminin şablonu henüz yok. Bu gönderiye giden bağlantıyı açmayı deneyebiliriz. Tracy, Post/show.latte şablonu henüz var olmadığı için bir hata gösterecek. Farklı bir hata mesajı görüyorsanız, büyük olasılıkla web sunucunuzda mod_rewrite modülünü etkinleştirmeniz gerekiyor.

Öyleyse Post/show.latte dosyasını şu içerikle oluşturacağız:

{block content}

<p><a n:href="Home:default">← gönderi listesine dön</a></p>

<div class="date">{$post->created_at|date:'F j, Y'}</div>

<h1 n:block="title">{$post->title}</h1>

<div class="post">{$post->content}</div>

Şimdi şablonun tek tek parçalarını gözden geçirelim.

İlk satır, tıpkı ana sayfadaki gibi “content” adlı bir bloğun tanımını başlatır. Bu blok yine ana yerleşim şablonunun içinde görüntülenecek. Gördüğünüz gibi kapanış {/block} etiketi yok. O isteğe bağlıdır.

İkinci satır, blog gönderilerinin listesine geri dönmeyi sağlayan bir bağlantı sunar; böylece kullanıcı gönderi listesiyle belirli bir gönderi arasında kolayca gezinebilir. Yine n:href niteliğini kullanıyoruz, dolayısıyla URL üretmeyi Nette üstlenecek. Bağlantı, Home presenter'ının default eylemine işaret eder (n:href="Home:" de yazabilirdiniz; çünkü default eylem adı atlanabilir, otomatik eklenir).

Üçüncü satır, tarihi zaten bildiğimiz bir filtreyle biçimlendirir.

Dördüncü satır, blog gönderisinin başlığını bir <h1> HTML etiketinin içinde gösterir. Bu etiket, tanımayabileceğiniz bir nitelik içerir (n:block="title"). Ne yaptığını tahmin edebilir misiniz? Önceki bölümü dikkatle okuduysanız onun bir n:attribute olduğunu zaten biliyorsunuz. Bu, şuna eşdeğer bir başka örnektir:

{block title}<h1>{$post->title}</h1>{/block}

Basitçe söylemek gerekirse, bu blok title adlı bloğu yeniden tanımlar. Bu blok, ana layout şablonunda (/app/Presentation/@layout.latte:11) zaten tanımlıdır ve tıpkı OOP'deki metot geçersiz kılma gibi, bu blok ana şablondakini geçersiz kılar. Bu yüzden sayfanın <title> etiketi artık gösterilen gönderinin başlığını içerecek ve tek gereken bu basit n:block="title" niteliğiydi. Harika, değil mi?

Şablonun beşinci ve son satırı, belirli gönderinin içeriğinin tamamını gösterir.

Gönderi ID'sini Denetleme

Biri URL'deki ID'yi değiştirip var olmayan bir id koyarsa ne olur? Kullanıcıya güzel bir “sayfa bulunamadı” hatası göstermeliyiz. PostPresenter içindeki render metodunu biraz değiştirelim:

public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Post not found');
	}

	$this->template->post = $post;
}

Gönderi bulunamazsa, $this->error(...) çağrısı anlaşılır bir mesaj içeren bir 404 sayfası gösterecek. Geliştirme ortamında (localhost'ta) bu hata sayfasını görmeyeceğinizi unutmayın. Bunun yerine Tracy, istisnayı tüm ayrıntılarıyla gösterecek; bu da geliştirme için epey elverişlidir. İki kipi de sınamak isterseniz, Bootstrap.php dosyasında setDebugMode metoduna verilen argümanı değiştirmeniz yeter.

Özet

Gönderileri içeren bir veritabanımız ve iki view'lı bir web uygulamamız var; ilki tüm gönderilere genel bakış gösteriyor, ikincisi belirli bir gönderiyi gösteriyor.