src/Controller/UserController.php line 278

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\User;
  4. use App\Form\UserType;
  5. use App\Repository\UserRepository;
  6. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\Routing\Annotation\Route;
  10. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  11. use Doctrine\ORM\EntityManagerInterface;
  12. use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
  13. use App\Entity\Appointment;
  14. use Symfony\Component\HttpFoundation\JsonResponse;
  15. use App\Form\ProveedorType;
  16. use App\Service\ProviderNotifier;
  17. class UserController extends AbstractController
  18. {
  19.     private $passwordHasher;
  20.     public function __construct(UserPasswordHasherInterface $passwordHasher)
  21.     {
  22.         $this->passwordHasher $passwordHasher;
  23.     }
  24.     /*****************************************************************
  25.      * PACIENTES - ADMIN
  26.      *****************************************************************/
  27.     /**
  28.      * @Route("/admin/pacientes/nuevo", name="admin_paciente_new", methods={"GET", "POST"})
  29.      */
  30.     public function nuevoPaciente(Request $requestUserRepository $userRepositoryEntityManagerInterface $entityManager): Response
  31.     {
  32.         $user = new User();
  33.            $form $this->createForm(UserType::class, $user, [
  34.             'validation_groups' => ['Default'// Solo validaciones básicas, sin password
  35.         ]);
  36.         $form->handleRequest($request);
  37.         
  38.     
  39.         if ($form->isSubmitted() && $form->isValid()) {
  40.             // Generar contraseña aleatoria
  41.             $randomPassword $this->generateRandomPassword();
  42.             $user->setPassword($this->passwordHasher->hashPassword($user$randomPassword));
  43.             
  44.             // Asignar rol de paciente por defecto
  45.             $user->setRoles(['ROLE_CLIENT']);
  46.     
  47.             try {
  48.                 if ($this->isGranted('ROLE_ADMIN')) {
  49.                     // Buscar al admin por rol, ordenando por ID descendente para obtener el último
  50.                     $admin $entityManager->getRepository(User::class)
  51.                         ->createQueryBuilder('u')
  52.                         ->andWhere('u.roles LIKE :role')
  53.                         ->setParameter('role''%"ROLE_ADMIN"%')
  54.                         ->orderBy('u.id''DESC'// Ordenar por ID descendente
  55.                         ->setMaxResults(1)
  56.                         ->getQuery()
  57.                         ->getOneOrNullResult();
  58.     
  59.                     if ($admin) {
  60.                         $admin->addPatient($user);
  61.                         $entityManager->persist($admin);
  62.                     }
  63.                 } elseif ($this->isGranted('ROLE_PROVIDER')) {
  64.                     /** @var User $provider */
  65.                     $provider $this->getUser();
  66.                     $provider->addPatient($user);
  67.                     $entityManager->persist($provider);
  68.                 }
  69.     
  70.                 $userRepository->add($usertrue);
  71.     
  72.                 // Mostrar la contraseña generada al administrador
  73.                 $this->addFlash('success''Paciente creado correctamente.');
  74.     
  75.                 return $this->redirectToRoute('admin_pacientes');
  76.     
  77.             } catch (UniqueConstraintViolationException $e) {
  78.                 $this->addFlash('error''Ya existe una cuenta con este correo electrónico.');
  79.             }
  80.         }
  81.     
  82.         return $this->render('admin/user/form.html.twig', [
  83.             'user' => $user,
  84.             'form' => $form->createView(),
  85.             'modo' => 'new',
  86.             'tipo' => 'paciente',
  87.             'seccion' => 'pacientes',
  88.             'titulo_pagina' => 'Nuevo Paciente'
  89.         ]);
  90.     }
  91.     
  92.     /**
  93.      * Genera una contraseña aleatoria segura
  94.      */
  95.     private function generateRandomPassword(int $length 12): string
  96.     {
  97.         $characters '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%&*';
  98.         $charactersLength strlen($characters);
  99.         $randomPassword '';
  100.         
  101.         for ($i 0$i $length$i++) {
  102.             $randomPassword .= $characters[random_int(0$charactersLength 1)];
  103.         }
  104.         
  105.         return $randomPassword;
  106.     }
  107.     /**
  108.      * @Route("/admin/pacientes/editar/{id}", name="admin_paciente_edit", methods={"GET", "POST"})
  109.      */
  110.     public function editarPaciente(Request $requestUser $userUserRepository $userRepositoryEntityManagerInterface $entityManager): Response
  111.     {
  112.         // Verificar que el usuario sea un paciente
  113.         if (!in_array('ROLE_CLIENT'$user->getRoles())) {
  114.             $this->addFlash('error''El usuario no es un paciente.');
  115.             return $this->redirectToRoute('admin_pacientes');
  116.         }
  117.     
  118.         // Guardar el email original para verificar cambios
  119.         $emailOriginal $user->getEmail();
  120.         
  121.         $form $this->createForm(UserType::class, $user);
  122.         $form->handleRequest($request);
  123.     
  124.         if ($form->isSubmitted() && $form->isValid()) {
  125.   
  126.             $randomPassword $this->generateRandomPassword();
  127.             $user->setPassword($this->passwordHasher->hashPassword($user$randomPassword));
  128.         
  129.             try {
  130.                 // Si el usuario actual es admin, actualizar la relación con el último admin
  131.                 if ($this->isGranted('ROLE_ADMIN')) {
  132.                     // Buscar al admin por rol, ordenando por ID descendente para obtener el último
  133.                     $admin $entityManager->getRepository(User::class)
  134.                         ->createQueryBuilder('u')
  135.                         ->andWhere('u.roles LIKE :role')
  136.                         ->setParameter('role''%"ROLE_ADMIN"%')
  137.                         ->orderBy('u.id''DESC'// Ordenar por ID descendente
  138.                         ->setMaxResults(1)
  139.                         ->getQuery()
  140.                         ->getOneOrNullResult();
  141.     
  142.                     if ($admin) {
  143.                         // Remover de todos los admins anteriores
  144.                         $allAdmins $entityManager->getRepository(User::class)
  145.                             ->createQueryBuilder('u')
  146.                             ->andWhere('u.roles LIKE :role')
  147.                             ->setParameter('role''%"ROLE_ADMIN"%')
  148.                             ->getQuery()
  149.                             ->getResult();
  150.     
  151.                         foreach ($allAdmins as $previousAdmin) {
  152.                             $previousAdmin->removePatient($user);
  153.                             $entityManager->persist($previousAdmin);
  154.                         }
  155.     
  156.                         // Agregar al último admin
  157.                         $admin->addPatient($user);
  158.                         $entityManager->persist($admin);
  159.                     }
  160.                 }
  161.     
  162.                 $userRepository->add($usertrue);
  163.     
  164.                 $this->addFlash('success''Paciente actualizado correctamente.');
  165.     
  166.                 return $this->redirectToRoute('admin_pacientes');
  167.     
  168.             } catch (UniqueConstraintViolationException $e) {
  169.                 $this->addFlash('error''Ya existe una cuenta con este correo electrónico.');
  170.             } catch (\Exception $e) {
  171.                 $this->addFlash('error''Error al actualizar el paciente: ' $e->getMessage());
  172.             }
  173.         }
  174.     
  175.         return $this->render('admin/user/form.html.twig', [
  176.             'user' => $user,
  177.             'form' => $form->createView(),
  178.             'modo' => 'edit',
  179.             'tipo' => 'paciente',
  180.             'seccion' => 'pacientes',
  181.             'titulo_pagina' => 'Editar Paciente'
  182.         ]);
  183.     }
  184.     /**
  185.      * @Route("/admin/paciente/{id}/check-citas", name="admin_paciente_check_citas", methods={"GET"})
  186.      */
  187.     public function checkCitasPaciente(User $pacienteEntityManagerInterface $entityManager): JsonResponse
  188.     {
  189.         $citasCount $entityManager->getRepository(Appointment::class)
  190.             ->createQueryBuilder('a')
  191.             ->select('COUNT(a.id)')
  192.             ->where('a.patient = :patient')
  193.             ->setParameter('patient'$paciente)
  194.             ->getQuery()
  195.             ->getSingleScalarResult();
  196.         return $this->json([
  197.             'hasCitas' => $citasCount 0,
  198.             'citasCount' => $citasCount
  199.         ]);
  200.     }
  201.     /**
  202.      * @Route("/admin/pacientes/eliminar/{id}", name="admin_paciente_delete", methods={"POST"})
  203.     */
  204.     public function eliminarPaciente(User $pacienteEntityManagerInterface $entityManager): Response
  205.     {
  206.         // Verificar si tiene citas
  207.         $citasCount $entityManager->getRepository(Appointment::class)
  208.             ->createQueryBuilder('a')
  209.             ->select('COUNT(a.id)')
  210.             ->where('a.patient = :patient')
  211.             ->setParameter('patient'$paciente)
  212.             ->getQuery()
  213.             ->getSingleScalarResult();
  214.         
  215.         try {
  216.             // Si tiene citas, eliminarlas primero
  217.             if ($citasCount 0) {
  218.                 $appointments $entityManager->getRepository(Appointment::class)
  219.                     ->createQueryBuilder('a')
  220.                     ->where('a.patient = :patient')
  221.                     ->setParameter('patient'$paciente)
  222.                     ->getQuery()
  223.                     ->getResult();
  224.                 
  225.                 foreach ($appointments as $appointment) {
  226.                     $entityManager->remove($appointment);
  227.                 }
  228.             }
  229.             
  230.           // Buscar todos los proveedores que tienen a este paciente asignado
  231.             $providers $entityManager->getRepository(User::class)
  232.                 ->createQueryBuilder('u')
  233.                 ->innerJoin('u.patients''p')
  234.                 ->where('p = :patient')
  235.                 ->setParameter('patient'$paciente)
  236.                 ->getQuery()
  237.                 ->getResult();
  238.             // Remover al paciente de la lista de pacientes de cada proveedor
  239.             foreach ($providers as $provider) {
  240.                 $provider->removePatient($paciente); // Necesitas este método en tu entidad User
  241.             }
  242.             // Finalmente eliminar el usuario
  243.             $entityManager->remove($paciente);
  244.             $entityManager->flush();
  245.             
  246.             if ($citasCount 0) {
  247.                 $this->addFlash('warning'"Paciente eliminado junto con {$citasCount} cita(s) asociada(s)");
  248.             } else {
  249.                 $this->addFlash('success''Paciente eliminado correctamente');
  250.             }
  251.             
  252.         } catch (\Exception $e) {
  253.             $this->addFlash('error''Error al eliminar el paciente: ' $e->getMessage());
  254.         }
  255.         
  256.         return $this->redirectToRoute('admin_pacientes');
  257.     }
  258.     /*****************************************************************
  259.      * PROVEEDORES - ADMIN
  260.      *****************************************************************/
  261.     /**
  262.      * @Route("/admin/proveedores/nuevo", name="admin_proveedor_new", methods={"GET", "POST"})
  263.      */
  264.     public function nuevoProveedor(
  265.         Request $request
  266.         UserRepository $userRepository
  267.         EntityManagerInterface $entityManager,
  268.         ProviderNotifier $providerNotifier
  269.     ): Response
  270.     {
  271.         $user = new User();
  272.     
  273.         // Para proveedores, establece un lastName por defecto
  274.         $user->setLastName('Clínica');
  275.     
  276.         $form $this->createForm(ProveedorType::class, $user, [
  277.             'es_nuevo' => true,
  278.         ]);
  279.         $form->handleRequest($request);
  280.     
  281.         if ($form->isSubmitted() && $form->isValid()) {
  282.             // Verificar que plainPassword no sea null
  283.             if (!$user->getPlainPassword()) {
  284.                 $this->addFlash('error''La contraseña es obligatoria.');
  285.                 return $this->render('admin/user/proveedor_form.html.twig', [
  286.                     'user' => $user,
  287.                     'form' => $form->createView(),
  288.                     'modo' => 'new',
  289.                     'tipo' => 'proveedor',
  290.                     'seccion' => 'proveedores',
  291.                     'titulo_pagina' => 'Nuevo Proveedor'
  292.                 ]);
  293.             }
  294.     
  295.             $user->setPassword($this->passwordHasher->hashPassword($user$user->getPlainPassword()));
  296.     
  297.             // Asegurar que el lastName esté establecido para proveedores
  298.             if (empty($user->getLastName())) {
  299.                 $user->setLastName('Clínica');
  300.             }
  301.             
  302.             // Asignar rol de proveedor por defecto
  303.             $user->setRoles(['ROLE_PROVIDER']);
  304.     
  305.             $user->setEntityType('clinica'); // Marcar como clínica
  306.     
  307.             try {
  308.                 if ($this->isGranted('ROLE_ADMIN')) {
  309.                     // Buscar al admin por rol, ordenando por ID descendente para obtener el último
  310.                     $admin $entityManager->getRepository(User::class)
  311.                         ->createQueryBuilder('u')
  312.                         ->andWhere('u.roles LIKE :role')
  313.                         ->setParameter('role''%"ROLE_ADMIN"%')
  314.                         ->orderBy('u.id''DESC'// ← ORDENAR POR ID DESCENDENTE
  315.                         ->setMaxResults(1)
  316.                         ->getQuery()
  317.                         ->getOneOrNullResult();
  318.     
  319.                     if ($admin) {
  320.                         $admin->addPatient($user);
  321.                         $entityManager->persist($admin);
  322.                     }
  323.                 } elseif ($this->isGranted('ROLE_PROVIDER')) {
  324.                     /** @var User $provider */
  325.                     $provider $this->getUser();
  326.                     $provider->addPatient($user);
  327.                     $entityManager->persist($provider);
  328.                 }
  329.     
  330.                 $userRepository->add($usertrue);
  331.                 
  332.                 // ✅ CORRECTO: Usar el servicio inyectado
  333.                 $language $request->getSession()->get('_locale''es'); 
  334.                 $providerNotifier->sendProviderNotification($user'create'$language);
  335.     
  336.                 $this->addFlash('success''Proveedor creado correctamente.');
  337.     
  338.                 return $this->redirectToRoute('admin_proveedores');
  339.     
  340.             } catch (UniqueConstraintViolationException $e) {
  341.                 $this->addFlash('error''Ya existe una cuenta con este correo electrónico.');
  342.             } catch (\Exception $e) {
  343.                 $this->addFlash('error''Error al crear el proveedor: ' $e->getMessage());
  344.             }
  345.         }
  346.     
  347.         return $this->render('admin/user/proveedor_form.html.twig', [
  348.             'user' => $user,
  349.             'form' => $form->createView(),
  350.             'modo' => 'new',
  351.             'tipo' => 'proveedor',
  352.             'seccion' => 'proveedores',
  353.             'titulo_pagina' => 'Nuevo Proveedor'
  354.         ]);
  355.     }
  356.     /**
  357.      * @Route("/admin/proveedores/editar/{id}", name="admin_proveedor_edit", methods={"GET", "POST"})
  358.      */
  359.     public function editarProveedor(Request $requestUser $userUserRepository $userRepositoryEntityManagerInterface $entityManager): Response
  360.     {
  361.         // Verificar que el usuario sea un proveedor
  362.         if (!in_array('ROLE_PROVIDER'$user->getRoles())) {
  363.             $this->addFlash('error''El usuario no es un proveedor.');
  364.             return $this->redirectToRoute('admin_proveedores');
  365.         }
  366.     
  367.         // Para proveedores, establece un lastName por defecto si está vacío
  368.         if (empty($user->getLastName())) {
  369.             $user->setLastName('Clínica');
  370.         }
  371.     
  372.         $form $this->createForm(ProveedorType::class, $user, [
  373.             'es_nuevo' => false,
  374.         ]);
  375.         
  376.         $form->handleRequest($request);
  377.     
  378.         if ($form->isSubmitted()) {
  379.             if ($form->isValid()) {
  380.                 // Si se cambió la contraseña, hashearla
  381.                 if ($user->getPlainPassword()) {
  382.                     $hashedPassword $this->passwordHasher->hashPassword($user$user->getPlainPassword());
  383.                     $user->setPassword($hashedPassword);
  384.                 }
  385.     
  386.                try {
  387.                     // Si el usuario actual es admin, actualizar la relación con el último admin
  388.                     if ($this->isGranted('ROLE_ADMIN')) {
  389.                         // Buscar al admin por rol, ordenando por ID descendente para obtener el último
  390.                         $admin $entityManager->getRepository(User::class)
  391.                             ->createQueryBuilder('u')
  392.                             ->andWhere('u.roles LIKE :role')
  393.                             ->setParameter('role''%"ROLE_ADMIN"%')
  394.                             ->orderBy('u.id''DESC'// ← ORDENAR POR ID DESCENDENTE
  395.                             ->setMaxResults(1)
  396.                             ->getQuery()
  397.                             ->getOneOrNullResult();
  398.     
  399.                         if ($admin) {
  400.                             // Remover de todos los admins anteriores
  401.                             $allAdmins $entityManager->getRepository(User::class)
  402.                                 ->createQueryBuilder('u')
  403.                                 ->andWhere('u.roles LIKE :role')
  404.                                 ->setParameter('role''%"ROLE_ADMIN"%')
  405.                                 ->getQuery()
  406.                                 ->getResult();
  407.     
  408.                             foreach ($allAdmins as $previousAdmin) {
  409.                                 $previousAdmin->removePatient($user);
  410.                                 $entityManager->persist($previousAdmin);
  411.                             }
  412.     
  413.                             // Agregar al último admin
  414.                             $admin->addPatient($user);
  415.                             $entityManager->persist($admin);
  416.                         }
  417.                     }
  418.     
  419.                     $entityManager->persist($user);
  420.                     dump("aki1 - Persist realizado");
  421.                     
  422.                     $entityManager->flush();
  423.                     dump("aki2 - Flush exitoso");
  424.                     
  425.                     $this->addFlash('success''Proveedor actualizado correctamente.');
  426.                     return $this->redirectToRoute('admin_proveedores');
  427.                 
  428.                 } catch (\Doctrine\DBAL\Exception\DriverException $e) {
  429.                     dump('Error de driver:'$e->getMessage());
  430.                     $this->addFlash('error''Error de base de datos: ' $e->getMessage());
  431.                 } catch (\Doctrine\DBAL\Exception\ConstraintViolationException $e) {
  432.                     dump('Error de constraint:'$e->getMessage());
  433.                     $this->addFlash('error''Error de restricción: ' $e->getMessage());
  434.                 } catch (\Doctrine\ORM\ORMException $e) {
  435.                     dump('Error ORM:'$e->getMessage());
  436.                     $this->addFlash('error''Error ORM: ' $e->getMessage());
  437.                 } catch (UniqueConstraintViolationException $e) {
  438.                     $this->addFlash('error''Ya existe una cuenta con este correo electrónico.');
  439.                 } catch (\Exception $e) {
  440.                     dump('Error general:'$e->getMessage(), $e->getTraceAsString());
  441.                     $this->addFlash('error''Error al actualizar el proveedor: ' $e->getMessage());
  442.                 }
  443.             } else {
  444.                 $this->addFlash('error''Por favor, corrige los errores en el formulario.');
  445.             }
  446.         }
  447.     
  448.         return $this->render('admin/user/proveedor_form.html.twig', [
  449.             'user' => $user,
  450.             'form' => $form->createView(),
  451.             'modo' => 'edit',
  452.             'tipo' => 'proveedor',
  453.             'seccion' => 'proveedores',
  454.             'titulo_pagina' => 'Editar Proveedor'
  455.         ]);
  456.     }
  457.     
  458.     /**
  459.      * @Route("/admin/proveedores/eliminar/{id}", name="admin_proveedor_delete", methods={"POST"})
  460.      */
  461.     public function eliminarProveedor(User $proveedorEntityManagerInterface $entityManager): Response
  462.     {
  463.         // Verificar si tiene citas
  464.         $citasCount $entityManager->getRepository(Appointment::class)
  465.             ->createQueryBuilder('a')
  466.             ->select('COUNT(a.id)')
  467.             ->where('a.patient = :patient')
  468.             ->setParameter('patient'$proveedor)
  469.             ->getQuery()
  470.             ->getSingleScalarResult();
  471.         
  472.         try {
  473.             // Si tiene citas, eliminarlas primero
  474.             if ($citasCount 0) {
  475.                 $appointments $entityManager->getRepository(Appointment::class)
  476.                     ->createQueryBuilder('a')
  477.                     ->where('a.patient = :patient')
  478.                     ->setParameter('patient'$proveedor)
  479.                     ->getQuery()
  480.                     ->getResult();
  481.                 
  482.                 foreach ($appointments as $appointment) {
  483.                     $entityManager->remove($appointment);
  484.                 }
  485.             }
  486.             
  487.           // Buscar todos los proveedores que tienen a este proveedor asignado
  488.             $providers $entityManager->getRepository(User::class)
  489.                 ->createQueryBuilder('u')
  490.                 ->innerJoin('u.patients''p')
  491.                 ->where('p = :patient')
  492.                 ->setParameter('patient'$proveedor)
  493.                 ->getQuery()
  494.                 ->getResult();
  495.             // Remover al proveedor de la lista de proveedors de cada proveedor
  496.             foreach ($providers as $provider) {
  497.                 $provider->removePatient($proveedor); // Necesitas este método en tu entidad User
  498.             }
  499.             // Finalmente eliminar el usuario
  500.             $entityManager->remove($proveedor);
  501.             $entityManager->flush();
  502.             
  503.             if ($citasCount 0) {
  504.                 $this->addFlash('warning'"Proveedor eliminado junto con {$citasCount} cita(s) asociada(s)");
  505.             } else {
  506.                 $this->addFlash('success''Proveedor eliminado correctamente');
  507.             }
  508.             
  509.         } catch (\Exception $e) {
  510.             $this->addFlash('error''Error al eliminar el proveedor: ' $e->getMessage());
  511.         }
  512.         
  513.         return $this->redirectToRoute('admin_proveedores');
  514.     }
  515.     /*****************************************************************
  516.      * PACIENTES - PROVEEDOR
  517.      *****************************************************************/
  518.     /**
  519.      * @Route("/proveedor/pacientes/nuevo", name="provider_patient_new", methods={"GET", "POST"})
  520.      */
  521.     public function newPatient(Request $requestUserRepository $userRepositoryEntityManagerInterface $entityManager): Response
  522.     {
  523.         $this->denyAccessUnlessGranted('ROLE_PROVIDER');
  524.         
  525.         $user = new User();
  526.         $form $this->createForm(UserType::class, $user);
  527.         $form->handleRequest($request);
  528.         if ($form->isSubmitted() && $form->isValid()) {
  529.             
  530.             $randomPassword $this->generateRandomPassword();
  531.             $user->setPassword($this->passwordHasher->hashPassword($user$randomPassword));
  532.             
  533.             // Asignar rol de paciente por defecto
  534.             $user->setRoles(['ROLE_CLIENT']);
  535.             try {
  536.                 /** @var User $provider */
  537.                 $provider $this->getUser();
  538.                 $provider->addPatient($user);
  539.                 $entityManager->persist($provider);
  540.                 $userRepository->add($usertrue);
  541.                 $this->addFlash('success''Paciente creado correctamente.');
  542.                 return $this->redirectToRoute('provider_patients');
  543.             } catch (UniqueConstraintViolationException $e) {
  544.                 $this->addFlash('error''Ya existe una cuenta con este correo electrónico.');
  545.             }
  546.         }
  547.         return $this->render('provider/patients/form.html.twig', [
  548.             'user' => $user,
  549.             'form' => $form->createView(),
  550.             'modo' => 'new',
  551.             'seccion' => 'patients'
  552.         ]);
  553.     }
  554.     /**
  555.      * @Route("/proveedor/pacientes/editar/{id}", name="provider_patient_edit", methods={"GET", "POST"})
  556.      */
  557.     public function editPatient(Request $requestUser $userUserRepository $userRepository): Response
  558.     {
  559.         $this->denyAccessUnlessGranted('ROLE_PROVIDER');
  560.         
  561.         /** @var User $provider */
  562.         $provider $this->getUser();
  563.         
  564.         // Verificar que el paciente pertenece a este proveedor
  565.         if (!$provider->getPatients()->contains($user)) {
  566.             throw $this->createAccessDeniedException('No tienes permisos para editar este paciente.');
  567.         }
  568.         $form $this->createForm(UserType::class, $user);
  569.         $form->handleRequest($request);
  570.         if ($form->isSubmitted() && $form->isValid()) {
  571.             try {
  572.                 $randomPassword $this->generateRandomPassword();
  573.                 $user->setPassword($this->passwordHasher->hashPassword($user$randomPassword));
  574.                 $userRepository->add($usertrue);
  575.                 $this->addFlash('success''Paciente actualizado correctamente.');
  576.                 return $this->redirectToRoute('provider_patients');
  577.             } catch (UniqueConstraintViolationException $e) {
  578.                 $this->addFlash('error''Ya existe una cuenta con este correo electrónico.');
  579.             } catch (\Exception $e) {
  580.                 $this->addFlash('error''Error al actualizar el paciente.');
  581.             }
  582.         }
  583.         return $this->render('provider/patients/form.html.twig', [
  584.             'user' => $user,
  585.             'form' => $form->createView(),
  586.             'modo' => 'edit',
  587.             'seccion' => 'patients'
  588.         ]);
  589.     }
  590.     /**
  591.      * @Route("/proveedor/pacientes/eliminar/{id}", name="provider_patient_delete", methods={"POST"})
  592.      */
  593.     public function deletePatient(Request $requestUser $patientEntityManagerInterface $entityManager): Response
  594.     {
  595.         $this->denyAccessUnlessGranted('ROLE_PROVIDER');
  596.         
  597.         /** @var User $provider */
  598.         $provider $this->getUser();
  599.         
  600.         // Verificar que el paciente pertenece a este proveedor
  601.         if (!$provider->getPatients()->contains($patient)) {
  602.             throw $this->createAccessDeniedException('No tienes permisos para eliminar este paciente.');
  603.         }
  604.         // Verificar el token CSRF para seguridad
  605.         if (!$this->isCsrfTokenValid('delete-patient-'.$patient->getId(), $request->request->get('_token'))) {
  606.             $this->addFlash('error''Token de seguridad inválido.');
  607.             return $this->redirectToRoute('provider_patients');
  608.         }
  609.         try {
  610.             // Eliminar el paciente
  611.             $entityManager->remove($patient);
  612.             $entityManager->flush();
  613.             $this->addFlash('success''Paciente eliminado correctamente.');
  614.         } catch (\Exception $e) {
  615.             $this->addFlash('error''Error al eliminar el paciente.');
  616.         }
  617.         return $this->redirectToRoute('provider_patients');
  618.     }
  619. }