Ας δημιουργήσουμε μια φόρμα επικοινωνίας

Ας δούμε πώς μπορείτε να δημιουργήσετε μια φόρμα επικοινωνίας στη Nette, συμπεριλαμβανομένης της αποστολής της σε ένα email. Ας το κάνουμε λοιπόν!

Πρώτα πρέπει να δημιουργήσουμε ένα νέο έργο. Όπως εξηγεί η σελίδα Getting Started. Και στη συνέχεια μπορούμε να ξεκινήσουμε τη δημιουργία της φόρμας.

Ο ευκολότερος τρόπος είναι να δημιουργήσουμε τη φόρμα απευθείας στο Presenter. Μπορούμε να χρησιμοποιήσουμε την προκατασκευασμένη διεύθυνση HomePresenter. Θα προσθέσουμε το στοιχείο contactForm που αντιπροσωπεύει τη φόρμα. Αυτό το κάνουμε γράφοντας τη μέθοδο createComponentContactForm() factory στον κώδικα που θα παράγει το συστατικό:

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
	}
}

Όπως μπορείτε να δείτε, έχουμε δημιουργήσει δύο μεθόδους. Η πρώτη μέθοδος createComponentContactForm() δημιουργεί μια νέα φόρμα. Αυτή έχει πεδία για το όνομα, το email και το μήνυμα, τα οποία προσθέτουμε χρησιμοποιώντας τις μεθόδους addText(), addEmail() και addTextArea(). Προσθέσαμε επίσης ένα κουμπί για την υποβολή της φόρμας. Τι γίνεται όμως αν ο χρήστης δεν συμπληρώσει κάποια πεδία; Σε αυτή την περίπτωση, θα πρέπει να τον ενημερώσουμε ότι πρόκειται για υποχρεωτικό πεδίο. Αυτό το κάναμε με τη μέθοδο setRequired(). Τέλος, προσθέσαμε και ένα συμβάν onSuccess, το οποίο ενεργοποιείται αν η φόρμα υποβληθεί με επιτυχία. Στην περίπτωσή μας, καλεί τη μέθοδο contactFormSucceeded, η οποία αναλαμβάνει την επεξεργασία της υποβληθείσας φόρμας. Θα το προσθέσουμε αυτό στον κώδικα σε λίγο.

Αφήστε το στοιχείο contantForm να αποδοθεί στο πρότυπο Home/default.latte:

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

Για να στείλουμε το ίδιο το email, δημιουργούμε μια νέα κλάση με όνομα ContactFacade και την τοποθετούμε στο αρχείο app/Model/ContactFacade.php:

<?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);
	}
}

Η μέθοδος sendMessage() θα δημιουργήσει και θα στείλει το email. Χρησιμοποιεί έναν λεγόμενο mailer για να το κάνει αυτό, τον οποίο περνάει ως εξάρτηση μέσω του κατασκευαστή. Διαβάστε περισσότερα σχετικά με την αποστολή μηνυμάτων ηλεκτρονικού ταχυδρομείου.

Τώρα, θα επιστρέψουμε στον παρουσιαστή και θα ολοκληρώσουμε τη μέθοδο contactFormSucceeded(). Καλεί τη μέθοδο sendMessage() της κλάσης ContactFacade και της περνάει τα δεδομένα της φόρμας. Και πώς παίρνουμε το αντικείμενο ContactFacade; Θα μας το περάσει ο κατασκευαστής:

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');
	}
}

Μετά την αποστολή του ηλεκτρονικού ταχυδρομείου, εμφανίζουμε στο χρήστη το λεγόμενο flash message, επιβεβαιώνοντας ότι το μήνυμα έχει σταλεί, και στη συνέχεια ανακατευθύνουμε στην επόμενη σελίδα, έτσι ώστε να μην μπορεί να ξαναστείλει τη φόρμα χρησιμοποιώντας refresh στο πρόγραμμα περιήγησης.

Λοιπόν, αν όλα λειτουργούν, θα πρέπει να είστε σε θέση να στείλετε ένα μήνυμα ηλεκτρονικού ταχυδρομείου από τη φόρμα επικοινωνίας σας. Συγχαρητήρια!

Πρότυπο ηλεκτρονικού ταχυδρομείου HTML

Προς το παρόν, αποστέλλεται ένα email απλού κειμένου που περιέχει μόνο το μήνυμα που αποστέλλεται από τη φόρμα. Μπορούμε όμως να χρησιμοποιήσουμε HTML στο email και να το κάνουμε πιο ελκυστικό. Θα δημιουργήσουμε ένα πρότυπο για αυτό στο Latte, το οποίο θα αποθηκεύσουμε στο app/Model/contactEmail.latte:

<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>

Μένει να τροποποιήσουμε το ContactFacade για να χρησιμοποιήσουμε αυτό το πρότυπο. Στον κατασκευαστή, ζητάμε την κλάση LatteFactory, η οποία μπορεί να παράγει το αντικείμενο Latte\Engine, ένα πρότυπο απόδοσης Latte. Χρησιμοποιούμε τη μέθοδο renderToString() για την απόδοση του προτύπου σε ένα αρχείο, η πρώτη παράμετρος είναι η διαδρομή προς το πρότυπο και η δεύτερη οι μεταβλητές.

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

Στη συνέχεια, περνάμε το παραγόμενο email HTML στη μέθοδο setHtmlBody() αντί του αρχικού setBody(). Επίσης, δεν χρειάζεται να καθορίσουμε το θέμα του email στο setSubject(), επειδή η βιβλιοθήκη το παίρνει από το στοιχείο <title> στο πρότυπο.

Διαμόρφωση του

Στον κώδικα της κλάσης ContactFacade, το email του διαχειριστή μας admin@example.com εξακολουθεί να είναι σκληρά κωδικοποιημένο. Θα ήταν καλύτερα να το μεταφέρουμε στο αρχείο ρυθμίσεων. Πώς να το κάνετε;

Πρώτα, τροποποιούμε την κλάση ContactFacade και αντικαθιστούμε το αλφαριθμητικό email με μια μεταβλητή που περνάει από τον κατασκευαστή:

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

Και το δεύτερο βήμα είναι να τοποθετήσουμε την τιμή αυτής της μεταβλητής στη διαμόρφωση. Στο αρχείο app/config/services.neon προσθέτουμε:

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

Και αυτό είναι όλο. Αν υπάρχουν πολλά στοιχεία στην ενότητα services και νιώθετε ότι το email χάνεται ανάμεσά τους, μπορούμε να το κάνουμε μεταβλητή. Θα τροποποιήσουμε την καταχώρηση σε:

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

Και θα ορίσουμε αυτή τη μεταβλητή στο αρχείο app/config/common.neon:

parameters:
	adminEmail: admin@example.com

Και τελείωσε!