Давайте создадим контактную форму
Давайте рассмотрим, как создать контактную форму в Nette, включая отправку ее на электронную почту. Итак, давайте сделаем это!
Сначала мы должны создать новый проект. Как объясняется на странице " Начало работы". А затем мы можем приступить к созданию формы.
Самый простой способ – создать форму
непосредственно в Presenter. Мы можем использовать готовый
HomePresenter
. Мы добавим компонент contactForm
, представляющий
форму. Для этого мы напишем фабричный метод createComponentContactForm()
в
коде, который будет создавать компонент:
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()
создает новую форму. В ней есть поля для имени,
электронной почты и сообщения, которые мы добавляем с помощью методов
addText()
, addEmail()
и addTextArea()
. Мы также добавили кнопку
для отправки формы. Но что, если пользователь не заполнит некоторые
поля? В этом случае мы должны сообщить ему, что это обязательное поле.
Мы сделали это с помощью метода setRequired()
. Наконец, мы также
добавили событие onSuccess
, которое
срабатывает в случае успешной отправки формы. В нашем случае оно
вызывает метод contactFormSucceeded
, который обрабатывает отправленную
форму. Мы добавим это в код через некоторое время.
Пусть компонент contantForm
будет отображен в шаблоне
Home/default.latte
:
{block content}
<h1>Contant Form</h1>
{control contactForm}
Для отправки самого письма мы создадим новый класс 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()
будет создавать и отправлять электронное
письмо. Для этого он использует так называемый 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-сообщение, подтверждающее, что письмо отправлено, а затем перенаправляем на следующую страницу, чтобы форма не могла быть повторно отправлена с помощью refresh в браузере.
Ну, если все работает, вы должны быть в состоянии отправить электронное письмо из вашей контактной формы. Поздравляем!
Шаблон электронной почты HTML
Пока что отправляется обычное текстовое письмо, содержащее только
сообщение, отправленное формой. Но мы можем использовать HTML в письме и
сделать его более привлекательным. Для этого мы создадим шаблон в 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);
}
}
Затем мы передаем сгенерированное HTML-письмо в метод setHtmlBody()
вместо исходного setBody()
. Нам также не нужно указывать тему письма
в 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
много элементов и вам кажется, что
письмо теряется среди них, мы можем сделать его переменной. Мы изменим
запись на:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
И определим эту переменную в файле app/config/common.neon
:
parameters:
adminEmail: admin@example.com
И готово!