| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- <?php
- namespace App\Controller;
- use App\Entity\User;
- use App\Form\ChangePasswordFormType;
- use App\Form\ResetPasswordRequestFormType;
- use Doctrine\ORM\EntityManagerInterface;
- use Symfony\Bridge\Twig\Mime\TemplatedEmail;
- use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
- use Symfony\Component\HttpFoundation\RedirectResponse;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\Mailer\MailerInterface;
- use Symfony\Component\Mime\Address;
- use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
- use Symfony\Component\Routing\Attribute\Route;
- use Symfony\Contracts\Translation\TranslatorInterface;
- use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
- use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
- use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
- #[Route('/reset-password')]
- class ResetPasswordController extends AbstractController
- {
- use ResetPasswordControllerTrait;
- public function __construct(
- private ResetPasswordHelperInterface $resetPasswordHelper,
- private EntityManagerInterface $entityManager
- ) {
- }
- /**
- * Display & process form to request a password reset.
- */
- #[Route('', name: 'app_forgot_password_request')]
- public function request(Request $request, MailerInterface $mailer, TranslatorInterface $translator): Response
- {
- $form = $this->createForm(ResetPasswordRequestFormType::class);
- $form->handleRequest($request);
- if ($form->isSubmitted() && $form->isValid()) {
- /** @var string $email */
- $email = $form->get('email')->getData();
- return $this->processSendingPasswordResetEmail($email, $mailer, $translator
- );
- }
- return $this->render('reset_password/request.html.twig', [
- 'requestForm' => $form,
- ]);
- }
- /**
- * Confirmation page after a user has requested a password reset.
- */
- #[Route('/check-email', name: 'app_check_email')]
- public function checkEmail(): Response
- {
- // Generate a fake token if the user does not exist or someone hit this page directly.
- // This prevents exposing whether or not a user was found with the given email address or not
- if (null === ($resetToken = $this->getTokenObjectFromSession())) {
- $resetToken = $this->resetPasswordHelper->generateFakeResetToken();
- }
- return $this->render('reset_password/check_email.html.twig', [
- 'resetToken' => $resetToken,
- ]);
- }
- /**
- * Validates and process the reset URL that the user clicked in their email.
- */
- #[Route('/reset/{token}', name: 'app_reset_password')]
- public function reset(Request $request, UserPasswordHasherInterface $passwordHasher, TranslatorInterface $translator, ?string $token = null): Response
- {
- if ($token) {
- // We store the token in session and remove it from the URL, to avoid the URL being
- // loaded in a browser and potentially leaking the token to 3rd party JavaScript.
- $this->storeTokenInSession($token);
- return $this->redirectToRoute('app_reset_password');
- }
- $token = $this->getTokenFromSession();
- if (null === $token) {
- throw $this->createNotFoundException('No reset password token found in the URL or in the session.');
- }
- try {
- /** @var User $user */
- $user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
- } catch (ResetPasswordExceptionInterface $e) {
- $this->addFlash('reset_password_error', sprintf(
- '%s - %s',
- $translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_VALIDATE, [], 'ResetPasswordBundle'),
- $translator->trans($e->getReason(), [], 'ResetPasswordBundle')
- ));
- return $this->redirectToRoute('app_forgot_password_request');
- }
- // The token is valid; allow the user to change their password.
- $form = $this->createForm(ChangePasswordFormType::class);
- $form->handleRequest($request);
- if ($form->isSubmitted() && $form->isValid()) {
- // A password reset token should be used only once, remove it.
- $this->resetPasswordHelper->removeResetRequest($token);
- /** @var string $plainPassword */
- $plainPassword = $form->get('plainPassword')->getData();
- // Encode(hash) the plain password, and set it.
- $user->setPassword($passwordHasher->hashPassword($user, $plainPassword));
- $this->entityManager->flush();
- // The session is cleaned up after the password has been changed.
- $this->cleanSessionAfterReset();
- return $this->redirectToRoute('app_main');
- }
- return $this->render('reset_password/reset.html.twig', [
- 'resetForm' => $form,
- ]);
- }
- private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer, TranslatorInterface $translator): RedirectResponse
- {
- $user = $this->entityManager->getRepository(User::class)->findOneBy([
- 'email' => $emailFormData,
- ]);
- // Do not reveal whether a user account was found or not.
- if (!$user) {
- return $this->redirectToRoute('app_check_email');
- }
- try {
- $resetToken = $this->resetPasswordHelper->generateResetToken($user);
- } catch (ResetPasswordExceptionInterface $e) {
- // If you want to tell the user why a reset email was not sent, uncomment
- // the lines below and change the redirect to 'app_forgot_password_request'.
- // Caution: This may reveal if a user is registered or not.
- //
- // $this->addFlash('reset_password_error', sprintf(
- // '%s - %s',
- // $translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_HANDLE, [], 'ResetPasswordBundle'),
- // $translator->trans($e->getReason(), [], 'ResetPasswordBundle')
- // ));
- return $this->redirectToRoute('app_check_email');
- }
- $email = (new TemplatedEmail())
- ->from(new Address($_ENV['CONTACT_EMAIL'], $_ENV['CONTACT_NAME']))
- ->to((string) $user->getEmail())
- ->subject('Votre demande de réinitialisation de mot de passe')
- ->htmlTemplate('reset_password/email.html.twig')
- ->textTemplate('reset_password/email.txt.twig')
- ->context([
- 'resetToken' => $resetToken,
- ])
- ;
- $mailer->send($email);
- // Store the token object in session for retrieval in check-email route.
- $this->setTokenObjectInSession($resetToken);
- return $this->redirectToRoute('app_check_email');
- }
- }
|