src/Controller/HomeController.php line 75

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Configuration;
  4. use App\Entity\Space;
  5. use App\Entity\User;
  6. use App\Entity\WidgetNotes;
  7. use App\Entity\HtFile;
  8. use App\MDS\AvexpressBundle\Entity\AveFiles;
  9. use App\Form\WidgetNotesType;
  10. use App\MDS\VenuesBundle\Entity\Reservation;
  11. use App\MDS\VenuesBundle\Entity\ReservationLoungeDetails;
  12. use App\MDS\VenuesBundle\Entity\ReservationLoungeSimple;
  13. use App\MDS\VenuesBundle\Entity\ReservationVisit;
  14. use App\Service\CalendarService;
  15. use App\Service\UserNotificationService;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  18. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  19. use Symfony\Component\Routing\Annotation\Route;
  20. use Symfony\Component\HttpFoundation\Request;
  21. use Symfony\Component\HttpFoundation\Response;
  22. use Symfony\Component\HttpFoundation\Session\Session;
  23. use Symfony\Component\HttpFoundation\JsonResponse;
  24. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  25. use Symfony\Contracts\Translation\TranslatorInterface;
  26. use Google_Client;
  27. use Google_Service_Calendar;
  28. use Doctrine\ORM\Query;
  29. class HomeController extends AbstractController
  30. {
  31.     private $googleCalendar;
  32.     private $translator;
  33.     private $userNotificationService;
  34.     private SessionInterface $session;
  35.     public function __construct(TranslatorInterface $translatorUserNotificationService $userNotificationServiceSessionInterface $session)
  36.     {
  37.         $redirectUri 'https://' . ($_SERVER['HTTP_HOST'] ?? '') . '/calendar/token';
  38.         $client = new Google_Client();
  39.         $client->setApplicationName('Google Calendar API');
  40.         $client->setClientId('YOUR_GOOGLE_CLIENT_ID');
  41.         $client->setClientSecret('YOUR_GOOGLE_CLIENT_SECRET');
  42.         $client->setRedirectUri($redirectUri);
  43.         $client->addScope(Google_Service_Calendar::CALENDAR);
  44.         $guzzle = new \GuzzleHttp\Client(['curl' => [CURLOPT_SSL_VERIFYPEER => false]]);
  45.         $client->setHttpClient($guzzle);
  46.         $this->googleCalendar $client;
  47.         $this->translator $translator;
  48.         $this->userNotificationService $userNotificationService;
  49.         $this->session $session;
  50.     }
  51.     /**
  52.      * Portal principal con los 3 accesos (ManteVenues, ManteCatering, ManteAV)
  53.      * @Route("/inicio", name="ruta_inicio")
  54.      */
  55.     public function inicioAction(AuthenticationUtils $authenticationUtilsEntityManagerInterface $em): Response
  56.     {
  57.         $configuration $em->getRepository(Configuration::class)->findOneBy([]);
  58.         return $this->render('login/login.html.twig', [
  59.             'last_username' => $authenticationUtils->getLastUsername(),
  60.             'error' => $authenticationUtils->getLastAuthenticationError(),
  61.             'configuration' => $configuration,
  62.         ]);
  63.     }
  64.     /**
  65.      * @Route("/", name="homepage")
  66.      */
  67.     public function index(EntityManagerInterface $emRequest $request): Response
  68.     {
  69.         $user $this->getUser();
  70.         if (!$user) {
  71.             return $this->redirectToRoute('ruta_inicio');
  72.         }
  73.         // Recuperamos el tipo de acceso actual (Venues, Catering o AV) de la sesión
  74.         $accessType $this->session->get('current_access_type') ?? 'venues';
  75.         $tz = new \DateTimeZone('Europe/Madrid');
  76.         $from = (new \DateTimeImmutable('today'$tz))->setTime(00);
  77.         $to $from->modify('today')->setTime(235959);
  78.         // Si entra por venues
  79.         $agendaMix = [];
  80.         $formattedReservations = [];
  81.         $formattedVisits = [];
  82.         if ($accessType === 'venues') {
  83.             // 1. FILTRADO POR EQUIPO "LEGENDS VIEW"
  84.             $isLegendTeam = (strtoupper(trim($user->getTeam() ?? '')) === 'LEGENDS VIEW');
  85.             $lSpace null;
  86.             if ($isLegendTeam) {
  87.                 $lSpace $em->getRepository(Space::class)->createQueryBuilder('s')
  88.                     ->where('s.name LIKE :n')->setParameter('n''%LEGEND%')
  89.                     ->setMaxResults(1)->getQuery()->getOneOrNullResult();
  90.             }
  91.             /** --- LÓGICA Módulo VENUES (Reservas y Visitas) --- */
  92.             // RESERVAS: Agrupadas por ID y Tipo (para incluir Montajes/Desmontajes)
  93.             $qbR $em->createQueryBuilder()
  94.                 ->select('r.id''r.title''r.dateStart''r.dateEnd''lounge.name as loungeName''rls.type')
  95.                 ->from(Reservation::class, 'r')
  96.                 ->leftJoin(ReservationLoungeSimple::class, 'rls''WITH''rls.idReservation = r.id')
  97.                 ->leftJoin(ReservationLoungeDetails::class, 'lounge''WITH''lounge.id = rls.idLounge')
  98.                 ->where('r.dateStart <= :to AND COALESCE(r.dateEnd, r.dateStart) >= :from')
  99.                 ->andWhere('r.status <> :deleted')
  100.                 ->setParameter('from'$from)
  101.                 ->setParameter('to'$from)
  102.                 ->setParameter('deleted''Deleted')
  103.                 ->orderBy('r.dateStart''ASC');
  104.             if ($isLegendTeam && $lSpace) {
  105.                 $qbR->andWhere('lounge.space = :sid')->setParameter('sid'$lSpace->getId());
  106.             }
  107.             $rawRows $qbR->getQuery()->getArrayResult();
  108.             $reservationsMap = [];
  109.             foreach ($rawRows as $row) {
  110.                 $id $row['id'];
  111.                 $type $row['type'];
  112.                 $key $id . ($type '_' $type '');
  113.                 if (!isset($reservationsMap[$key])) {
  114.                     $prefix $type '[' strtoupper($type) . '] ' '';
  115.                     $reservationsMap[$key] = [
  116.                         'id' => $id,
  117.                         'title' => $prefix . ($row['title'] ?? 'Reserva'),
  118.                         'dateStart' => $row['dateStart'],
  119.                         'rooms' => [],
  120.                         'tipo' => 'RESERVA'
  121.                     ];
  122.                 }
  123.                 if ($row['loungeName'])
  124.                     $reservationsMap[$key]['rooms'][] = $row['loungeName'];
  125.             }
  126.             $formattedReservations = [];
  127.             foreach ($reservationsMap as $res) {
  128.                 $res['room'] = implode(', 'array_unique($res['rooms']));
  129.                 $formattedReservations[] = $res;
  130.             }
  131.             // VISITAS: Filtradas y con búsqueda manual de sala (idLounge)
  132.             $qbV $em->getRepository(ReservationVisit::class)->createQueryBuilder('v')
  133.                 ->where('v.dateStart <= :to AND COALESCE(v.dateEnd, v.dateStart) >= :from')
  134.                 ->setParameter('from'$from)
  135.                 ->setParameter('to'$to)
  136.                 ->orderBy('v.dateStart''ASC');
  137.             if ($isLegendTeam && $lSpace) {
  138.                 $qbV->andWhere('v.space = :sid')->setParameter('sid'$lSpace->getId());
  139.             }
  140.             $visitEntities $qbV->getQuery()->getResult();
  141.             $formattedVisits = [];
  142.             $loungeRepo $em->getRepository(ReservationLoungeDetails::class);
  143.             foreach ($visitEntities as $visit) {
  144.                 $lName '-';
  145.                 if ($visit->getIdLoungeDetails()) {
  146.                     $lounge $loungeRepo->find($visit->getIdLoungeDetails());
  147.                     $lName $lounge $lounge->getName() : '-';
  148.                 }
  149.                 $formattedVisits[] = [
  150.                     'id' => $visit->getId(),
  151.                     'title' => ($visit->getTitle() ?? 'Sin título'),
  152.                     'dateStart' => $visit->getDateStart(),
  153.                     'room' => $lName,
  154.                     'tipo' => 'VISITA'
  155.                 ];
  156.             }
  157.             $agendaMix array_merge($formattedReservations$formattedVisits);
  158.             usort($agendaMix, function ($a$b) {
  159.                 return $a['dateStart'] <=> $b['dateStart'];
  160.             });
  161.         } else if ($accessType === 'catering') {
  162.             /** --- LÓGICA Módulo CATERING (Higo & Trigo + Montajes Venues) --- */
  163.             // 1. Obtenemos los eventos de Catering (Objetos HtFile)
  164.             $htFiles $em->getRepository(HtFile::class)->createQueryBuilder('h')
  165.                 ->where('h.dateStart <= :to AND COALESCE(h.dateEnd, h.dateStart) >= :from')
  166.                 ->setParameter('from'$from)
  167.                 ->setParameter('to'$to)
  168.                 ->orderBy('h.dateStart''ASC')
  169.                 ->getQuery()->getResult();
  170.             $htEventsFormatted = [];
  171.             foreach ($htFiles as $ht) {
  172.                 $htEventsFormatted[] = [
  173.                     'id' => $ht->getId(),
  174.                     'title' => '[CATERING] ' . ($ht->getTitle() ?? 'Sin título'),
  175.                     'dateStart' => $ht->getDateStart(),
  176.                     'room' => ''// Catering no tiene sala fija en su entidad habitualmente
  177.                     'tipo' => 'RESERVA' // Usamos el mismo 'tipo' que en Venues para que el Twig lo pinte igual
  178.                 ];
  179.             }
  180.             // 2. Obtenemos Montajes/Desmontajes (exactamente igual que en Venues)
  181.             $qbM $em->createQueryBuilder()
  182.                 ->select('r.id''r.title''r.dateStart''lounge.name as loungeName''rls.type')
  183.                 ->from(Reservation::class, 'r')
  184.                 ->leftJoin(ReservationLoungeSimple::class, 'rls''WITH''rls.idReservation = r.id')
  185.                 ->leftJoin(ReservationLoungeDetails::class, 'lounge''WITH''lounge.id = rls.idLounge')
  186.                 ->where('r.dateStart <= :to AND COALESCE(r.dateEnd, r.dateStart) >= :from')
  187.                 ->andWhere('rls.type IN (:types)')
  188.                 ->andWhere('r.status <> :deleted')
  189.                 ->setParameter('from'$from)
  190.                 ->setParameter('to'$from)
  191.                 ->setParameter('types', ['montaje''desmontaje'])
  192.                 ->setParameter('deleted''Deleted');
  193.             $venueRows $qbM->getQuery()->getArrayResult();
  194.             $venueEventsFormatted = [];
  195.             foreach ($venueRows as $row) {
  196.                 $venueEventsFormatted[] = [
  197.                     'id' => $row['id'],
  198.                     'title' => '[' strtoupper($row['type'] ?? 'TRABAJO') . '] ' . ($row['title'] ?? 'Reserva'),
  199.                     'dateStart' => $row['dateStart'],
  200.                     'room' => $row['loungeName'] ?? '-',
  201.                     'tipo' => 'RESERVA'
  202.                 ];
  203.             }
  204.             // 3. UNIFICACIÓN: Importante usar la misma variable que usa Venues
  205.             $agendaMix array_merge($htEventsFormatted$venueEventsFormatted);
  206.             usort($agendaMix, function ($a$b) {
  207.                 return $a['dateStart'] <=> $b['dateStart'];
  208.             });
  209.             // Para evitar errores en el render de Twig si espera estas variables:
  210.             $formattedReservations $agendaMix;
  211.             $formattedVisits = [];
  212.         } else if ($accessType === 'av') {
  213.             /** --- LÓGICA Módulo AV (Audiovisuales) --- */
  214.             $formattedReservations $em->getRepository(AveFiles::class)->createQueryBuilder('a')
  215.                 ->where('a.dateStart <= :to AND COALESCE(a.dateEnd, a.dateStart) >= :from')
  216.                 ->andWhere('a.status <> :deleted')
  217.                 ->setParameter('from'$from)->setParameter('to'$from)
  218.                 ->setParameter('deleted''Deleted')
  219.                 ->orderBy('a.dateStart''ASC')
  220.                 ->getQuery()->getResult();
  221.         }
  222.         // Checkeamos las notificaciones
  223.         $this->userNotificationService->checkRecentNotifications($user);
  224.         return $this->render('home/index.html.twig', [
  225.             'agenda' => $agendaMix,
  226.             'upcomingReservations' => $formattedReservations,
  227.             'upcomingVisits' => $formattedVisits,
  228.             'notifications' => $this->userNotificationService->getForModal($user)
  229.         ]);
  230.     }
  231.     // src/Controller/HomeController.php
  232.     /**
  233.      * @Route("/calendar/global/visits", name="calendar_global_visits", methods={"GET"})
  234.      */
  235.     public function globalVisits(Request $requestCalendarService $calendarEntityManagerInterface $em): JsonResponse
  236.     {
  237.         $user $this->getUser();
  238.         $spaceIds null;
  239.         if ($user && strtoupper(trim($user->getTeam() ?? '')) === 'LEGENDS VIEW') {
  240.             // Buscamos todos los espacios cuyo nombre sea o contenga 'LEGENDS VIEW'
  241.             $spaces $em->getRepository(Space::class)->createQueryBuilder('s')
  242.                 ->where('s.name LIKE :n')
  243.                 ->setParameter('n''%ESPACIO LEGENDS%')
  244.                 ->getQuery()
  245.                 ->getResult();
  246.             if (!empty($spaces)) {
  247.                 $spaceIds array_map(fn($s) => $s->getId(), $spaces);
  248.             } else {
  249.                 // Seguridad: Si no encuentra el espacio, ID inexistente para que no vea nada por error
  250.                 $spaceIds = [99999];
  251.             }
  252.         }
  253.         $from = new \DateTime($request->query->get('start'));
  254.         $to = new \DateTime($request->query->get('end'));
  255.         return new JsonResponse($calendar->getVisitsForCalendar($spaceIdsnull$from$to));
  256.     }
  257.     /**
  258.      * @Route("/calendar/global/reservations", name="calendar_global_reservations", methods={"GET"})
  259.      */
  260.     public function globalReservations(Request $requestCalendarService $calendarEntityManagerInterface $em): JsonResponse
  261.     {
  262.         $user $this->getUser();
  263.         $spaceId null;
  264.         if ($user && strtoupper(trim($user->getTeam() ?? '')) === 'LEGENDS VIEW') {
  265.             $lSpace $em->getRepository(Space::class)->createQueryBuilder('s')
  266.                 ->where('s.name LIKE :n')
  267.                 ->setParameter('n''%LEGEND%')
  268.                 ->setMaxResults(1)
  269.                 ->getQuery()
  270.                 ->getOneOrNullResult();
  271.             $spaceId $lSpace?->getId();
  272.         }
  273.         $from = new \DateTime($request->query->get('start'));
  274.         $to = new \DateTime($request->query->get('end'));
  275.         return new JsonResponse($calendar->getReservationsForCalendar($spaceIdnull$from$to));
  276.     }
  277.     /**
  278.      * @Route("/calendar/ht/events", name="calendar_ht_events", methods={"GET"})
  279.      */
  280.     public function calendarHtEvents(Request $requestCalendarService $calendar): JsonResponse
  281.     {
  282.         $from = new \DateTimeImmutable($request->query->get('start''first day of this month'));
  283.         $to = new \DateTimeImmutable($request->query->get('end''last day of next month'));
  284.         return new JsonResponse($calendar->getHtEvents($from$to));
  285.     }
  286.     /**
  287.      * @Route("/calendar/av/events", name="calendar_av_events", methods={"GET"})
  288.      */
  289.     public function calendarAvEvents(Request $requestCalendarService $calendar): JsonResponse
  290.     {
  291.         $from = new \DateTimeImmutable($request->query->get('start''first day of this month'));
  292.         $to = new \DateTimeImmutable($request->query->get('end''last day of next month'));
  293.         return new JsonResponse($calendar->getAvEvents($from$to));
  294.     }
  295.     /**
  296.      * @Route("/ChangeLanguage/{lang}", name="change_language")
  297.      */
  298.     public function changeLanguage(Request $requeststring $lang): Response
  299.     {
  300.         $this->translator->setLocale($lang);
  301.         $request->getSession()->set('_locale'$lang);
  302.         return $this->redirect($request->headers->get('referer'));
  303.     }
  304.     /**
  305.      * @Route("/calendar-full", name="calendar_full")
  306.      */
  307.     public function calendarFull(Request $request): Response
  308.     {
  309.         $token $request->request->get('token');
  310.         $em $this->getDoctrine()->getManager();
  311.         $user $em->getRepository(User::class)->findOneByAccessKey($token);
  312.         if (!$user)
  313.             return $this->redirectToRoute('ruta_inicio');
  314.         $userId $user->getId();
  315.         $wnotes = new WidgetNotes();
  316.         $wnotes->setDateAt(new \DateTime());
  317.         $form $this->createForm(WidgetNotesType::class, $wnotes, [
  318.             'action' => $this->generateUrl('widget_notes_create'),
  319.             'method' => 'POST',
  320.         ]);
  321.         return $this->render('home/calendar-fullscreen.html.twig', [
  322.             'form' => $form->createView(),
  323.             'user' => $userId,
  324.             'token' => $token,
  325.         ]);
  326.     }
  327.     /**
  328.      * @Route("/external/calendar-reservation", name="calendar_external_reservation")
  329.      */
  330.     public function externalCalendar(): Response
  331.     {
  332.         return $this->render('home/calendar-reservation.html.twig');
  333.     }
  334. }