Bir İletişim Formu Oluşturalım

Nette'de bir iletişim formunu, gönderilen verilerin e-postayla iletilmesi de dahil olmak üzere nasıl oluşturacağımıza bakalım. Başlayalım!

Önce yeni bir proje oluşturmamız gerekiyor. Başlangıç sayfası bunun nasıl yapılacağını anlatıyor. Sonra formu oluşturmaya başlayabiliriz.

En basit yaklaşım, formu doğrudan presenter'ın içinde oluşturmaktır. Var olan HomePresenter sınıfını kullanabiliriz. Formumuzu temsil etmesi için contactForm adlı bir bileşen ekleyeceğiz. Bunu, presenter'ın koduna bileşeni oluşturacak createComponentContactForm() factory metodunu ekleyerek yaparız:

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

class HomePresenter extends Presenter
{
	protected function createComponentContactForm(): Form
	{
		$form = new Form;
		$form->addText('name', 'Ad:')
			->setRequired('Lütfen adınızı girin');
		$form->addEmail('email', 'E-posta:')
			->setRequired('Lütfen e-postanızı girin');
		$form->addTextArea('message', 'Mesaj:')
			->setRequired('Lütfen bir mesaj girin');
		$form->addSubmit('send', 'Gönder');
		$form->onSuccess[] = $this->contactFormSucceeded(...);
		return $form;
	}

	private function contactFormSucceeded(Form $form, $data): void
	{
		// e-posta gönderimi
	}
}

Gördüğünüz gibi iki metot oluşturduk. İlki, createComponentContactForm(), yeni bir form örneği oluşturur. Sırasıyla addText(), addEmail() ve addTextArea() metotlarıyla eklenen ad, e-posta ve mesaj alanlarını içerir. Bir de gönder düğmesi ekledik. Peki kullanıcı bir alanı boş bırakırsa ne olur? O durumda ona alanın zorunlu olduğunu bildirmeliyiz. Bunu setRequired() metoduyla sağladık. Son olarak, form başarıyla gönderildiğinde tetiklenen onSuccess olayına bir işleyici bağladık. Bizim durumumuzda bu, gönderilen verilerin işlenmesini üstlenecek contactFormSucceeded metodunu çağırır. Bu metodu birazdan yazacağız.

contactForm bileşenini Home/default.latte şablonunda render edelim:

{block content}
<h1>İletişim Formu</h1>
{control contactForm}

E-postanın kendisini göndermek için ContactFacade adında yeni bir sınıf oluşturup app/Model/ContactFacade.php dosyasına koyacağız:

namespace App\Model;

use Nette\Mail\Mailer;
use Nette\Mail\Message;

class ContactFacade
{
	public function __construct(
		private Mailer $mailer,
	) {
	}

	public function sendMessage(string $email, string $name, string $message): void
	{
		$mail = new Message;
		$mail->addTo('admin@example.com') // sizin e-postanız
			->setFrom($email, $name)
			->setSubject('İletişim formundan mesaj')
			->setBody($message);

		$this->mailer->send($mail);
	}
}

sendMessage() metodu e-postayı oluşturur ve gönderir. Bunun için, yapıcı üzerinden bağımlılık olarak aldığı bir mailer servisini kullanır. E-posta gönderme hakkında daha fazlasını okuyun.

Şimdi presenter'a dönelim ve contactFormSucceeded() metodunu tamamlayalım. Bu metot, ContactFacade sınıfının sendMessage() metodunu çağıracak ve form üzerinden gönderilen verileri aktaracak. Peki ContactFacade nesnesini nasıl elde ederiz? Onu, bağımlılık enjeksiyonu kullanarak yapıcı üzerinden isteyeceğiz:

use App\Model\ContactFacade;
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;

class HomePresenter extends Presenter
{
	public function __construct(
		private ContactFacade $facade,
	) {
	}

	protected function createComponentContactForm(): Form
	{
		// ...
	}

	public function contactFormSucceeded(stdClass $data): void
	{
		$this->facade->sendMessage($data->email, $data->name, $data->message);
		$this->flashMessage('Mesaj gönderildi');
		$this->redirect('this');
	}
}

E-posta gönderildikten sonra kullanıcıya gönderimi doğrulayan bir flash mesajı gösteririz. Ardından, tarayıcı yenilenerek formun yeniden gönderilmesini önlemek için yönlendirme yaparız.

Yani her şey doğru kurulduysa, artık iletişim formunuzdan e-posta gönderebiliyor olmalısınız. Tebrikler!

HTML E-posta Şablonu

Şu anda yalnızca form üzerinden gönderilen mesajı içeren düz metin bir e-posta gönderiliyor. Ancak görünümünü daha çekici kılmak için e-postada HTML kullanabiliriz. Bunun için Latte'de bir şablon oluşturup app/Model/contactEmail.latte olarak kaydedeceğiz:

<html>
	<title>İletişim formundan mesaj</title>

	<body>
		<p><strong>Ad:</strong> {$name}</p>
		<p><strong>E-posta:</strong> {$email}</p>
		<p><strong>Mesaj:</strong> {$message}</p>
	</body>
</html>

Geriye ContactFacade sınıfını bu şablonu kullanacak şekilde değiştirmek kalıyor. Yapıcıda, Latte şablon render'ı olan Latte\Engine nesnesini oluşturabilen LatteFactory sınıfını isteyeceğiz. renderToString() metoduyla şablonu bir dizeye render ederiz. İlk parametre şablon dosyasının yolu, ikincisi ise ona aktarılacak değişkenlerden oluşan bir dizidir.

namespace App\Model;

use Nette\Bridges\ApplicationLatte\LatteFactory;
use Nette\Mail\Mailer;
use Nette\Mail\Message;

class ContactFacade
{
	public function __construct(
		private Mailer $mailer,
		private LatteFactory $latteFactory,
	) {
	}

	public function sendMessage(string $email, string $name, string $message): void
	{
		$latte = $this->latteFactory->create();
		$body = $latte->renderToString(__DIR__ . '/contactEmail.latte', [
			'email' => $email,
			'name' => $name,
			'message' => $message,
		]);

		$mail = new Message;
		$mail->addTo('admin@example.com') // sizin e-postanız
			->setFrom($email, $name)
			->setHtmlBody($body);

		$this->mailer->send($mail);
	}
}

Üretilen HTML e-posta içeriğini, özgün setBody() yerine setHtmlBody() metoduna aktarırız. Ayrıca e-postanın konusunu setSubject() ile belirtmemize de gerek kalmaz; kütüphane onu şablondaki <title> elemanından otomatik olarak çıkarır.

Yapılandırma

ContactFacade sınıfının kodunda yönetici e-postamız admin@example.com hâlâ sabit kodlanmış durumda. Bunu yapılandırma dosyasına taşımak daha iyi olurdu. Bunu nasıl yaparız?

Önce ContactFacade sınıfını değiştirin ve sabit kodlanmış e-posta dizesinin yerine yapıcı üzerinden aktarılan bir değişken koyun:

class ContactFacade
{
	public function __construct(
		private Mailer $mailer,
		private LatteFactory $latteFactory,
		private string $adminEmail,
	) {
	}

	public function sendMessage(string $email, string $name, string $message): void
	{
		// ...
		$mail = new Message;
		$mail->addTo($this->adminEmail)
			->setFrom($email, $name)
			->setHtmlBody($body);
		// ...
	}
}

İkinci adım, bu değişkenin değerini yapılandırmada vermektir. app/config/services.neon dosyasına şunu ekleyin:

services:
	- App\Model\ContactFacade(adminEmail: admin@example.com)

Ve hepsi bu. services bölümü çok sayıda girdi içeriyorsa ve e-posta adresinin aralarında kaybolduğunu düşünüyorsanız, onu bir parametreye dönüştürebiliriz. Girdiyi şöyle değiştirin:

services:
	- App\Model\ContactFacade(adminEmail: %adminEmail%)

Ve bu parametreyi app/config/common.neon dosyasında tanımlayın:

parameters:
	adminEmail: admin@example.com

Ve iş tamam!