<?php
namespace App\EventSubscriber;
use App\Entity\Booking;
use App\Entity\BookingEvent;
use App\Entity\BookingVisitReport;
use App\Repository\BookingEventRepository;
use App\Repository\BookingRepository;
use App\Repository\BookingVisitReportRepository;
use CalendarBundle\CalendarEvents;
use CalendarBundle\Entity\Event;
use CalendarBundle\Event\CalendarEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
class CalendarSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly BookingRepository $bookingRepository,
private readonly BookingVisitReportRepository $bookingVisitReportRepository,
private readonly BookingEventRepository $bookingEventRepository,
private readonly UrlGeneratorInterface $router,
private readonly Security $security
)
{
}
public static function getSubscribedEvents()
{
return [
CalendarEvents::SET_DATA => 'onCalendarSetData',
];
}
// Cette méthode est appelée pour configurer les données du calendrier.
public function onCalendarSetData(CalendarEvent $calendar): void
{
$filters = $calendar->getFilters();
// dump($filters['eventTypes']);
// SI on a les droits de voir les événements et les rapports de visite
if ($this->security->isGranted('ROLE_VISIT_REPORT')) {
// Vérifiez si le filtre pour les rapports de visite est activé
if ($this->security->isGranted('ROLE_COMMERCIAL') || !$filters || in_array('rv', $filters['eventTypes'] ?? [], true)) {
$this->getVisitReports($calendar);
}
}
// Vérifiez si le filtre pour les événements et séminaires est activé
if ($this->security->isGranted('ROLE_COMMERCIAL') || !$filters || in_array('ev', $filters['eventTypes'] ?? [], true)) {
$this->getBookingEvents($calendar);
}
}
/**
* @param CalendarEvent $calendar
* @return void
*/
protected function getVisitReports(CalendarEvent $calendar): void
{
$user = $this->security->getUser();
if (!$user) {
return;
}
$start = $calendar->getStart()->format('Y-m-d H:i:s');
$end = $calendar->getEnd()->format('Y-m-d H:i:s');
// Récupérer les filtres depuis l'objet CalendarEvent
$filters = $calendar->getFilters();
$queryBuilder = $this->bookingVisitReportRepository
->createQueryBuilder('booking')
->where('booking.beginAt BETWEEN :start and :end OR booking.endAt BETWEEN :start and :end')
->setParameter('start', $start)
->setParameter('end', $end)
;
// Comme les commerciaux ont pas (encore) le filtres,
if (!$user->hasRole('ROLE_COMMERCIAL')) {
// Vérifier si le filtre commercialIds est défini
if (isset($filters['commercialIds'])) {
// Si le tableau commercialIds est vide, ne retourner aucun événement
if (empty($filters['commercialIds'])) {
return;
}
$queryBuilder->andWhere('booking.owner IN (:commercials)')
->setParameter('commercials', $filters['commercialIds'])
;
}
}
// La gestion des rôles doit être explicite et claire.
if ($user->hasRole('ROLE_EMPLOYEE')) {
// Si on a un role EMPLOYEE, on renvoie les rapports de visite de tous le monde
$queryBuilder->leftJoin('booking.visitReport', 'visitReport');
} // Si on a un role commercial, on renvoie les rapports de visite qui lui sont liés
elseif ($user->hasRole('ROLE_COMMERCIAL')) {
// $queryBuilder->andWhere('booking.owner = :user')
$queryBuilder->leftJoin('booking.visitReport', 'visitReport')
->andWhere('booking.owner = :user OR visitReport.visitedBy = :user')
->setParameter('user', $user)
;
}
// Exécution de la requête et obtention des résultats.
$bookings = $queryBuilder->getQuery()->getResult();
// Parcours de chaque réservation pour créer et configurer un événement de calendrier correspondant.
/** @var BookingVisitReport $booking */
foreach ($bookings as $booking) {
// Vérification de l'existence d'un rapport de visite pour cette réservation.
if (null === $visitReport = $booking->getVisitReport()) {
continue; // Passer à la réservation suivante si aucun rapport de visite n'est associé.
}
// Création d'un nouvel événement avec le titre et les dates de début et de fin de la réservation.
$bookingEvent = new Event(
$booking->getTitle(),
$booking->getBeginAt(),
$booking->getEndAt(), // Si pas de date de fin, un événement sur toute la journée est créé.
null,
);
// Ajout de la mention "(RDV)" au titre de l'événement.
// Gestion du titre de l'événement en fonction du rôle.
$eventTitlePrefix = "";
switch ($booking->getVisitReport()?->getBooking()?->getMethod()?->getSlug()) {
case BookingVisitReport::VISIT_TYPE_PHYSICAL:
$eventTitlePrefix = '(RP) ';
break;
case BookingVisitReport::VISIT_TYPE_TELEPHONE:
$eventTitlePrefix = '(RT) ';
break;
case BookingVisitReport::VISIT_TYPE_VISIO:
$eventTitlePrefix = '(RV) ';
break;
}
$bookingEvent->setOptions(
[
'className' => 'visitReportEvent',
'backgroundColor' => 'white',
]);
// Gestion du titre de l'événement en fonction du rôle.
if ($user->hasRole('ROLE_EMPLOYEE')) {
$bookingEvent->setTitle($eventTitlePrefix . $booking->getVisitReport()->getVisitedBy()?->getFullName());
} else {
$bookingEvent->setTitle($eventTitlePrefix . $booking->getVisitReport()->getPrescriber()?->getFullName());
}
if (!$visitReport->isApproved()) {
if ($visitReport->isIsReadyForValidation()) {
// Événements non validés mais prêts pour la validation.
$bookingEvent->setOptions(
[
'className' => 'visitReportEvent',
'backgroundColor' => 'orange',
]);
} else {
// Événements ni prêts pour la validation ni validés (marqués comme temporaires).
$bookingEvent->setOptions(
[
'className' => 'visitReportEvent',
'backgroundColor' => 'yellow',
]);
$bookingEvent->setTitle($bookingEvent->getTitle());
}
} elseif ($visitReport->isIsReadyForValidation() && $visitReport->isApproved()) {
// Événements prêts pour la validation et déjà validés.
// Aucune option supplémentaire n'est définie, on affiche seulement le titre.
}
if ($visitReport->getBooking()?->isIsCancelled()) {
// Événements annulés.
$bookingEvent->setOptions(
[
'className' => 'visitReportEvent cancelled-booking',
'backgroundColor' => 'red',
]);
}
$bookingEvent->addOption(
'url',
$this->router->generate('app_booking_visit_report_edit', [
'id' => $booking->getId(),
])
);
$bookingEvent->addOption(
'object', $booking->getTitle(),
);
// Ajout de l'événement configuré au calendrier.
$calendar->addEvent($bookingEvent);
}
}
protected function getBookingEvents(CalendarEvent $calendar): void
{
$user = $this->security->getUser();
if (!$user) {
return;
}
$start = $calendar->getStart()->format('Y-m-d H:i:s');
$end = $calendar->getEnd()->format('Y-m-d H:i:s');
// Récupérer les filtres depuis l'objet CalendarEvent
$filters = $calendar->getFilters();
$queryBuilder = $this->bookingEventRepository
->createQueryBuilder('booking')
->where('booking.beginAt BETWEEN :start and :end OR booking.endAt BETWEEN :start and :end')
->setParameter('start', $start)
->setParameter('end', $end)
;
// Exécution de la requête et obtention des résultats.
$bookings = $queryBuilder->getQuery()->getResult();
// Parcours de chaque réservation pour créer et configurer un événement de calendrier correspondant.
/** @var BookingEvent $booking */
foreach ($bookings as $booking) {
// Vérifier si l'utilisateur courant est le propriétaire ou fait partie des utilisateurs autorisés
if ($booking->getOwner() === $user ||
$booking->getUsers()->contains($user) ||
$booking->getAllowedEmployees()->contains($user) ||
$booking->getAllowedCommercials()->contains($user)) {
// Création d'un nouvel événement avec le titre et les dates de début et de fin de la réservation.
$bookingEvent = new Event(
$booking->getTitle(),
$booking->getBeginAt(),
$booking->getEndAt(), // Si pas de date de fin, un événement sur toute la journée est créé.
null,
);
$className = $booking->getEventCategory()?->getSlug() ?? '';
// Gestion de la pastille en fonction du RAF.
$backgroundColor = 'orange';
if ($booking->isIsClosed()) {
$backgroundColor = 'green';
}
// Configuration des options de l'événement...
$bookingEvent->setOptions(
[
'className' => "booking-event-" . $className,
'backgroundColor' => $backgroundColor, // Couleur de fond de l'événement
]);
$bookingEventDb = $this->bookingEventRepository->find($booking->getId());
if ($bookingEventDb) {
if ($bookingEventDb->getCity()) {
$bookingEvent->addOption(
'city', $bookingEventDb->getCity(),
);
}
}
if ($bookingEventDb->isIsCancelled()) {
$bookingEvent->setOptions(
[
'className' => "cancelled-booking "."booking-event-" . $className,
'backgroundColor' => 'red', // Couleur de la pastille
]);
}
$route = 'app_booking_event_show';
if ($user->hasRole('ROLE_BOOKING_EVENT')) {
$route = 'app_booking_event_edit';
}
$bookingEvent->addOption(
'url',
$this->router->generate($route, [
'id' => $booking->getId(),
])
);
$bookingEvent->addOption(
'object', $booking->getTitle(),
);
// Ajout de l'événement configuré au calendrier.
$calendar->addEvent($bookingEvent);
}
}
}
}