Add contact page with form, email template, and tests
- Create ContactController with GET/POST handling and MailerService integration - Create contact page template with name, surname, email, message form - Create dedicated email template for contact messages - Update navbar links (desktop + mobile) to point to /contact route - Add ContactControllerTest with 5 tests covering form submission and validation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
55
src/Controller/ContactController.php
Normal file
55
src/Controller/ContactController.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Service\MailerService;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ContactController extends AbstractController
|
||||
{
|
||||
#[Route('/contact', name: 'app_contact', methods: ['GET', 'POST'])]
|
||||
public function index(Request $request, MailerService $mailerService): Response
|
||||
{
|
||||
if ($request->isMethod('POST')) {
|
||||
$name = trim($request->request->getString('name'));
|
||||
$surname = trim($request->request->getString('surname'));
|
||||
$email = trim($request->request->getString('email'));
|
||||
$message = trim($request->request->getString('message'));
|
||||
|
||||
if ('' === $name || '' === $surname || '' === $email || '' === $message) {
|
||||
$this->addFlash('error', 'Tous les champs sont obligatoires.');
|
||||
|
||||
return $this->redirectToRoute('app_contact');
|
||||
}
|
||||
|
||||
$html = $this->renderView('email/contact.html.twig', [
|
||||
'name' => $name,
|
||||
'surname' => $surname,
|
||||
'email' => $email,
|
||||
'message' => $message,
|
||||
]);
|
||||
|
||||
$mailerService->sendEmail(
|
||||
to: 'contact@e-cosplay.fr',
|
||||
subject: sprintf('Contact de %s %s', $surname, $name),
|
||||
content: $html,
|
||||
replyTo: $email,
|
||||
withUnsubscribe: false,
|
||||
);
|
||||
|
||||
$this->addFlash('success', 'Votre message a bien ete envoye. Nous vous repondrons dans les plus brefs delais.');
|
||||
|
||||
return $this->redirectToRoute('app_contact');
|
||||
}
|
||||
|
||||
return $this->render('contact/index.html.twig', [
|
||||
'breadcrumbs' => [
|
||||
['name' => 'Accueil', 'url' => '/'],
|
||||
['name' => 'Contact', 'url' => '/contact'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@
|
||||
<div class="hidden lg:flex items-center space-x-1">
|
||||
<a href="{{ path('app_home') }}" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all bg-yellow-400 border-2 border-gray-900 shadow-[2px_2px_0px_rgba(0,0,0,1)]"><span itemprop="name">Accueil</span></a>
|
||||
<a href="#" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all hover:text-indigo-600"><span itemprop="name">Evenements</span></a>
|
||||
<a href="#" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all hover:text-indigo-600"><span itemprop="name">Contact</span></a>
|
||||
<a href="{{ path('app_contact') }}" itemprop="url" class="px-3 py-2 text-xs font-black uppercase tracking-widest transition-all hover:text-indigo-600"><span itemprop="name">Contact</span></a>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-4 border-l-4 border-gray-900 pl-6 h-full">
|
||||
@@ -112,7 +112,7 @@
|
||||
<div class="p-4 space-y-2 uppercase font-black italic">
|
||||
<a href="{{ path('app_home') }}" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Accueil</a>
|
||||
<a href="#" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Evenements</a>
|
||||
<a href="#" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Contact</a>
|
||||
<a href="{{ path('app_contact') }}" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Contact</a>
|
||||
{% if app.user %}
|
||||
<a href="{{ path('app_account') }}" class="block p-3 border-2 border-transparent hover:border-gray-900 hover:bg-gray-50" role="menuitem">Mon espace</a>
|
||||
{% else %}
|
||||
|
||||
74
templates/contact/index.html.twig
Normal file
74
templates/contact/index.html.twig
Normal file
@@ -0,0 +1,74 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Contact - E-Ticket{% endblock %}
|
||||
{% block description %}Contactez l'equipe E-Ticket pour toute question sur la plateforme de billetterie associative{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div style="max-width:50rem;margin:0 auto;padding:3rem 1rem;">
|
||||
<h1 class="text-3xl font-black uppercase tracking-tighter italic" style="border-bottom:4px solid #111827;display:inline-block;margin-bottom:0.5rem;">Contact</h1>
|
||||
<p class="font-bold text-gray-600 italic" style="margin-bottom:2rem;">Une question, une demande ? Ecrivez-nous.</p>
|
||||
|
||||
{% for message in app.flashes('success') %}
|
||||
<div style="border:4px solid #111827;padding:1rem 1.5rem;margin-bottom:2rem;background:#d1fae5;box-shadow:4px 4px 0 rgba(0,0,0,1);">
|
||||
<p class="font-black text-sm">{{ message }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for message in app.flashes('error') %}
|
||||
<div style="border:4px solid #111827;padding:1rem 1.5rem;margin-bottom:2rem;background:#fee2e2;box-shadow:4px 4px 0 rgba(0,0,0,1);">
|
||||
<p class="font-black text-sm">{{ message }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<form method="post" action="{{ path('app_contact') }}" style="display:flex;flex-direction:column;gap:1.5rem;">
|
||||
<div style="display:flex;flex-wrap:wrap;gap:1.5rem;">
|
||||
<div style="flex:1;min-width:200px;">
|
||||
<label for="contact_name" class="text-xs font-black uppercase tracking-widest" style="display:block;margin-bottom:0.5rem;">Nom</label>
|
||||
<input type="text" id="contact_name" name="name" required
|
||||
style="width:100%;padding:0.75rem 1rem;border:3px solid #111827;font-weight:700;outline:none;"
|
||||
class="focus:border-indigo-600"
|
||||
placeholder="Dupont">
|
||||
</div>
|
||||
<div style="flex:1;min-width:200px;">
|
||||
<label for="contact_surname" class="text-xs font-black uppercase tracking-widest" style="display:block;margin-bottom:0.5rem;">Prenom</label>
|
||||
<input type="text" id="contact_surname" name="surname" required
|
||||
style="width:100%;padding:0.75rem 1rem;border:3px solid #111827;font-weight:700;outline:none;"
|
||||
class="focus:border-indigo-600"
|
||||
placeholder="Jean">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="contact_email" class="text-xs font-black uppercase tracking-widest" style="display:block;margin-bottom:0.5rem;">Email</label>
|
||||
<input type="email" id="contact_email" name="email" required
|
||||
style="width:100%;padding:0.75rem 1rem;border:3px solid #111827;font-weight:700;outline:none;"
|
||||
class="focus:border-indigo-600"
|
||||
placeholder="jean.dupont@exemple.fr">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="contact_message" class="text-xs font-black uppercase tracking-widest" style="display:block;margin-bottom:0.5rem;">Message</label>
|
||||
<textarea id="contact_message" name="message" required rows="6"
|
||||
style="width:100%;padding:0.75rem 1rem;border:3px solid #111827;font-weight:700;outline:none;resize:vertical;"
|
||||
class="focus:border-indigo-600"
|
||||
placeholder="Votre message..."></textarea>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit"
|
||||
style="padding:0.75rem 2rem;border:3px solid #111827;box-shadow:4px 4px 0 rgba(0,0,0,1);cursor:pointer;"
|
||||
class="bg-yellow-400 font-black uppercase text-sm tracking-widest hover:bg-indigo-600 hover:text-white transition-all">
|
||||
Envoyer
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div style="border:4px solid #111827;padding:1.5rem;background:#f9fafb;box-shadow:6px 6px 0 rgba(0,0,0,1);margin-top:3rem;">
|
||||
<h2 class="text-lg font-black uppercase" style="margin-bottom:0.5rem;">Autres moyens de contact</h2>
|
||||
<ul style="list-style:disc;padding-left:1.5rem;" class="text-sm font-bold text-gray-700">
|
||||
<li>Email : <a href="mailto:contact@e-cosplay.fr" class="text-indigo-600 hover:underline">contact@e-cosplay.fr</a></li>
|
||||
<li>Adresse : 42 rue de Saint-Quentin, 02800 Beautor, France</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
24
templates/email/contact.html.twig
Normal file
24
templates/email/contact.html.twig
Normal file
@@ -0,0 +1,24 @@
|
||||
{% extends 'email/base.html.twig' %}
|
||||
|
||||
{% block title %}Nouveau message de contact{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Nouveau message de contact</h2>
|
||||
<table style="width:100%;border-collapse:collapse;margin-bottom:24px;">
|
||||
<tr>
|
||||
<td style="padding:8px 12px;font-weight:700;font-size:14px;color:#18181b;border-bottom:1px solid #e4e4e7;width:120px;">Nom</td>
|
||||
<td style="padding:8px 12px;font-size:14px;color:#3f3f46;border-bottom:1px solid #e4e4e7;">{{ name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:8px 12px;font-weight:700;font-size:14px;color:#18181b;border-bottom:1px solid #e4e4e7;">Prenom</td>
|
||||
<td style="padding:8px 12px;font-size:14px;color:#3f3f46;border-bottom:1px solid #e4e4e7;">{{ surname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:8px 12px;font-weight:700;font-size:14px;color:#18181b;border-bottom:1px solid #e4e4e7;">Email</td>
|
||||
<td style="padding:8px 12px;font-size:14px;color:#3f3f46;border-bottom:1px solid #e4e4e7;"><a href="mailto:{{ email }}" style="color:#7c3aed;text-decoration:none;">{{ email }}</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="background:#f4f4f5;border-radius:8px;padding:16px;font-size:15px;line-height:1.6;color:#3f3f46;">
|
||||
{{ message|nl2br }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
76
tests/Controller/ContactControllerTest.php
Normal file
76
tests/Controller/ContactControllerTest.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Service\MailerService;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class ContactControllerTest extends WebTestCase
|
||||
{
|
||||
public function testContactPageReturnsSuccess(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->request('GET', '/contact');
|
||||
|
||||
self::assertResponseIsSuccessful();
|
||||
}
|
||||
|
||||
public function testContactFormSubmitRedirectsWithSuccess(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$mailer = $this->createMock(MailerService::class);
|
||||
$mailer->expects(self::once())->method('sendEmail');
|
||||
static::getContainer()->set(MailerService::class, $mailer);
|
||||
|
||||
$client->request('POST', '/contact', [
|
||||
'name' => 'Dupont',
|
||||
'surname' => 'Jean',
|
||||
'email' => 'jean@exemple.fr',
|
||||
'message' => 'Bonjour, je voudrais des informations.',
|
||||
]);
|
||||
|
||||
self::assertResponseRedirects('/contact');
|
||||
$client->followRedirect();
|
||||
self::assertSelectorExists('.font-black.text-sm');
|
||||
}
|
||||
|
||||
public function testContactFormEmptyFieldsRedirectsWithError(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->request('POST', '/contact', [
|
||||
'name' => '',
|
||||
'surname' => 'Jean',
|
||||
'email' => 'jean@exemple.fr',
|
||||
'message' => 'Bonjour',
|
||||
]);
|
||||
|
||||
self::assertResponseRedirects('/contact');
|
||||
}
|
||||
|
||||
public function testContactFormAllEmptyRedirectsWithError(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->request('POST', '/contact', [
|
||||
'name' => '',
|
||||
'surname' => '',
|
||||
'email' => '',
|
||||
'message' => '',
|
||||
]);
|
||||
|
||||
self::assertResponseRedirects('/contact');
|
||||
}
|
||||
|
||||
public function testContactFormWhitespaceOnlyRedirectsWithError(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$client->request('POST', '/contact', [
|
||||
'name' => ' ',
|
||||
'surname' => 'Jean',
|
||||
'email' => 'jean@exemple.fr',
|
||||
'message' => 'Bonjour',
|
||||
]);
|
||||
|
||||
self::assertResponseRedirects('/contact');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user