<?php
namespace App\Controller;
use App\Entity\Configuration;
use App\Entity\Space;
use App\Entity\User;
use App\Entity\WidgetNotes;
use App\Entity\HtFile;
use App\MDS\AvexpressBundle\Entity\AveFiles;
use App\Form\WidgetNotesType;
use App\MDS\VenuesBundle\Entity\Reservation;
use App\MDS\VenuesBundle\Entity\ReservationLoungeDetails;
use App\MDS\VenuesBundle\Entity\ReservationLoungeSimple;
use App\MDS\VenuesBundle\Entity\ReservationVisit;
use App\Service\CalendarService;
use App\Service\UserNotificationService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Contracts\Translation\TranslatorInterface;
use Google_Client;
use Google_Service_Calendar;
use Doctrine\ORM\Query;
class HomeController extends AbstractController
{
private $googleCalendar;
private $translator;
private $userNotificationService;
private SessionInterface $session;
public function __construct(TranslatorInterface $translator, UserNotificationService $userNotificationService, SessionInterface $session)
{
$redirectUri = 'https://' . ($_SERVER['HTTP_HOST'] ?? '') . '/calendar/token';
$client = new Google_Client();
$client->setApplicationName('Google Calendar API');
$client->setClientId('YOUR_GOOGLE_CLIENT_ID');
$client->setClientSecret('YOUR_GOOGLE_CLIENT_SECRET');
$client->setRedirectUri($redirectUri);
$client->addScope(Google_Service_Calendar::CALENDAR);
$guzzle = new \GuzzleHttp\Client(['curl' => [CURLOPT_SSL_VERIFYPEER => false]]);
$client->setHttpClient($guzzle);
$this->googleCalendar = $client;
$this->translator = $translator;
$this->userNotificationService = $userNotificationService;
$this->session = $session;
}
/**
* Portal principal con los 3 accesos (ManteVenues, ManteCatering, ManteAV)
* @Route("/inicio", name="ruta_inicio")
*/
public function inicioAction(AuthenticationUtils $authenticationUtils, EntityManagerInterface $em): Response
{
$configuration = $em->getRepository(Configuration::class)->findOneBy([]);
return $this->render('login/login.html.twig', [
'last_username' => $authenticationUtils->getLastUsername(),
'error' => $authenticationUtils->getLastAuthenticationError(),
'configuration' => $configuration,
]);
}
/**
* @Route("/", name="homepage")
*/
public function index(EntityManagerInterface $em, Request $request): Response
{
$user = $this->getUser();
if (!$user) {
return $this->redirectToRoute('ruta_inicio');
}
// Recuperamos el tipo de acceso actual (Venues, Catering o AV) de la sesión
$accessType = $this->session->get('current_access_type') ?? 'venues';
$tz = new \DateTimeZone('Europe/Madrid');
$from = (new \DateTimeImmutable('today', $tz))->setTime(0, 0);
$to = $from->modify('today')->setTime(23, 59, 59);
// Si entra por venues
$agendaMix = [];
$formattedReservations = [];
$formattedVisits = [];
if ($accessType === 'venues') {
// 1. FILTRADO POR EQUIPO "LEGENDS VIEW"
$isLegendTeam = (strtoupper(trim($user->getTeam() ?? '')) === 'LEGENDS VIEW');
$lSpace = null;
if ($isLegendTeam) {
$lSpace = $em->getRepository(Space::class)->createQueryBuilder('s')
->where('s.name LIKE :n')->setParameter('n', '%LEGEND%')
->setMaxResults(1)->getQuery()->getOneOrNullResult();
}
/** --- LÓGICA Módulo VENUES (Reservas y Visitas) --- */
// RESERVAS: Agrupadas por ID y Tipo (para incluir Montajes/Desmontajes)
$qbR = $em->createQueryBuilder()
->select('r.id', 'r.title', 'r.dateStart', 'r.dateEnd', 'lounge.name as loungeName', 'rls.type')
->from(Reservation::class, 'r')
->leftJoin(ReservationLoungeSimple::class, 'rls', 'WITH', 'rls.idReservation = r.id')
->leftJoin(ReservationLoungeDetails::class, 'lounge', 'WITH', 'lounge.id = rls.idLounge')
->where('r.dateStart <= :to AND COALESCE(r.dateEnd, r.dateStart) >= :from')
->andWhere('r.status <> :deleted')
->setParameter('from', $from)
->setParameter('to', $from)
->setParameter('deleted', 'Deleted')
->orderBy('r.dateStart', 'ASC');
if ($isLegendTeam && $lSpace) {
$qbR->andWhere('lounge.space = :sid')->setParameter('sid', $lSpace->getId());
}
$rawRows = $qbR->getQuery()->getArrayResult();
$reservationsMap = [];
foreach ($rawRows as $row) {
$id = $row['id'];
$type = $row['type'];
$key = $id . ($type ? '_' . $type : '');
if (!isset($reservationsMap[$key])) {
$prefix = $type ? '[' . strtoupper($type) . '] ' : '';
$reservationsMap[$key] = [
'id' => $id,
'title' => $prefix . ($row['title'] ?? 'Reserva'),
'dateStart' => $row['dateStart'],
'rooms' => [],
'tipo' => 'RESERVA'
];
}
if ($row['loungeName'])
$reservationsMap[$key]['rooms'][] = $row['loungeName'];
}
$formattedReservations = [];
foreach ($reservationsMap as $res) {
$res['room'] = implode(', ', array_unique($res['rooms']));
$formattedReservations[] = $res;
}
// VISITAS: Filtradas y con búsqueda manual de sala (idLounge)
$qbV = $em->getRepository(ReservationVisit::class)->createQueryBuilder('v')
->where('v.dateStart <= :to AND COALESCE(v.dateEnd, v.dateStart) >= :from')
->setParameter('from', $from)
->setParameter('to', $to)
->orderBy('v.dateStart', 'ASC');
if ($isLegendTeam && $lSpace) {
$qbV->andWhere('v.space = :sid')->setParameter('sid', $lSpace->getId());
}
$visitEntities = $qbV->getQuery()->getResult();
$formattedVisits = [];
$loungeRepo = $em->getRepository(ReservationLoungeDetails::class);
foreach ($visitEntities as $visit) {
$lName = '-';
if ($visit->getIdLoungeDetails()) {
$lounge = $loungeRepo->find($visit->getIdLoungeDetails());
$lName = $lounge ? $lounge->getName() : '-';
}
$formattedVisits[] = [
'id' => $visit->getId(),
'title' => ($visit->getTitle() ?? 'Sin título'),
'dateStart' => $visit->getDateStart(),
'room' => $lName,
'tipo' => 'VISITA'
];
}
$agendaMix = array_merge($formattedReservations, $formattedVisits);
usort($agendaMix, function ($a, $b) {
return $a['dateStart'] <=> $b['dateStart'];
});
} else if ($accessType === 'catering') {
/** --- LÓGICA Módulo CATERING (Higo & Trigo + Montajes Venues) --- */
// 1. Obtenemos los eventos de Catering (Objetos HtFile)
$htFiles = $em->getRepository(HtFile::class)->createQueryBuilder('h')
->where('h.dateStart <= :to AND COALESCE(h.dateEnd, h.dateStart) >= :from')
->setParameter('from', $from)
->setParameter('to', $to)
->orderBy('h.dateStart', 'ASC')
->getQuery()->getResult();
$htEventsFormatted = [];
foreach ($htFiles as $ht) {
$htEventsFormatted[] = [
'id' => $ht->getId(),
'title' => '[CATERING] ' . ($ht->getTitle() ?? 'Sin título'),
'dateStart' => $ht->getDateStart(),
'room' => '', // Catering no tiene sala fija en su entidad habitualmente
'tipo' => 'RESERVA' // Usamos el mismo 'tipo' que en Venues para que el Twig lo pinte igual
];
}
// 2. Obtenemos Montajes/Desmontajes (exactamente igual que en Venues)
$qbM = $em->createQueryBuilder()
->select('r.id', 'r.title', 'r.dateStart', 'lounge.name as loungeName', 'rls.type')
->from(Reservation::class, 'r')
->leftJoin(ReservationLoungeSimple::class, 'rls', 'WITH', 'rls.idReservation = r.id')
->leftJoin(ReservationLoungeDetails::class, 'lounge', 'WITH', 'lounge.id = rls.idLounge')
->where('r.dateStart <= :to AND COALESCE(r.dateEnd, r.dateStart) >= :from')
->andWhere('rls.type IN (:types)')
->andWhere('r.status <> :deleted')
->setParameter('from', $from)
->setParameter('to', $from)
->setParameter('types', ['montaje', 'desmontaje'])
->setParameter('deleted', 'Deleted');
$venueRows = $qbM->getQuery()->getArrayResult();
$venueEventsFormatted = [];
foreach ($venueRows as $row) {
$venueEventsFormatted[] = [
'id' => $row['id'],
'title' => '[' . strtoupper($row['type'] ?? 'TRABAJO') . '] ' . ($row['title'] ?? 'Reserva'),
'dateStart' => $row['dateStart'],
'room' => $row['loungeName'] ?? '-',
'tipo' => 'RESERVA'
];
}
// 3. UNIFICACIÓN: Importante usar la misma variable que usa Venues
$agendaMix = array_merge($htEventsFormatted, $venueEventsFormatted);
usort($agendaMix, function ($a, $b) {
return $a['dateStart'] <=> $b['dateStart'];
});
// Para evitar errores en el render de Twig si espera estas variables:
$formattedReservations = $agendaMix;
$formattedVisits = [];
} else if ($accessType === 'av') {
/** --- LÓGICA Módulo AV (Audiovisuales) --- */
$formattedReservations = $em->getRepository(AveFiles::class)->createQueryBuilder('a')
->where('a.dateStart <= :to AND COALESCE(a.dateEnd, a.dateStart) >= :from')
->andWhere('a.status <> :deleted')
->setParameter('from', $from)->setParameter('to', $from)
->setParameter('deleted', 'Deleted')
->orderBy('a.dateStart', 'ASC')
->getQuery()->getResult();
}
// Checkeamos las notificaciones
$this->userNotificationService->checkRecentNotifications($user);
return $this->render('home/index.html.twig', [
'agenda' => $agendaMix,
'upcomingReservations' => $formattedReservations,
'upcomingVisits' => $formattedVisits,
'notifications' => $this->userNotificationService->getForModal($user)
]);
}
// src/Controller/HomeController.php
/**
* @Route("/calendar/global/visits", name="calendar_global_visits", methods={"GET"})
*/
public function globalVisits(Request $request, CalendarService $calendar, EntityManagerInterface $em): JsonResponse
{
$user = $this->getUser();
$spaceIds = null;
if ($user && strtoupper(trim($user->getTeam() ?? '')) === 'LEGENDS VIEW') {
// Buscamos todos los espacios cuyo nombre sea o contenga 'LEGENDS VIEW'
$spaces = $em->getRepository(Space::class)->createQueryBuilder('s')
->where('s.name LIKE :n')
->setParameter('n', '%ESPACIO LEGENDS%')
->getQuery()
->getResult();
if (!empty($spaces)) {
$spaceIds = array_map(fn($s) => $s->getId(), $spaces);
} else {
// Seguridad: Si no encuentra el espacio, ID inexistente para que no vea nada por error
$spaceIds = [99999];
}
}
$from = new \DateTime($request->query->get('start'));
$to = new \DateTime($request->query->get('end'));
return new JsonResponse($calendar->getVisitsForCalendar($spaceIds, null, $from, $to));
}
/**
* @Route("/calendar/global/reservations", name="calendar_global_reservations", methods={"GET"})
*/
public function globalReservations(Request $request, CalendarService $calendar, EntityManagerInterface $em): JsonResponse
{
$user = $this->getUser();
$spaceId = null;
if ($user && strtoupper(trim($user->getTeam() ?? '')) === 'LEGENDS VIEW') {
$lSpace = $em->getRepository(Space::class)->createQueryBuilder('s')
->where('s.name LIKE :n')
->setParameter('n', '%LEGEND%')
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
$spaceId = $lSpace?->getId();
}
$from = new \DateTime($request->query->get('start'));
$to = new \DateTime($request->query->get('end'));
return new JsonResponse($calendar->getReservationsForCalendar($spaceId, null, $from, $to));
}
/**
* @Route("/calendar/ht/events", name="calendar_ht_events", methods={"GET"})
*/
public function calendarHtEvents(Request $request, CalendarService $calendar): JsonResponse
{
$from = new \DateTimeImmutable($request->query->get('start', 'first day of this month'));
$to = new \DateTimeImmutable($request->query->get('end', 'last day of next month'));
return new JsonResponse($calendar->getHtEvents($from, $to));
}
/**
* @Route("/calendar/av/events", name="calendar_av_events", methods={"GET"})
*/
public function calendarAvEvents(Request $request, CalendarService $calendar): JsonResponse
{
$from = new \DateTimeImmutable($request->query->get('start', 'first day of this month'));
$to = new \DateTimeImmutable($request->query->get('end', 'last day of next month'));
return new JsonResponse($calendar->getAvEvents($from, $to));
}
/**
* @Route("/ChangeLanguage/{lang}", name="change_language")
*/
public function changeLanguage(Request $request, string $lang): Response
{
$this->translator->setLocale($lang);
$request->getSession()->set('_locale', $lang);
return $this->redirect($request->headers->get('referer'));
}
/**
* @Route("/calendar-full", name="calendar_full")
*/
public function calendarFull(Request $request): Response
{
$token = $request->request->get('token');
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository(User::class)->findOneByAccessKey($token);
if (!$user)
return $this->redirectToRoute('ruta_inicio');
$userId = $user->getId();
$wnotes = new WidgetNotes();
$wnotes->setDateAt(new \DateTime());
$form = $this->createForm(WidgetNotesType::class, $wnotes, [
'action' => $this->generateUrl('widget_notes_create'),
'method' => 'POST',
]);
return $this->render('home/calendar-fullscreen.html.twig', [
'form' => $form->createView(),
'user' => $userId,
'token' => $token,
]);
}
/**
* @Route("/external/calendar-reservation", name="calendar_external_reservation")
*/
public function externalCalendar(): Response
{
return $this->render('home/calendar-reservation.html.twig');
}
}