Criando um formulário de contato
Vamos ver como criar um formulário de contato no Nette, incluindo o envio para e-mail. Então, vamos lá!
Primeiro, precisamos criar um novo projeto. Como fazer isso é explicado na página Começando. E então podemos começar a criar o formulário.
A maneira mais simples é criar o formulário diretamente no
presenter. Podemos usar o HomePresenter
pré-preparado. Nele, adicionaremos o componente
contactForm
que representa o formulário. Faremos isso escrevendo o método de fábrica
createComponentContactForm()
no código, que 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', 'Nome:')
->setRequired('Por favor, digite seu nome.');
$form->addEmail('email', 'E-mail:')
->setRequired('Por favor, digite seu e-mail.');
$form->addTextarea('message', 'Mensagem:')
->setRequired('Por favor, digite sua mensagem.');
$form->addSubmit('send', 'Enviar');
$form->onSuccess[] = [$this, 'contactFormSucceeded'];
return $form;
}
public function contactFormSucceeded(Form $form, $data): void
{
// envio de e-mail
}
}
Como você pode ver, criamos dois métodos. O primeiro método createComponentContactForm()
cria um novo
formulário. Ele tem campos para nome, e-mail e mensagem, que adicionamos com 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 algum campo? Nesse caso, devemos informá-lo de que é um campo obrigatório. Conseguimos isso com
o método setRequired()
. Finalmente, adicionamos também o evento onSuccess
, que é acionado se o formulário for
enviado com sucesso. No nosso caso, ele chama o método contactFormSucceeded
, que cuidará do processamento do
formulário enviado. Adicionaremos isso ao código em um momento.
Deixaremos o componente contactForm
ser renderizado no template Home/default.latte
:
{block content}
<h1>Formulário de Contato</h1>
{control contactForm}
Para o envio do e-mail em si, criaremos uma nova classe, que chamaremos de ContactFacade
e a colocaremos 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') // seu e-mail
->setFrom($email, $name)
->setSubject('Mensagem do formulário de contato')
->setBody($message);
$this->mailer->send($mail);
}
}
O método sendMessage()
cria e envia o e-mail. Ele usa o chamado mailer para isso, que ele recebe como
dependência através do construtor. Leia mais sobre envio de e-mails.
Agora voltaremos ao presenter e finalizaremos o método contactFormSucceeded()
. Ele chamará o método
sendMessage()
da classe ContactFacade
e passará os dados do formulário para ele. E como obtemos
o objeto ContactFacade
? Vamos recebê-lo através do construtor:
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('A mensagem foi enviada');
$this->redirect('this');
}
}
Depois que o e-mail for enviado, ainda exibiremos ao usuário a chamada flash message, confirmando que a mensagem foi
enviada, e depois redirecionaremos para a mesma página (usando this
), para que não seja possível reenviar
o formulário usando refresh no navegador.
Então, se tudo funcionar, você deve ser capaz de enviar um e-mail do seu formulário de contato. Parabéns!
Template HTML do e-mail
Até agora, um e-mail de texto simples está sendo enviado, contendo apenas a mensagem enviada pelo formulário. Mas no e-mail,
podemos usar HTML e tornar sua aparência mais atraente. Criaremos um template em Latte para ele, que escreveremos em
app/Model/contactEmail.latte
:
<html>
<title>Mensagem do formulário de contato</title>
<body>
<p><strong>Nome:</strong> {$name}</p>
<p><strong>E-mail:</strong> {$email}</p>
<p><strong>Mensagem:</strong> {$message}</p>
</body>
</html>
Resta modificar o ContactFacade
, para usar este template. No construtor, solicitaremos a classe
LatteFactory
, que pode criar um objeto Latte\Engine
, ou seja, o renderizador de templates Latte. Usando o método
renderToString()
, renderizamos o template para uma string, o primeiro parâmetro é o caminho para o template 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') // seu e-mail
->setFrom($email, $name)
->setHtmlBody($body);
$this->mailer->send($mail);
}
}
O e-mail HTML gerado é então passado para o método setHtmlBody()
em vez do original setBody()
.
Da mesma forma, não precisamos especificar o assunto do e-mail em setSubject()
, pois a biblioteca o pegará do
elemento <title>
do template.
Configuração
No código da classe ContactFacade
, nosso e-mail de administrador 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 com o 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 é especificar o valor desta variável na configuração. No arquivo app/config/services.neon
,
escrevemos:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
E está feito. Se houvesse muitos itens na seção services
e você sentisse que o e-mail se perde entre eles,
podemos transformá-lo em um parâmetro. Modificamos a entrada para:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
E no arquivo app/config/common.neon
, definimos esta variável:
parameters:
adminEmail: admin@example.com
E está pronto!