Yorumlar
Blog yayına alındı, çok ilginç birkaç blog gönderisi yazdık ve onları Adminer ile yayımladık. İnsanlar blogumuzu okuyor ve ona büyük coşku duyuyor. Her gün övgü dolu pek çok e-posta alıyoruz. Ama tüm bu övgü yalnızca e-postamızda kalıyor ve başka kimse okuyamıyorsa ne işe yarar? Okuyucular doğrudan yazılara yorum yapabilseydi ve herkes ne kadar harika olduğumuzu görebilseydi daha iyi olmaz mıydı?
Hadi yorumları gerçekleştirelim.
Yeni Bir Tablo Oluşturma
Adminer'ı yeniden çalıştıralım ve şu sütunlarla bir comments tablosu oluşturalım:
idint, autoincrement (AI) işaretlipost_id,poststablosuna başvuran yabancı anahtarnamevarchar, uzunluk 255emailvarchar, uzunluk 255contenttextcreated_attimestamp
Tablo şuna benzer görünmelidir:

Yine InnoDB depolama motorunu kullanmayı unutmayın.
CREATE TABLE `comments` (
`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`post_id` int NOT NULL,
`name` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`content` text NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
) ENGINE=InnoDB CHARSET=utf8;
Yorum Formu
Önce, kullanıcıların gönderilere yorum yapmasını sağlayan bir form oluşturmamız gerekiyor. Nette Framework'ün formlar için mükemmel desteği vardır. Onları presenter'da yapılandırıp şablonda render edebiliriz.
Nette Framework, bileşen kavramını kullanır. Bileşen, başka bir bileşene iliştirilebilen, yeniden
kullanılabilir bir sınıf ya da kod parçasıdır. Presenter bile bir bileşendir. Her bileşen bir factory metoduyla
oluşturulur. PostPresenter içinde yorum formu için bir factory oluşturalım.
protected function createComponentCommentForm(): Form
{
$form = new Form; // yani Nette\Application\UI\Form
$form->addText('name', 'Adınız:')
->setRequired();
$form->addEmail('email', 'E-posta:');
$form->addTextArea('content', 'Yorum:')
->setRequired();
$form->addSubmit('send', 'Yorumu yayımla');
return $form;
}
Bunu kısaca açıklayalım. İlk satır, Form bileşeninin yeni bir örneğini oluşturur. Sonraki metotlar, form
tanımına HTML girdileri iliştirir. ->addText, bir <label>Adınız:</label> etiketiyle
birlikte <input type="text" name="name"> olarak render edilir. Tahmin edebileceğiniz gibi
->addTextArea bir <textarea>, ->addSubmit ise bir
<input type="submit"> ekler. Benzer pek çok metot var, ama şimdilik bunlar yeterli. Belgelerden daha fazlasını öğrenebilirsiniz.
Form bileşeni presenter'da tanımlandıktan sonra, onu şablonda render edebiliriz (gösterebiliriz). Bunun için
{control} etiketini, tek bir gönderiyi gösteren şablonun, yani Post/show.latte dosyasının sonuna
koyun. Bileşenin adı commentForm olduğundan (createComponentCommentForm metot adından türetilir),
etiket şöyle görünecek:
...
<h2>Yeni yorum yaz</h2>
{control commentForm}
Şimdi bir gönderinin ayrıntı sayfasını görüntülerseniz, sonda yeni yorum formunu göreceksiniz.
Veritabanına Kaydetme
Formu doldurup göndermeyi denediniz mi? Formun henüz aslında hiçbir şey yapmadığını fark etmiş olabilirsiniz. Gönderilen veriyi kaydedecek bir callback metodu iliştirmemiz gerekiyor.
commentForm bileşeninin factory metodunda return deyiminden önce şu satırı ekleyin:
$form->onSuccess[] = $this->commentFormSucceeded(...);
Bu satır, “form başarıyla gönderildikten sonra geçerli presenter'ın commentFormSucceeded metodunu
çağır” demektir. Bu metot henüz yok, hadi oluşturalım:
private function commentFormSucceeded(\stdClass $data): void
{
$id = $this->getParameter('id');
$this->database->table('comments')->insert([
'post_id' => $id,
'name' => $data->name,
'email' => $data->email,
'content' => $data->content,
]);
$this->flashMessage('Yorumunuz için teşekkürler', 'success');
$this->redirect('this');
}
Onu commentForm bileşen factory'sinin hemen ardına koymalısınız.
Yeni metodun bir argümanı var: bileşen factory'sinin oluşturduğu, gönderilen formun örneği. Gönderilen değerleri
$data içinde alırız. Sonra veriyi comments veritabanı tablosuna ekleriz.
Açıklanacak iki metot çağrısı daha var. redirect('this') metodu, harfi harfine geçerli sayfaya geri
yönlendirir. Bunu, bir form her başarıyla gönderildiğinde ve callback işlemi tamamlandığında yapmalısınız. Form
gönderiminden sonra yönlendirmek, tarayıcıdaki bilinen “Gönderi verilerini yeniden göndermek ister misiniz?” mesajını
da önler. (Genel olarak, bir formu POST metoduyla gönderdikten sonra her zaman bir GET eylemine
yönlendirmelisiniz.)
flashMessage metodu, kullanıcıyı bir işlemin sonucu hakkında bilgilendirmek için kullanılır. Yönlendirme
yaptığımızdan, mesaj öylece şablona aktarılıp doğrudan render edilemez. Bu metot mesajı saklar ve bir sonraki sayfa
yüklemesinde kullanılabilir kılar. Flash mesajları, app/Presentation/@layout.latte ana yerleşim şablonunda
render edilir ve şöyle görünür:
<div n:foreach="$flashes as $flash" n:class="flash, $flash->type">
{$flash->message}
</div>
Zaten bildiğimiz gibi flash mesajları şablona otomatik olarak aktarılır, dolayısıyla bunu pek düşünmemize gerek yok; öylece çalışır. Ayrıntılar için belgelere bakın.
Yorumların Render Edilmesi
Bu, öylece seveceğiniz özelliklerden biri. Nette Database'in Explorer adlı harika bir özelliği var. Veritabanı tablolarını InnoDB motoruyla bilinçli olarak nasıl oluşturduğumuzu anımsıyor musunuz? Adminer, bize bolca iş kazandıran yabancı anahtarlar oluşturdu.
Nette Database Explorer, tablolar arasındaki ilişkileri çözmek için bu yabancı anahtarları kullanır. Bu ilişkileri bilerek, veritabanı sorgularını sizin için otomatik oluşturabilir.
Anımsayacağınız gibi, PostPresenter::renderShow() içinde şablona $post değişkenini
aktarmıştık. Şimdi post_id sütunu bizim $post->id değerimizle eşleşen tüm yorumları
dolaşmak istiyoruz. Bunu $post->related('comments') çağırarak yapabiliriz. Evet, o kadar basit. Nihai koda
bakalım:
public function renderShow(int $id): void
{
// ...
$this->template->post = $post;
$this->template->comments = $post->related('comments')->order('created_at');
}
Ve şablon:
...
<h2>Yorumlar</h2>
<div class="comments">
{foreach $comments as $comment}
<p><b><a href="mailto:{$comment->email}" n:tag-if="$comment->email">
{$comment->name}
</a></b> şöyle dedi:</p>
<div>{$comment->content}</div>
{/foreach}
</div>
...
Özel n:tag-if niteliğine dikkat edin. n:attribute'ların nasıl çalıştığını zaten
biliyorsunuz. Niteliğin önüne tag- koyarsanız, işlev yalnızca HTML etiketinin kendisine uygulanır, içeriğine
değil. Bu, yorum yapanın adını yalnızca e-postasını verdiyse bağlantıya çevirmemizi sağlar. Şu iki satır aynı
sonucu verir:
<strong n:tag-if="$important"> Merhaba! </strong>
{if $important}<strong>{/if} Merhaba! {if $important}</strong>{/if}