Kapcsolatfelvételi űrlap létrehozása

Megnézzük, hogyan hozzunk létre egy kapcsolatfelvételi űrlapot a Nette-ben, beleértve az e-mail küldést is. Vágjunk bele!

Először létre kell hoznunk egy új projektet. Hogy hogyan, azt az Első lépések oldal magyarázza el. Ezután elkezdhetjük az űrlap létrehozását.

A legegyszerűbb módja az űrlap létrehozása közvetlenül a presenterben. Használhatjuk az előkészített HomePresenter-t. Hozzáadjuk a contactForm komponenst, amely az űrlapot képviseli. Ezt úgy tesszük, hogy a kódba beírjuk a createComponentContactForm() factory metódust, amely létrehozza a komponenst:

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

class HomePresenter extends Presenter
{
	protected function createComponentContactForm(): Form
	{
		$form = new Form;
		$form->addText('name', 'Név:')
			->setRequired('Adja meg a nevét');
		$form->addEmail('email', 'E-mail:')
			->setRequired('Adja meg az e-mail címét');
		$form->addTextarea('message', 'Üzenet:')
			->setRequired('Adja meg az üzenetet');
		$form->addSubmit('send', 'Küldés');
		$form->onSuccess[] = [$this, 'contactFormSucceeded'];
		return $form;
	}

	public function contactFormSucceeded(Form $form, $data): void
	{
		// e-mail küldése
	}
}

Amint látja, két metódust hoztunk létre. Az első, createComponentContactForm() metódus létrehoz egy új űrlapot. Ennek vannak mezői a név, e-mail és üzenet számára, amelyeket az addText(), addEmail() és addTextArea() metódusokkal adunk hozzá. Hozzáadtunk egy gombot is az űrlap elküldéséhez. De mi van, ha a felhasználó nem tölt ki valamelyik mezőt? Ebben az esetben tudatnunk kell vele, hogy ez egy kötelező mező. Ezt a setRequired() metódussal értük el. Végül hozzáadtuk az onSuccess eseményt is, amely akkor fut le, ha az űrlapot sikeresen elküldték. Esetünkben a contactFormSucceeded metódust hívja meg, amely gondoskodik az elküldött űrlap feldolgozásáról. Ezt hamarosan kiegészítjük a kódban.

A contactForm komponenst a Home/default.latte sablonban rajzoltatjuk ki:

{block content}
<h1>Kapcsolatfelvételi űrlap</h1>
{control contactForm}

Magához az e-mail küldéshez létrehozunk egy új osztályt, amelyet ContactFacade-nek nevezünk el, és az app/Model/ContactFacade.php fájlba helyezzük:

<?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') // az Ön e-mail címe
			->setFrom($email, $name)
			->setSubject('Üzenet a kapcsolatfelvételi űrlapról')
			->setBody($message);

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

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

Most visszatérünk a presenterhez, és befejezzük a contactFormSucceeded() metódust. Ez meghívja a ContactFacade osztály sendMessage() metódusát, és átadja neki az űrlap adatait. És hogyan szerezzük meg a ContactFacade objektumot? Megkapjuk a konstruktoron keresztül:

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('Az üzenet elküldve');
		$this->redirect('this');
	}
}

Miután az e-mail elküldésre került, még megjelenítünk a felhasználónak egy úgynevezett flash üzenetet, amely megerősíti, hogy az üzenet elküldésre került, majd átirányítjuk egy másik oldalra, hogy ne lehessen az űrlapot ismételten elküldeni a böngésző frissítésével.

Nos, ha minden működik, képesnek kell lennie e-mailt küldeni a kapcsolatfelvételi űrlapjáról. Gratulálok!

HTML e-mail sablon

Eddig egy egyszerű szöveges e-mail került elküldésre, amely csak az űrlapon elküldött üzenetet tartalmazta. Az e-mailben azonban használhatunk HTML-t, és vonzóbbá tehetjük a megjelenését. Létrehozunk hozzá egy Latte sablont, amelyet az app/Model/contactEmail.latte fájlba írunk:

<html>
	<title>Üzenet a kapcsolatfelvételi űrlapról</title>

	<body>
		<p><strong>Név:</strong> {$name}</p>
		<p><strong>E-mail:</strong> {$email}</p>
		<p><strong>Üzenet:</strong> {$message}</p>
	</body>
</html>

Már csak a ContactFacade-et kell módosítani, hogy ezt a sablont használja. A konstruktorban kérjük a LatteFactory osztályt, amely képes létrehozni egy Latte\Engine objektumot, azaz egy Latte sablon renderelőt. A renderToString() metódussal rendereljük a sablont egy fájlba, az első paraméter a sablon elérési útja, 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') // az Ön e-mail címe
			->setFrom($email, $name)
			->setHtmlBody($body);

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

A generált HTML e-mailt ezután a setHtmlBody() metódusnak adjuk át az eredeti setBody() helyett. Szintén nem kell megadnunk az e-mail tárgyát a setSubject()-ben, mert a könyvtár azt a sablon <title> eleméből veszi át.

Konfiguráció

A ContactFacade osztály kódjában még mindig fixen be van írva az adminisztrátori e-mail címünk, az admin@example.com. Jobb lenne ezt a konfigurációs fájlba helyezni. Hogyan tegyük ezt?

Először módosítjuk a ContactFacade osztályt, és az e-mail címet tartalmazó stringet egy konstruktoron keresztül á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 ennek a változónak az értékének megadása a konfigurációban. Az app/config/services.neon fájlba írjuk:

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

És kész is. Ha a services szekcióban sok elem lenne, és úgy éreznénk, hogy az e-mail elveszik közöttük, akkor változóvá tehetjük. Módosítjuk a bejegyzést erre:

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

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

parameters:
	adminEmail: admin@example.com

És kész is vagyunk!