Vamos criar um formulário de contato
Vamos ver como criar um formulário de contato em Nette, inclusive enviando-o para um e-mail. Então, vamos fazer isso!
Primeiro temos que criar um novo projeto. Como explica a página Primeiros Pass os. E depois podemos começar a criar o formulário.
A maneira mais fácil é criar o formulário diretamente no
Apresentador. Podemos usar o pré-fabricado HomePresenter
. Acrescentaremos o componente
contactForm
que representa o formulário. Fazemos isso escrevendo o método de fábrica
createComponentContactForm()
no código que irá produzir o componente:
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
}
}
Como você pode ver, nós criamos dois métodos. O primeiro método createComponentContactForm()
cria uma nova
forma. Este tem campos para nome, e-mail e mensagem, que adicionamos usando os métodos addText()
,
addEmail()
e addTextArea()
. Também adicionamos um botão para enviar o formulário. Mas e se
o usuário não preencher alguns campos? Nesse caso, devemos avisá-lo que se trata de um campo obrigatório. Fizemos isso com
o método setRequired()
. Finalmente, adicionamos também um evento onSuccess
, que é acionado se o formulário for
submetido com sucesso. Em nosso caso, ele chama o método contactFormSucceeded
, que se encarrega de processar
o formulário submetido. Acrescentaremos isso ao código em um momento.
Deixe o componente contantForm
ser apresentado no modelo Home/default.latte
:
{block content}
<h1>Contant Form</h1>
{control contactForm}
Para enviar o e-mail em si, criamos uma nova classe chamada ContactFacade
e a colocamos no arquivo
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);
}
}
O método sendMessage()
irá criar e enviar o e-mail. Para isso, ele usa o chamado mailer, que passa como uma
dependência através do construtor. Leia mais sobre o envio de e-mails.
Agora, vamos voltar ao apresentador e completar o método contactFormSucceeded()
. Ele chama o método
sendMessage()
da classe ContactFacade
e lhe passa os dados do formulário. E como obtemos o objeto
ContactFacade
? O construtor nos passará os dados:
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');
}
}
Após o envio do e-mail, mostramos ao usuário a chamada mensagem flash, confirmando que a mensagem foi enviada, e então redirecionamos para a página seguinte para que o formulário não possa ser reapresentado usando refresh no navegador.
Bem, se tudo funcionar, você deve poder enviar um e-mail a partir de seu formulário de contato. Parabéns!
Modelo de e-mail HTML
Por enquanto, é enviado um e-mail com texto simples contendo apenas a mensagem enviada pelo formulário. Mas podemos usar HTML
no e-mail e torná-lo mais atraente. Criaremos um modelo para ele em Latte, que salvaremos em
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>
Resta modificar ContactFacade
para usar este modelo. No construtor, solicitamos a classe
LatteFactory
, que pode produzir o objeto Latte\Engine
, um renderizador de modelos Latte. Usamos o método
renderToString()
para renderizar o modelo em um arquivo, o primeiro parâmetro é o caminho para o modelo e
o segundo são as variáveis.
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);
}
}
Passamos então o e-mail HTML gerado para o método setHtmlBody()
em vez do original setBody()
.
Também não precisamos especificar o assunto do e-mail em setSubject()
, pois a biblioteca o retira do elemento
<title>
em modelo.
Configurando
No código de classe ContactFacade
, nosso e-mail administrativo admin@example.com
ainda está
codificado. Seria melhor movê-lo para o arquivo de configuração. Como fazer isso?
Primeiro, modificamos a classe ContactFacade
e substituímos a string de e-mail por uma variável passada pelo
construtor:
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);
// ...
}
}
E o segundo passo é colocar o valor desta variável na configuração. No arquivo app/config/services.neon
,
adicionamos:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
E é isso aí. Se houver muitos itens na seção services
e você sentir que o e-mail está se perdendo entre
eles, podemos torná-lo uma variável. Modificaremos a entrada para:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
E defina esta variável no arquivo app/config/common.neon
:
parameters:
adminEmail: admin@example.com
E está feito!