src/Controller/ResetPasswordController.php line 42

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 Doctrine\ORM\EntityManagerInterface;
  7. use Symfony\Bridge\Twig\Mime\TemplatedEmail;
  8. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  9. use Symfony\Component\HttpFoundation\RedirectResponse;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\Response;
  12. use Symfony\Component\Mailer\MailerInterface;
  13. use Symfony\Component\Mime\Address;
  14. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  15. use Symfony\Component\Routing\Annotation\Route;
  16. use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
  17. use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
  18. use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
  19. #[ Route( '/reset-password' ) ]
  20. class ResetPasswordController extends AbstractController
  21.  {
  22.     use ResetPasswordControllerTrait;
  23.     private $resetPasswordHelper;
  24.     private $entityManager;
  25.     public function __construct( ResetPasswordHelperInterface $resetPasswordHelper, EntityManagerInterface $entityManager )
  26.  {
  27.         $this->resetPasswordHelper = $resetPasswordHelper;
  28.         $this->entityManager = $entityManager;
  29.     }
  30.     /**
  31.     * Display & process form to request a password reset.
  32.     */
  33.     #[ Route( '', name: 'app_forgot_password_request' ) ]
  34.     public function request( Request $request, MailerInterface $mailer ): Response
  35.  {
  36.         $form = $this->createForm( ResetPasswordRequestFormType::class );
  37.         $form->handleRequest( $request );
  38.         if ( $form->isSubmitted() && $form->isValid() ) {
  39.             return $this->processSendingPasswordResetEmail(
  40.                 $form->get( 'email' )->getData(),
  41.                 $mailer
  42.             );
  43.         }
  44.         return $this->render( 'reset_password/request.html.twig', [
  45.             'requestForm' => $form->createView(),
  46.         ] );
  47.     }
  48.     /**
  49.     * Confirmation page after a user has requested a password reset.
  50.     */
  51.     #[ Route( '/check-email', name: 'app_check_email' ) ]
  52.     public function checkEmail(): Response
  53.  {
  54.         // Generate a fake token if the user does not exist or someone hit this page directly.
  55.         // This prevents exposing whether or not a user was found with the given email address or not
  56.         if ( null === ( $resetToken = $this->getTokenObjectFromSession() ) ) {
  57.             $resetToken = $this->resetPasswordHelper->generateFakeResetToken();
  58.         }
  59.         return $this->render( 'reset_password/check_email.html.twig', [
  60.             'resetToken' => $resetToken,
  61.         ] );
  62.     }
  63.     /**
  64.     * Validates and process the reset URL that the user clicked in their email.
  65.     */
  66.     #[ Route( '/reset/{token}', name: 'app_reset_password' ) ]
  67.     public function reset( Request $request, UserPasswordHasherInterface $userPasswordHasher, string $token = null ): Response
  68.  {
  69.         if ( $token ) {
  70.             // We store the token in session and remove it from the URL, to avoid the URL being
  71.             // loaded in a browser and potentially leaking the token to 3rd party JavaScript.
  72.             $this->storeTokenInSession( $token );
  73.             return $this->redirectToRoute( 'app_reset_password' );
  74.         }
  75.         $token = $this->getTokenFromSession();
  76.         if ( null === $token ) {
  77.             throw $this->createNotFoundException( 'No reset password token found in the URL or in the session.' );
  78.         }
  79.         try {
  80.             $user = $this->resetPasswordHelper->validateTokenAndFetchUser( $token );
  81.         } catch ( ResetPasswordExceptionInterface $e ) {
  82.             $this->addFlash( 'reset_password_error', sprintf(
  83.                 'There was a problem validating your reset request - %s',
  84.                 $e->getReason()
  85.             ) );
  86.             return $this->redirectToRoute( 'app_forgot_password_request' );
  87.         }
  88.         // The token is valid;
  89.         // allow the user to change their password.
  90.         $form = $this->createForm( ChangePasswordFormType::class );
  91.         $form->handleRequest( $request );
  92.         if ( $form->isSubmitted() && $form->isValid() ) {
  93.             // A password reset token should be used only once, remove it.
  94.             $this->resetPasswordHelper->removeResetRequest( $token );
  95.             // Encode( hash ) the plain password, and set it.
  96.             $encodedPassword = $userPasswordHasher->hashPassword(
  97.                 $user,
  98.                 $form->get( 'plainPassword' )->getData()
  99.             );
  100.             $user->setPassword( $encodedPassword );
  101.             $this->entityManager->flush();
  102.             // The session is cleaned up after the password has been changed.
  103.             $this->cleanSessionAfterReset();
  104.             return $this->redirectToRoute( 'login' );
  105.         }
  106.         return $this->render( 'reset_password/reset.html.twig', [
  107.             'resetForm' => $form->createView(),
  108.         ] );
  109.     }
  110.     private function processSendingPasswordResetEmail( string $emailFormData, MailerInterface $mailer ): RedirectResponse
  111.  {
  112.         $user = $this->entityManager->getRepository( User::class )->findOneBy( [
  113.             'email' => $emailFormData,
  114.         ] );
  115.         // Do not reveal whether a user account was found or not.
  116.         if ( !$user ) {
  117.             return $this->redirectToRoute( 'app_check_email' );
  118.         }
  119.         try {
  120.             $resetToken = $this->resetPasswordHelper->generateResetToken( $user );
  121.         } catch ( ResetPasswordExceptionInterface $e ) {
  122.             // If you want to tell the user why a reset email was not sent, uncomment
  123.             // the lines below and change the redirect to 'app_forgot_password_request'.
  124.             // Caution: This may reveal if a user is registered or not.
  125.             //
  126.             // $this->addFlash( 'reset_password_error', sprintf(
  127.             //     'There was a problem handling your password reset request - %s',
  128.             //     $e->getReason()
  129.             // ) );
  130.             return $this->redirectToRoute( 'app_check_email' );
  131.         }
  132.         $email = ( new TemplatedEmail() )
  133.         ->from( new Address( 'notificaciones@flc.tecsens.com', 'FLC - TECSENS' ) )
  134.         ->to( $user->getEmail() )
  135.         ->subject( 'Restablece la contraseƱa de tu cuenta como usuario' )
  136.         ->htmlTemplate( 'reset_password/email.html.twig' )
  137.         ->context( [
  138.             'resetToken' => $resetToken,
  139.         ] );
  140.         $mailer->send( $email );
  141.         // Store the token object in session for retrieval in check-email route.
  142.         $this->setTokenObjectInSession( $resetToken );
  143.         return $this->redirectToRoute( 'app_check_email' );
  144.     }
  145. }