src/Controller/Frontend/ResetPasswordController.php line 41

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Frontend;
  3. use App\Entity\Abonnent\Abonnent;
  4. use App\Form\Abo\ChangePasswordFormType;
  5. use App\Form\Abo\ResetPasswordRequestFormType;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use Symfony\Bridge\Twig\Mime\TemplatedEmail;
  8. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  9. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  10. use Symfony\Component\HttpFoundation\RedirectResponse;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Mailer\MailerInterface;
  14. use Symfony\Component\Mime\Address;
  15. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  16. use Symfony\Component\Routing\Annotation\Route;
  17. use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
  18. use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
  19. use SymfonyCasts\Bundle\ResetPassword\Model\ResetPasswordToken;
  20. use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
  21. #[Route('/abo/reset-password')]
  22. class ResetPasswordController extends AbstractController
  23. {
  24. use ResetPasswordControllerTrait;
  25. public function __construct(
  26. private readonly ResetPasswordHelperInterface $resetPasswordHelper,
  27. private readonly EntityManagerInterface $entityManager,
  28. private readonly ParameterBagInterface $parameterBag
  29. )
  30. {
  31. }
  32. /**
  33. * Display & process form to request a password reset.
  34. */
  35. #[Route('', name: 'app_forgot_password_request')]
  36. public function request(Request $request, MailerInterface $mailer): Response
  37. {
  38. $form = $this->createForm(ResetPasswordRequestFormType::class);
  39. $form->handleRequest($request);
  40. if ($form->isSubmitted() && $form->isValid()) {
  41. return $this->processSendingPasswordResetEmail(
  42. $form->get('username')->getData(),
  43. $mailer
  44. );
  45. }
  46. return $this->render('frontend/abo/reset_password/request.html.twig', [
  47. 'requestForm' => $form->createView(),
  48. ]);
  49. }
  50. /**
  51. * Confirmation page after a user has requested a password reset.
  52. */
  53. #[Route('/check-email', name: 'app_check_email')]
  54. public function checkEmail(): Response
  55. {
  56. // Generate a fake token if the user does not exist or someone hit this page directly.
  57. // This prevents exposing whether a user was found with the given email address or not
  58. if (!($resetToken = $this->getTokenObjectFromSession()) instanceof ResetPasswordToken) {
  59. $resetToken = $this->resetPasswordHelper->generateFakeResetToken();
  60. }
  61. return $this->render('frontend/abo/reset_password/check_email.html.twig', [
  62. 'resetToken' => $resetToken,
  63. ]);
  64. }
  65. /**
  66. * Validates and process the reset URL that the user clicked in their email.
  67. */
  68. #[Route('/reset/{token}', name: 'app_reset_password')]
  69. public function reset(Request $request, UserPasswordHasherInterface $userPasswordHasher, ?string $token = null): Response
  70. {
  71. if ($token) {
  72. // We store the token in session and remove it from the URL, to avoid the URL being
  73. // loaded in a browser and potentially leaking the token to 3rd party JavaScript.
  74. $this->storeTokenInSession($token);
  75. return $this->redirectToRoute('app_reset_password');
  76. }
  77. $token = $this->getTokenFromSession();
  78. if (null === $token) {
  79. throw $this->createNotFoundException('In der URL oder in der Sitzung wurde kein Token zum Ändern des Passworts gefunden.');
  80. }
  81. try {
  82. $user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
  83. } catch (ResetPasswordExceptionInterface $e) {
  84. $this->addFlash('reset_password_error', sprintf(
  85. 'Es gab ein Problem bei der Validierung Ihrer Rücksetzanfrage - %s',
  86. $e->getReason()
  87. ));
  88. return $this->redirectToRoute('app_forgot_password_request');
  89. }
  90. // The token is valid; allow the user to change their password.
  91. $form = $this->createForm(ChangePasswordFormType::class);
  92. $form->handleRequest($request);
  93. if ($form->isSubmitted() && $form->isValid()) {
  94. //Wenn Passwort null ist - Redirect und Flash mit dem Hinweis, dass das Passwort nicht leer sein sollte.
  95. if (null === $form->get('plainPassword')->getData()) {
  96. $this->addFlash('notice', 'Das Passwort darf nicht leer sein!');
  97. return $this->redirectToRoute('app_reset_password');
  98. }
  99. // A password reset token should be used only once, remove it.
  100. $this->resetPasswordHelper->removeResetRequest($token);
  101. // Encode(hash) the plain password, and set it.
  102. $encodedPassword = $userPasswordHasher->hashPassword(
  103. $user,
  104. $form->get('plainPassword')->getData()
  105. );
  106. $user
  107. ->setPassword($encodedPassword)
  108. ->setLastPasswordChange(new \DateTime())
  109. ;
  110. $this->entityManager->flush();
  111. // The session is cleaned up after the password has been changed.
  112. $this->cleanSessionAfterReset();
  113. $this->addFlash('notice', 'Das Passwort wurde erfolgreich gesetzt!');
  114. return $this->redirectToRoute('fe.abo_login');
  115. }
  116. return $this->render('frontend/abo/reset_password/reset.html.twig', [
  117. 'resetForm' => $form->createView(),
  118. 'title' => 'Passwort ändern',
  119. ]);
  120. }
  121. private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer): RedirectResponse
  122. {
  123. $user = $this->entityManager->getRepository(Abonnent::class)->findOneBy([
  124. 'username' => $emailFormData,
  125. ]);
  126. // Do not reveal whether a user account was found or not.
  127. if (!$user) {
  128. return $this->redirectToRoute('app_check_email');
  129. }
  130. try {
  131. $resetToken = $this->resetPasswordHelper->generateResetToken($user);
  132. } catch (ResetPasswordExceptionInterface) {
  133. // If you want to tell the user why a reset email was not sent, uncomment
  134. // the lines below and change the redirect to 'app_forgot_password_request'.
  135. // Caution: This may reveal if a user is registered or not.
  136. //
  137. // $this->addFlash('reset_password_error', sprintf(
  138. // 'There was a problem handling your password reset request - %s',
  139. // $e->getReason()
  140. // ));
  141. return $this->redirectToRoute('app_check_email');
  142. }
  143. $email = (new TemplatedEmail())
  144. ->from(new Address($this->parameterBag->get('mailer_from'), $this->parameterBag->get('mailer_from_name')))
  145. ->to($user->getUsername())
  146. ->subject('Anfrage zum Ändern des Passworts')
  147. ->htmlTemplate('frontend/abo/reset_password/email.html.twig')
  148. ->context([
  149. 'resetToken' => $resetToken,
  150. ])
  151. ;
  152. $mailer->send($email);
  153. // Store the token object in session for retrieval in check-email route.
  154. $this->setTokenObjectInSession($resetToken);
  155. return $this->redirectToRoute('app_check_email');
  156. }
  157. }