<?php
namespace App\Controller;
use App\Repository\UserRepository;
use App\Form\ChangePasswordFormType;
use App\Form\ResetPasswordRequestFormType;
use App\Service\EmailService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
use SymfonyCasts\Bundle\ResetPassword\Exception\TooManyPasswordRequestsException;
#[Route('/reset-password')]
class ResetPasswordController extends AbstractController
{
use ResetPasswordControllerTrait;
private ResetPasswordHelperInterface $resetPasswordHelper;
private EntityManagerInterface $entityManager;
private EmailService $emailService;
public function __construct(
ResetPasswordHelperInterface $resetPasswordHelper,
EntityManagerInterface $entityManager,
EmailService $emailService
) {
$this->resetPasswordHelper = $resetPasswordHelper;
$this->entityManager = $entityManager;
$this->emailService = $emailService;
}
/**
* Demande de reset password
*/
#[Route('', name: 'app_forgot_password_request')]
public function request(
Request $request,
UserRepository $userRepository
): Response {
$form = $this->createForm(
ResetPasswordRequestFormType::class
);
$form->handleRequest($request);
if (
$form->isSubmitted()
&& $form->isValid()
) {
$email = $form
->get('email')
->getData();
$user = $userRepository->findOneBy([
'email' => $email
]);
// sécurité : ne jamais dire si email existe ou non
// sécurité : ne jamais dire si email existe ou non
if (!$user) {
return $this->redirectToRoute('app_check_email');
}
// Générer token (AVEC PROTECTION)
try {
$resetToken = $this->resetPasswordHelper->generateResetToken($user);
} catch (TooManyPasswordRequestsException $e) {
$this->addFlash(
'error',
'Vous avez déjà demandé un lien récemment. Veuillez attendre avant de réessayer.'
);
return $this->redirectToRoute('app_forgot_password_request');
}
// Générer lien absolu
$link = $this->generateUrl(
'app_reset_password',
[
'token' => $resetToken->getToken()
],
UrlGeneratorInterface::ABSOLUTE_URL
);
// Envoi email via PHPMailer
$this->emailService
->EnvoiResetPassword(
$user->getEmail(),
$user->getPrenom().' '.$user->getNom(),
$link
);
// stocker token en session
$this->setTokenObjectInSession(
$resetToken
);
return $this->redirectToRoute(
'app_check_email'
);
}
return $this->render(
'reset_password/request.html.twig',
[
'requestForm' => $form->createView(),
]
);
}
/**
* Message après demande
*/
#[Route('/check-email', name: 'app_check_email')]
public function checkEmail(): Response
{
return $this->render(
'reset_password/check_email.html.twig'
);
}
/**
* Réinitialisation mot de passe
*/
#[Route('/reset/{token}', name: 'app_reset_password')]
public function reset(
Request $request,
UserPasswordHasherInterface $passwordHasher,
?string $token = null
): Response {
if ($token) {
$this->storeTokenInSession(
$token
);
return $this->redirectToRoute(
'app_reset_password'
);
}
$token = $this
->getTokenFromSession();
if (null === $token) {
throw $this
->createNotFoundException(
'No reset token found.'
);
}
try {
$user = $this
->resetPasswordHelper
->validateTokenAndFetchUser(
$token
);
} catch (
ResetPasswordExceptionInterface $e
) {
$this->addFlash(
'reset_password_error',
sprintf(
'%s - %s',
$e->getReason(),
$e->getReasonData()
)
);
return $this->redirectToRoute(
'app_forgot_password_request'
);
}
$form = $this->createForm(
ChangePasswordFormType::class
);
$form->handleRequest($request);
if (
$form->isSubmitted()
&& $form->isValid()
) {
// supprimer token
$this
->resetPasswordHelper
->removeResetRequest(
$token
);
$plainPassword = $form
->get('plainPassword')
->getData();
// hash password
$user->setPassword(
$passwordHasher
->hashPassword(
$user,
$plainPassword
)
);
// nettoyage ancien FOSUser
/* if (
method_exists(
$user,
'setSalt'
)
) {
$user->setSalt(null);
}*/
$this
->entityManager
->flush();
// vider session token
$this
->cleanSessionAfterReset();
$this->addFlash(
'success',
'Mot de passe modifié avec succès.'
);
return $this->redirectToRoute(
'login'
);
}
return $this->render(
'reset_password/reset.html.twig',
[
'resetForm' => $form->createView(),
]
);
}
}