createForm(::class); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $user = $this->getDoctrine()->getRepository(::class)->findOneBy([ '' => $form->get('')->getData(), ]); // Needed to be able to access next page, app_check_email $request->getSession()->set(self::SESSION_CAN_CHECK_EMAIL, true); // Do not reveal whether an user account was found or not. if (!$user) { return $this->redirectToRoute('app_check_email'); } // If User already has a valid Token, we don't want to generate a new one. // We fail silently. $oldTokens = $this->getDoctrine()->getRepository(::class)->findNonExpiredForUser($user); if (count($oldTokens)) { return $this->redirectToRoute('app_check_email'); } // Generate a reset password token, that the user could use to change their password. $resetPasswordToken = new ($user); $this->getDoctrine()->getManager()->persist($resetPasswordToken); $this->getDoctrine()->getManager()->flush(); $message = (new \Swift_Message('Your password reset request')) ->setFrom(['noreply@mydomain.com' => 'Noreply']) ->setTo($user->()) ->setBody($this->renderView('forgotten_password/email.txt.twig', [ 'token' => $resetPasswordToken, ])) ; $mailer->send($message); return $this->redirectToRoute('app_check_email'); } return $this->render('forgotten_password/request.html.twig', [ 'requestForm' => $form->createView(), ]); } /** * @Route("/check-email", name="app_check_email") */ public function checkEmail(SessionInterface $session) { // We prevent users from directly accessing this page if (!$session->get(self::SESSION_CAN_CHECK_EMAIL)) { return $this->redirectToRoute('app_forgotten_password_request'); } $session->remove(self::SESSION_CAN_CHECK_EMAIL); return $this->render('forgotten_password/check_email.html.twig', [ 'tokenLifetime' => ::LIFETIME_HOURS, ]); } /** * @Route("/reset/{tokenAndSelector}", name="app_reset_password") */ public function reset(Request $request, UserPasswordEncoderInterface $passwordEncoder, $tokenAndSelector = null): Response { if ($tokenAndSelector) { // We store token in session and remove it from the URL, // to avoid any leak if someone get to know the URL (AJAX requests, Analytics...). $request->getSession()->set(self::SESSION_TOKEN_KEY, $tokenAndSelector); return $this->redirectToRoute('app_reset_password'); } $tokenAndSelector = $request->getSession()->get(self::SESSION_TOKEN_KEY); if (!$tokenAndSelector) { throw $this->createNotFoundException(); } $passwordResetToken = $this->getDoctrine()->getRepository(::class)->findOneBy([ 'selector' => substr($tokenAndSelector, 0, ::SELECTOR_LENGTH), ]); if (!$passwordResetToken) { throw $this->createNotFoundException(); } if ($passwordResetToken->isExpired() || !$passwordResetToken->isTokenEquals(substr($tokenAndSelector, ::SELECTOR_LENGTH))) { $this->getDoctrine()->getManager()->remove($passwordResetToken); $this->getDoctrine()->getManager()->flush(); throw $this->createNotFoundException(); } $form = $this->createForm(::class); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { // A should be used only once, remove it. $this->getDoctrine()->getManager()->remove($passwordResetToken); // Encode the plain password, and set it. $passwordResetToken->getUser()->( $passwordEncoder->encodePassword( $passwordResetToken->getUser(), $form->get('plainPassword')->getData() ) ); $this->getDoctrine()->getManager()->flush(); // TODO: please check the login route return $this->redirectToRoute(''); } return $this->render('forgotten_password/reset.html.twig', [ 'resetForm' => $form->createView(), ]); } }