src/Controller/ResetPasswordController.php line 74

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\User;
  4. use App\Form\ChangePasswordFormType;
  5. use App\Form\ResetPasswordRequestFormType;
  6. use App\Service\EmailManager;
  7. use App\Service\User\UserDomainHelper;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use Symfony\Bridge\Twig\Mime\TemplatedEmail;
  10. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  11. use Symfony\Component\HttpFoundation\RedirectResponse;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
  15. use Symfony\Component\Mime\Address;
  16. use Symfony\Component\Routing\Annotation\Route;
  17. use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  18. use Symfony\Contracts\Translation\TranslatorInterface;
  19. use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
  20. use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
  21. use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
  22. /**
  23. * @Route("/reset-password")
  24. */
  25. class ResetPasswordController extends AbstractController
  26. {
  27. use ResetPasswordControllerTrait;
  28. /**
  29. * @var ResetPasswordHelperInterface
  30. */
  31. private ResetPasswordHelperInterface $resetPasswordHelper;
  32. /**
  33. * @var TranslatorInterface
  34. */
  35. private TranslatorInterface $translator;
  36. /**
  37. * @var EmailManager
  38. */
  39. private EmailManager $emailManager;
  40. private EntityManagerInterface $manager;
  41. /**
  42. * ResetPasswordController constructor.
  43. * @param ResetPasswordHelperInterface $resetPasswordHelper
  44. * @param TranslatorInterface $translator
  45. * @param EmailManager $emailManager
  46. * @param EntityManagerInterface $manager
  47. */
  48. public function __construct(
  49. ResetPasswordHelperInterface $resetPasswordHelper,
  50. TranslatorInterface $translator,
  51. EmailManager $emailManager,
  52. EntityManagerInterface $manager
  53. ) {
  54. $this->resetPasswordHelper = $resetPasswordHelper;
  55. $this->translator = $translator;
  56. $this->emailManager = $emailManager;
  57. $this->manager = $manager;
  58. }
  59. /**
  60. * Display & process form to request a password reset.
  61. *
  62. * @Route("", name="app_forgot_password_request")
  63. * @param Request $request
  64. * @return Response
  65. * @throws TransportExceptionInterface
  66. */
  67. public function request(Request $request): Response
  68. {
  69. $form = $this->createForm(ResetPasswordRequestFormType::class);
  70. $form->handleRequest($request);
  71. if ($form->isSubmitted() && $form->isValid()) {
  72. return $this->processSendingPasswordResetEmail(
  73. $form->get('email')->getData()
  74. );
  75. }
  76. return $this->render('reset_password/request.html.twig', [
  77. 'requestForm' => $form->createView(),
  78. ]);
  79. }
  80. /**
  81. * Confirmation page after a user has requested a password reset.
  82. *
  83. * @Route("/check-email", name="app_check_email")
  84. */
  85. public function checkEmail(): Response
  86. {
  87. // We prevent users from directly accessing this page
  88. if (!$this->canCheckEmail()) {
  89. return $this->redirectToRoute('app_forgot_password_request');
  90. }
  91. return $this->render('reset_password/check_email.html.twig', [
  92. 'tokenLifetime' => $this->resetPasswordHelper->getTokenLifetime(),
  93. ]);
  94. }
  95. /**
  96. * Validates and process the reset URL that the user clicked in their email.
  97. *
  98. * @Route("/reset/{token}", name="app_reset_password")
  99. * @param Request $request
  100. * @param UserPasswordEncoderInterface $passwordEncoder
  101. * @param string|null $token
  102. * @param UserDomainHelper $userDomainHelper
  103. * @return Response
  104. */
  105. public function reset(
  106. Request $request,
  107. UserPasswordEncoderInterface $passwordEncoder,
  108. string $token = null,
  109. UserDomainHelper $userDomainHelper
  110. ): Response {
  111. try {
  112. $user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
  113. } catch (ResetPasswordExceptionInterface $e) {
  114. $this->addFlash('reset_password_error', sprintf(
  115. 'There was a problem validating your reset request - %s',
  116. $e->getReason()
  117. ));
  118. return $this->redirectToRoute('app_forgot_password_request');
  119. }
  120. // The token is valid; allow the user to change their password.
  121. $form = $this->createForm(ChangePasswordFormType::class);
  122. $form->handleRequest($request);
  123. if ($form->isSubmitted() && $form->isValid()) {
  124. // A password reset token should be used only once, remove it.
  125. $this->resetPasswordHelper->removeResetRequest($token);
  126. // Encode the plain password, and set it.
  127. $encodedPassword = $passwordEncoder->encodePassword(
  128. $user,
  129. $form->get('plainPassword')->getData()
  130. );
  131. $user->setPassword($encodedPassword);
  132. $this->manager->flush();
  133. // The session is cleaned up after the password has been changed.
  134. $this->cleanSessionAfterReset();
  135. $this->addFlash(
  136. 'success',
  137. $this->translator->trans('resetPassword.success', [], 'security')
  138. );
  139. return $this->redirect($userDomainHelper->getHomeUrlForUser($user));
  140. }
  141. return $this->render('reset_password/reset.html.twig', [
  142. 'resetForm' => $form->createView(),
  143. ]);
  144. }
  145. /**
  146. * @param string $emailFormData
  147. * @return RedirectResponse
  148. * @throws TransportExceptionInterface
  149. */
  150. private function processSendingPasswordResetEmail(string $emailFormData): RedirectResponse
  151. {
  152. $user = $this->manager->getRepository(User::class)->findOneBy([
  153. 'email' => $emailFormData,
  154. ]);
  155. // Marks that you are allowed to see the app_check_email page.
  156. $this->setCanCheckEmailInSession();
  157. // Do not reveal whether a user account was found or not.
  158. if (!$user) {
  159. return $this->redirectToRoute('app_check_email');
  160. }
  161. try {
  162. $resetToken = $this->resetPasswordHelper->generateResetToken($user);
  163. } catch (ResetPasswordExceptionInterface $e) {
  164. // If you want to tell the user why a reset email was not sent, uncomment
  165. // the lines below and change the redirect to 'app_forgot_password_request'.
  166. // Caution: This may reveal if a user is registered or not.
  167. //
  168. // $this->addFlash('reset_password_error', sprintf(
  169. // 'There was a problem handling your password reset request - %s',
  170. // $e->getReason()
  171. // ));
  172. return $this->redirectToRoute('app_check_email');
  173. }
  174. $email = (new TemplatedEmail())
  175. ->from(new Address('registrace@e-manazer.cz', 'E-manažer'))
  176. ->to($user->getEmail())
  177. ->subject($this->translator->trans('resetRequestEmail.subject', [], 'security'))
  178. ->htmlTemplate('reset_password/email.html.twig')
  179. ->textTemplate('reset_password/email.txt.twig')
  180. ->context([
  181. 'resetToken' => $resetToken,
  182. 'tokenLifetime' => $this->resetPasswordHelper->getTokenLifetime(),
  183. ]);
  184. $this->emailManager->sendMail($email);
  185. return $this->redirectToRoute('app_check_email');
  186. }
  187. }