Yorumlar

Blogu web sunucusuna yükledik ve Adminer kullanarak birkaç çok ilginç gönderi yayınladık. İnsanlar blogumuzu okuyor ve bundan çok heyecan duyuyorlar. Her gün övgülerle dolu birçok e-posta alıyoruz. Ama tüm bu övgüler sadece e-postamızda varsa ve kimse okuyamıyorsa ne anlamı var? Okuyucunun makaleye doğrudan yorum yapabilmesi daha iyi olurdu, böylece herkes ne kadar harika olduğumuzu okuyabilirdi.

Öyleyse yorumları programlayalım.

Yeni Tablo Oluşturma

Adminer'ı çalıştıralım ve şu sütunlarla comments tablosunu oluşturalım:

  • id int, autoincrement (AI) işaretleyin
  • post_id, posts tablosuna başvuran yabancı anahtar
  • name varchar, uzunluk 255
  • email varchar, uzunluk 255
  • content text
  • created_at timestamp

Tablo bu şekilde görünmelidir:

Yine InnoDB depolama alanını kullanmayı unutmayın.

CREATE TABLE `comments` (
	`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`post_id` int(11) NOT NULL,
	`name` varchar(250) NOT NULL,
	`email` varchar(250) 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

Öncelikle, kullanıcıların gönderilere yorum yapmasına olanak tanıyan bir form oluşturmamız gerekiyor. Nette Framework, formlar için harika bir desteğe sahiptir. Bunları presenter'da yapılandırabilir ve şablonda oluşturabiliriz.

Nette Framework, bileşenler kavramını kullanır. Bileşen, başka bir bileşene eklenebilen yeniden kullanılabilir bir sınıf veya kod parçasıdır. Presenter bile bir bileşendir. Her bileşen bir fabrika aracılığıyla oluşturulur. Bu nedenle, PostPresenter presenter'ında yorum formu için bir fabrika oluşturacağız.

protected function createComponentCommentForm(): Form
{
	$form = new Form; // Nette\Application\UI\Form anlamına gelir

	$form->addText('name', 'İsim:')
		->setRequired();

	$form->addEmail('email', 'E-posta:');

	$form->addTextArea('content', 'Yorum:')
		->setRequired();

	$form->addSubmit('send', 'Yorumu Yayınla');

	return $form;
}

Bunu biraz daha açıklayalım. İlk satır, Form bileşeninin yeni bir örneğini oluşturur. Sonraki metotlar, bu form tanımına HTML input elemanları ekler. ->addText, <label>İsim:</label> etiketiyle birlikte <input type="text" name="name"> olarak oluşturulacaktır. Muhtemelen doğru tahmin ettiğiniz gibi, ->addTextArea <textarea> olarak ve ->addSubmit <input type="submit"> olarak oluşturulacaktır. Çok daha fazla benzer metot vardır, ancak bunlar şimdilik bu form için yeterlidir. Daha fazlasını Formlar belgelerinde okuyabilirsiniz.

Form presenter'da zaten tanımlanmışsa, onu şablonda oluşturabiliriz (görüntüleyebiliriz). Bunu, şablonun sonuna, tek bir gönderiyi oluşturan Post/show.latte içine {control} etiketini yerleştirerek yaparız. Bileşenin adı commentForm olduğundan (createComponentCommentForm metodunun adından türetilmiştir), etiket şöyle görünecektir:

...
<h2>Yeni bir yorum ekleyin</h2>

{control commentForm}

Şimdi gönderi detay sayfasını görüntülerseniz, sonunda yeni yorum formunu göreceksiniz.

Veritabanına Kaydetme

Formu doldurup göndermeyi denediniz mi? Muhtemelen formun aslında hiçbir şey yapmadığını fark ettiniz. Gönderilen verileri kaydedecek bir geri arama metodu eklememiz gerekiyor.

commentForm bileşeni için fabrika içindeki return satırından önceki satıra aşağıdaki satırı yerleştirin:

$form->onSuccess[] = $this->commentFormSucceeded(...);

Önceki yazım “form başarıyla gönderildikten sonra mevcut presenter'dan commentFormSucceeded metodunu çağır” anlamına gelir. Ancak bu metot henüz mevcut değil. Öyleyse 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ür ederiz', 'success');
	$this->redirect('this');
}

Bu metodu doğrudan commentForm form fabrikasının arkasına yerleştirin.

Bu yeni metodun bir argümanı vardır, bu da gönderilen formun örneğidir – fabrika tarafından oluşturulmuştur. Gönderilen değerleri $data içinde alırız. Ve ardından verileri comments veritabanı tablosuna kaydederiz.

Açıklanması gereken iki metot daha var. Redirect metodu kelimenin tam anlamıyla mevcut sayfaya geri yönlendirir. Bu, geçerli veriler içeriyorsa ve geri arama işlemi gerektiği gibi gerçekleştirdiyse, her form gönderiminden sonra yapılması uygundur. Ayrıca, formu gönderdikten sonra sayfayı yönlendirirsek, tarayıcıda ara sıra görebileceğimiz iyi bilinen Form verilerini tekrar göndermek istiyor musunuz? mesajını görmeyiz. (Genel olarak, POST metoduyla bir form gönderdikten sonra her zaman bir GET eylemine yönlendirme yapılmalıdır.)

flashMessage metodu, kullanıcıyı bir işlemin sonucu hakkında bilgilendirmek içindir. Yönlendirme yaptığımız için, mesaj basitçe şablona aktarılıp oluşturulamaz. Bu nedenle, bu mesajı kaydeden ve bir sonraki sayfa yüklemesinde erişilebilir kılan bu metot vardır. Flash mesajları ana şablon app/Presentation/@layout.latte içinde oluşturulur ve şöyle görünür:

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

Bildiğimiz gibi, flash mesajları otomatik olarak şablona aktarılır, bu yüzden bunun hakkında fazla düşünmemize gerek yok, sadece çalışır. Daha fazla bilgi için belgeleri ziyaret edin.

Yorumları Oluşturma

Bu, kesinlikle seveceğiniz şeylerden biri. Nette Database, Explorer adlı harika bir özelliğe sahiptir. Veritabanındaki tabloları kasıtlı olarak InnoDB depolama alanını kullanarak oluşturduğumuzu hatırlıyor musunuz? Adminer böylece yabancı anahtarlar olarak adlandırılan ve bize çok iş kazandıran bir şey yarattı.

Nette Database Explorer, tablolar arasındaki karşılıklı ilişkiyi çözmek için yabancı anahtarları kullanır ve bu ilişkilerin bilgisiyle otomatik olarak veritabanı sorguları oluşturabilir.

Hatırlayacağınız gibi, $post değişkenini PostPresenter::renderShow() metoduyla şablona aktardık ve şimdi post_id sütununun değeri $post->id ile eşleşen tüm yorumlar üzerinde yineleme yapmak istiyoruz. Bunu $post->related('comments') çağrısıyla başarabiliriz. Evet, bu kadar basit. Sonuç koduna 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> yazdı:</p>

		<div>{$comment->content}</div>
	{/foreach}
</div>
...

Özel n:tag-if niteliğine dikkat edin. n:attributelerin nasıl çalıştığını zaten biliyorsunuz. Niteliğe tag- önekini eklerseniz, işlevsellik yalnızca HTML etiketine uygulanır, içeriğine değil. Bu, yorumcunun adını yalnızca e-postasını sağladığı takdirde bir bağlantı yapmamızı sağlar. Bu iki satır aynıdır:

<strong n:tag-if="$important"> Merhaba! </strong>

{if $important}<strong>{/if} Merhaba! {if $important}</strong>{/if}