<?php
namespace App\Controller\Home\authentication\recover;
use App\Exception\AuthenticationException;
use App\Exception\InvalidParameterException;
use App\Interfaces\UsuarioHermesRepositoryInterface;
use App\Services\AsymmetricEncryptionService;
use Doctrine\Common\Collections\Criteria;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;
/**
* Controlador para solicitar la recuperación de contraseña por email
*/
class RecoverRequestEmailController extends AbstractController
{
/**
* @param SessionInterface $session Servicio de sesión
* @param AsymmetricEncryptionService $asymmetricEncryptionService Servicio de encriptación asimétrica
* @param MailerInterface $mailer Servicio de correo electrónico
* @param RouterInterface $router Servicio de enrutamiento
* @param Environment $templating Servicio de plantillas Twig
* @param UsuarioHermesRepositoryInterface $usuarioHermesRepository Repositorio de usuarios
* @param TranslatorInterface $translator Servicio de traducción
* @param LoggerInterface $logger Servicio de logging
*/
public function __construct(
private SessionInterface $session,
private AsymmetricEncryptionService $asymmetricEncryptionService,
private MailerInterface $mailer,
private RouterInterface $router,
private Environment $templating,
private UsuarioHermesRepositoryInterface $usuarioHermesRepository,
private TranslatorInterface $translator,
private LoggerInterface $logger
) { }
/**
* Procesa la solicitud de recuperación de contraseña por email
*
* @Route("/{_locale}/recover/request/email", name="recover_request_email", defaults={"_locale" = "ca"}, requirements={"_locale": "es|ca"}, methods={"GET", "POST"})
*
* @param Request $request Objeto Request de Symfony
*
* @return Response
*
* @throws InvalidParameterException Si el email no es válido o está vacío
* @throws AuthenticationException Si no existe un usuario con el email proporcionado
*/
public function __invoke(Request $request): Response
{
try {
// Si no es una solicitud POST, simplemente renderizar el formulario
if (!$request->isMethod('POST')) {
return $this->render('home/authentication/recover/recover_request_email.html.twig');
}
// Obtener y validar el email
$email = $request->request->get('email');
if (empty($email)) {
throw new InvalidParameterException('El email es obligatorio');
}
// Validar formato de email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidParameterException('El formato del email no es válido');
}
// Buscar usuario por email
$criteria = (new Criteria())->andWhere(Criteria::expr()->eq('email', $email));
$usuarioCollection = $this->usuarioHermesRepository->find($criteria);
// Verificar que existe un usuario con ese email
if (!$usuarioCollection || $usuarioCollection->isEmpty()) {
throw new AuthenticationException("No existe ninguna cuenta con el email {$email}");
}
// Crear token de recuperación con tiempo de expiración
$tokenData = json_encode([
'ts' => time(),
'email' => $email
]);
// Encriptar token
$token = $this->asymmetricEncryptionService->privateEncrypt($tokenData);
// Generar link de recuperación
$link = $this->router->generate('recover_request_new_password', ['token' => $token], RouterInterface::ABSOLUTE_URL);
// Preparar y enviar email
$emailFrom = $_ENV['EMAIL_FROM_ADDRESS'] ?? "no-reply@conforcat.cat";
$nameFrom = $_ENV['EMAIL_FROM_NAME'] ?? "Conforcat";
$emailMessage = (new Email())
->from(new Address($emailFrom, $nameFrom))
->to($email)
->subject($this->translator->trans('email.subject.recover_password', [], 'recover_password'))
->html($this->templating->render(
'home/authentication/recover/email_recover_token_sent.html.twig',
['link' => $link]
));
// Enviar email
$this->mailer->send($emailMessage);
// Renderizar página de confirmación
return $this->render('home/authentication/recover/recover_token_sent.html.twig', [
'email' => $email
]);
} catch (InvalidParameterException | AuthenticationException $e) {
// Manejar excepciones no críticas
$this->addFlash('error', $e->getMessage());
$this->logger->warning('Error en solicitud de recuperación: ' . $e->getMessage());
// Volver al formulario
return $this->render('home/authentication/recover/recover_request_email.html.twig');
} catch (TransportExceptionInterface $e) {
// Manejar errores de envío de email
$this->logger->error('Error al enviar email de recuperación: ' . $e->getMessage());
$this->addFlash('error', 'No se pudo enviar el email de recuperación. Por favor, inténtelo más tarde.');
return $this->render('home/authentication/recover/recover_request_email.html.twig');
} catch (\Throwable $e) {
throw $e;
}
}
}