Hozzunk létre egy kapcsolatfelvételi űrlapot

Nézzük meg, hogyan hozhatunk létre egy kapcsolatfelvételi űrlapot a Nette-ben, beleértve annak e-mailben történő elküldését is. Akkor csináljuk!

Először is létre kell hoznunk egy új projektet. Ahogy a Kezdő lépések oldal elmagyarázza. Ezután pedig elkezdhetjük létrehozni az űrlapot.

A legegyszerűbb, ha közvetlenül a Presenterben hozzuk létre az űrlapot. Használhatjuk az előre elkészített HomePresenter. Hozzáadjuk az űrlapot reprezentáló contactForm komponenst. Ezt úgy tesszük, hogy a createComponentContactForm() gyári metódust írjuk be a komponens előállítását végző kódba:

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

class HomePresenter extends Presenter
{
	protected function createComponentContactForm(): Form
	{
		$form = new Form;
		$form->addText('name', 'Name:')
			->setRequired('Enter your name');
		$form->addEmail('email', 'E-mail:')
			->setRequired('Enter your e-mail');
		$form->addTextarea('message', 'Message:')
			->setRequired('Enter message');
		$form->addSubmit('send', 'Send');
		$form->onSuccess[] = [$this, 'contactFormSucceeded'];
		return $form;
	}

	public function contactFormSucceeded(Form $form, $data): void
	{
		// sending an email
	}
}

Mint látható, két metódust hoztunk létre. Az első metódus createComponentContactForm() létrehoz egy új űrlapot. Ez rendelkezik a név, az e-mail és az üzenet mezőivel, amelyeket a addText(), addEmail() és addTextArea() metódusokkal adunk hozzá. Hozzáadtunk egy gombot is az űrlap elküldéséhez. De mi van akkor, ha a felhasználó nem tölt ki néhány mezőt? Ebben az esetben tudatnunk kell vele, hogy az adott mező kötelezően kitöltendő. Ezt a setRequired() metódussal tettük meg. Végül hozzáadtunk egy onSuccesseseményt is, amely akkor lép működésbe, ha az űrlapot sikeresen elküldtük. A mi esetünkben meghívja a contactFormSucceeded metódust , amely a beküldött űrlap feldolgozásáról gondoskodik. Ezt is hozzáadjuk a kódhoz egy pillanat múlva.

Legyen a contantForm komponens megjelenítve a Home/default.latte sablonban:

{block content}
<h1>Contant Form</h1>
{control contactForm}

Magához az e-mail elküldéséhez hozzunk létre egy új osztályt ContactFacade néven, és helyezzük el a app/Model/ContactFacade.php fájlban:

<?php
declare(strict_types=1);

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') // your email
			->setFrom($email, $name)
			->setSubject('Message from the contact form')
			->setBody($message);

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

A sendMessage() metódus fogja létrehozni és elküldeni az e-mailt. Ehhez egy úgynevezett mailert használ, amelyet függőségként ad át a konstruktoron keresztül. Olvasson többet az e-mailek küldéséről.

Most visszamegyünk a prezenterhez, és befejezzük a contactFormSucceeded() metódust. Meghívja a ContactFacade osztály sendMessage() metódusát, és átadja neki az űrlap adatait. És hogyan kapjuk meg a ContactFacade objektumot ? A konstruktor fogja átadni nekünk:

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('The message has been sent');
		$this->redirect('this');
	}
}

Az e-mail elküldése után megjelenítjük a felhasználónak az úgynevezett flash üzenetet, amely megerősíti, hogy az üzenet elküldésre került, majd átirányítjuk a következő oldalra, hogy az űrlapot ne lehessen újra elküldeni a böngésző frissítésével.

Nos, ha minden működik, akkor a kapcsolatfelvételi űrlapról már tudsz e-mailt küldeni. Gratulálunk!

HTML e-mail sablon

Egyelőre egy egyszerű szöveges e-mailt küldünk, amely csak az űrlap által küldött üzenetet tartalmazza. De használhatunk HTML-t az e-mailben, és vonzóbbá tehetjük azt. Létrehozunk hozzá egy sablont a Latte-ban, amelyet a app/Model/contactEmail.latte címre mentünk el:

<html>
	<title>Message from the contact form</title>

	<body>
		<p><strong>Name:</strong> {$name}</p>
		<p><strong>E-mail:</strong> {$email}</p>
		<p><strong>Message:</strong> {$message}</p>
	</body>
</html>

Már csak a ContactFacade -t kell módosítani, hogy ezt a sablont használhassuk. A konstruktorban kérjük a LatteFactory osztályt, amely képes előállítani a Latte\Engine objektumot, egy Latte sablon renderelőt. A renderToString() metódust használjuk a sablon renderelésére egy fájlba, az első paraméter a sablon elérési útvonala, a második pedig a változók.

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') // your email
			->setFrom($email, $name)
			->setHtmlBody($body);

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

Ezután a generált HTML e-mailt átadjuk a setHtmlBody() metódusnak az eredeti setBody() helyett. Az e-mail tárgyát sem kell megadnunk a setSubject() metódusban, mert a könyvtár azt az elemből veszi át. <title> sablonból veszi át.

A konfigurálása

A ContactFacade osztály kódjában az admin e-mail címünk, a admin@example.com még mindig keményen kódolva van. Jobb lenne, ha áthelyeznénk a konfigurációs fájlba. Hogyan kell ezt megtenni?

Először is módosítjuk a ContactFacade osztályt, és az email karakterláncot a konstruktor által átadott változóval helyettesítjük:

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);
		// ...
	}
}

A második lépés pedig az, hogy ennek a változónak az értékét a konfigurációba helyezzük. A app/config/services.neon fájlban hozzáadjuk:

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

És ennyi. Ha sok elem van a services részben, és úgy érezzük, hogy az e-mail elveszik közöttük, akkor változtathatóvá tehetjük. Módosítjuk a bejegyzést:

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

És definiáljuk ezt a változót a app/config/common.neon fájlban:

parameters:
	adminEmail: admin@example.com

És kész!