<?php
namespace App\Controller;
use App\Entity\Consultation;
use App\Form\SupportType;
use App\Repository\ConsultationRepository;
use App\Repository\PatientRepository;
use App\Repository\UserRepository;
use App\Security\AccessChecker as SecurityAccessChecker;
use App\Security\AccessChecker;
use App\Service\Subscription;
use App\Service\UserData;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\String\Slugger\SluggerInterface;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Generator\UrlGenerator;
class DashboardController extends AbstractController
{
private $doctrine;
private $subscription;
private $patientRepository;
private $accessChecker;
private $em;
public function __construct(ManagerRegistry $doctrine, Subscription $subscription, PatientRepository $patientRepository, EntityManagerInterface $em, SecurityAccessChecker $accessChecker)
{
$this->doctrine = $doctrine;
$this->subscription = $subscription;
$this->patientRepository = $patientRepository;
$this->em = $em;
$this->accessChecker = $accessChecker;
}
/**
* @Route("/", name="dashboard_index")
*/
public function index(UserRepository $userRepository, ConsultationRepository $consultationRepository): Response
{
if ($this->accessChecker->isPatient()) return $this->redirectToRoute("dashboard_index_patient");
if (!$this->accessChecker->isAdmin() && !$this->accessChecker->isSubscribed()) return $this->redirectToRoute("subscription");
if (!$this->accessChecker->isCustomer() && !$this->accessChecker->isAdmin()) return $this->redirectToRoute("dashboard_index_patient");
$now = new \DateTimeImmutable();
$start = $now->modify("last month");
$end = $now;
$datas = $this->forward('App\Controller\DashboardController::chart', [], ["start" => $start->format('Y-m-d'), "end" => $end->format('Y-m-d')]);
$datas = json_decode($datas->getContent(), true);
$actifsPatients = $datas ? end($datas['series'][0]["data"]) : 0;
$nouveauxPatients = $datas ? end($datas['series'][1]["data"]) : 0;
$inactifsPatients = $datas ? end($datas['series'][2]["data"]) : 0;
// dd($datas, $nouveauxPatients, $inactifsPatients, $actifsPatients);
return $this->render('dashboard/index.html.twig', [
'user' => $this->getUser(),
"actifsPatients" => $actifsPatients,
"inactifsPatients" => $inactifsPatients,
'nouveauxPatients' => $nouveauxPatients
]);
}
/**
* @Route("/suivi", name="dashboard_index_patient")
*/
public function patientIndex(UserRepository $userRepository, UserData $userData): Response
{
$user = $this->getUser();
if (!$this->accessChecker->isPatient() && $this->accessChecker->isCustomer() && !$this->accessChecker->isAdmin()) return $this->redirectToRoute("dashboard_index");
$chart = [
'series' => array_values($userData->getProfils($this->getUser())),
'categories' => array_keys($userData->getProfils($this->getUser())),
'colors' => ['#ffaa43', "#9fbf7e", "#ffff99", "#a6a6a6", "#cddebc", "#ffcb8b", "#d9d9d9", "#f3f3f3"],
'tcolors' => ['#ffb965', "#aec993", "#ffffc5", "#b5b5b5", "#dce8d0", "#ffdaab", "#e8e8e8", "#f3f3f3"],
'tdescriptions' => ['(protéines, lipides, glucides)', "(sport, hydratation, stress, sommeil...)", "(troubles et pathologies en lien avec la nutrition)", "(comportement alimentaire)", "(flore intestinale)", "(vitamines, minéraux et oligoéléments)", "(neurotransmetteurs)", ""]
];
return $this->render('dashboard/suivi.html.twig', [
'user' => $this->getUser(),
'chart' => $chart
]);
}
/**
* @Route("/dashboard/data2", name="dashboard_chart2")
*/
public function chart(Request $request, UserRepository $userRepository): Response
{
// if (!$this->accessChecker->isAdmin()) return $this->redirectToRoute("dashboard_index");
if (!$this->accessChecker->isSubscribed()) return $this->redirectToRoute("subscription");
$start = $request->request->get('start') ? $request->request->get('start') : $request->query->get('start');
$end = $request->request->get('end') ? $request->request->get('end') : $request->query->get('end');
$patients = $userRepository->getPatients($this->getUser());
$weeks = $this->getWeeksOfMonthWithStartAndEndDates($start, $end);
$result = array();
foreach ($weeks as $week) {
$weekStart = new \DateTimeImmutable($week["start"]);
$weekEnd = new \DateTimeImmutable($week["end"]);
$result[$week["label"]]["Patients actifs"] = 0;
$result[$week["label"]]["Nouveaux patients"] = 0;
$result[$week["label"]]["Patients archivés"] = 0;
if ($weekStart > new \DateTimeImmutable()) continue;
$patientsActifs = [];
foreach ($patients as $patient) {
$patientLastConsultation = $this->em->getRepository(Consultation::class)->findOneBy(["patient" => $patient], ["date" => "desc"]);
$dateCreated = $patient->getCreatedAt();
if ($patientLastConsultation) {
$dateLastConsultation = $patientLastConsultation->getDate();
} else {
$dateLastConsultation = NULL;
}
$checkNewUser = $this->daysBetweenDates($weekStart, $dateCreated);
if ($checkNewUser >= 0 && $checkNewUser < 7) {
$result[$week["label"]]["Nouveaux patients"] += 1;
if (!in_array($patient->getId(), $patientsActifs)) {
$result[$week["label"]]["Patients actifs"] += 1;
$patientsActifs[] = $patient->getId();
}
}
if ($dateLastConsultation) {
$checkArchiveUser = $this->daysBetweenDates($weekStart, $dateLastConsultation);
if ($checkArchiveUser >= 170 && $checkArchiveUser < 180) {
$result[$week["label"]]["Patients archivés"] += 1;
} elseif ($dateCreated <= $weekStart && !in_array($patient->getId(), $patientsActifs)) {
$result[$week["label"]]["Patients actifs"] += 1;
$patientsActifs[] = $patient->getId();
}
} elseif ($dateCreated <= $weekStart && !in_array($patient->getId(), $patientsActifs)) {
$result[$week["label"]]["Patients actifs"] += 1;
$patientsActifs[] = $patient->getId();
}
}
}
$series[0]["name"] = "Patients actifs";
$series[1]["name"] = "Nouveaux patients";
$series[2]["name"] = "Patients archivés";
$categories = array();
foreach ($result as $s => $r) {
$categories[] = $s;
$series[0]["data"][] = $r["Patients actifs"];
$series[1]["data"][] = $r["Nouveaux patients"];
$series[2]["data"][] = $r["Patients archivés"];
}
return $this->json(["series" => $series, "categories" => $categories]);
}
private function daysBetweenDates($datetime2, $datetime1)
{
$interval = $datetime1->diff($datetime2);
$sign = ($datetime1 > $datetime2) ? -1 : 1;
return $sign * $interval->days;
}
private function getWeeksOfMonthWithStartAndEndDates($start = null, $end = null)
{
// Définir les dates de début et de fin si elles ne sont pas fournies
$startDate = $start ? strtotime($start) : strtotime(date("Y-m-01"));
$endDate = $end ? strtotime($end) : strtotime(date("Y-m-t"));
// Vérification que $start est avant $end
if ($startDate > $endDate) {
throw new \InvalidArgumentException("La date de début doit être antérieure ou égale à la date de fin.");
}
$weeks = [];
// Boucle à travers les jours entre $startDate et $endDate
for ($currentDate = $startDate; $currentDate <= $endDate; $currentDate = strtotime('+1 day', $currentDate)) {
$week_number = date("W", $currentDate);
if (!array_key_exists($week_number, $weeks)) {
$weeks[$week_number] = [
'start' => $currentDate,
'end' => $currentDate
];
} else {
$weeks[$week_number]['end'] = $currentDate;
}
}
// Formater les dates et ajouter les labels
foreach ($weeks as $week_number => $dates) {
$weeks[$week_number]['start'] = date("Y-m-d", $dates['start']);
$weeks[$week_number]['end'] = date("Y-m-d", $dates['end']);
$weeks[$week_number]['label'] = "Semaine " . date("W", $dates['start']);
}
return $weeks;
}
/**
* @Route("/dashboard/data", name="dashboard_chart")
*/
public function chart2(Request $request, ConsultationRepository $consultationRepository, UserRepository $userRepository): Response
{
// if (!$this->accessChecker->isAdmin()) return $this->redirectToRoute("dashboard_index");
if (!$this->accessChecker->isSubscribed()) return $this->redirectToRoute("subscription");
$start = $request->request->get('start') ? $request->request->get('start') : $request->query->get('start');
$end = $request->request->get('end') ? $request->request->get('end') : $request->query->get('end');
$start = new \DateTimeImmutable($start);
$end = new \DateTimeImmutable($end);
$categories = [];
$series = [
[
"name" => "Nouveaux patients",
"data" => []
],
[
"name" => "Patients actifs",
"data" => []
],
[
"name" => "Patients archivés",
"data" => []
],
];
$currentDate = new \DateTime($start->format('Y-m-d'));
$nextDate = new \DateTime($start->format('Y-m-d'));
$i = 0;
while ($currentDate <= $end) {
$i++;
$nextDate->modify('+1 week');
$old_date = new \DateTimeImmutable("2020-01-01");
$patients = $userRepository->findNewPatientsBetweenDates($old_date, $nextDate, $this->getUser());
// nouveaux patients
$nouveauxPatients = $userRepository->findNewPatientsBetweenDates($currentDate, $nextDate, $this->getUser());
$series[0]["data"][] = count($nouveauxPatients);
// patients actifs/inactifs
$inactifsPatients = 0;
$actifsPatients = 0;
foreach ($patients as $patient) {
$_currentDate = new \DateTimeImmutable($currentDate->format('Y-m-d'));
$_nextDate = new \DateTimeImmutable($nextDate->format('Y-m-d'));
if ($_currentDate > new \DateTimeImmutable()) {
continue; // Ignore la semaine qui est dans le futur
}
$_start = $_currentDate->modify("-180 days");
$_end = $_nextDate->modify("-180 days");
$lastConsultations = array_merge(
$consultationRepository->findBetweenDates($_start, $_currentDate, [$patient]),
$consultationRepository->findBetweenDates($_end, $_nextDate, [$patient])
);
// Vérifie si le patient n'a pas de consultations dans les 180 derniers jours
if (empty($lastConsultations)) {
$inactifsPatients += 1;
} else {
$actifsPatients += 1;
}
}
$series[1]["data"][] = $actifsPatients;
$series[2]["data"][] = $inactifsPatients;
$categories[] = "Semaine " . $currentDate->format('W');
$currentDate = clone $nextDate;
}
return $this->json(["series" => $series, "categories" => $categories]);
}
private function formatDatas(array $consultations, array $patients, \DateTime $start, \DateTime $end): array
{
// Crée un tableau pour les résultats des consultations et des autres entités
$consultationsData = [];
$consultationsCategories = [];
$patientsData = [];
$patientCategories = [];
$archivedPatientsData = [];
$archivedPatientsCategories = [];
// Initialise la date en cours avec la date de début
$currentDate = clone $start;
// Tant que la date en cours est inférieure ou égale à la date de fin, on continue
while ($currentDate <= $end) {
$yearWeek = $currentDate->format('o-W'); // o: année ISO-8601, W: numéro de semaine ISO-8601
$consultationsCategories[] = $currentDate->format('W');
// Compte le nombre de consultations pour chaque semaine
if (!isset($consultationsData[$yearWeek])) {
$consultationsData[$yearWeek] = 0;
}
foreach ($consultations as $consultation) {
$consultationYearWeek = $consultation->getDate()->format('o-W');
if ($consultationYearWeek === $yearWeek) {
$consultationsData[$yearWeek]++;
}
}
// Compte le nombre de consultations créées pour chaque semaine
if (!isset($patientsData[$yearWeek])) {
$patientsData[$yearWeek] = 0;
}
if (!isset($archivedPatientsData[$yearWeek])) {
$archivedPatientsData[$yearWeek] = 0;
}
foreach ($patients as $patient) {
$entityYearWeek = $patient->getCreatedAt()->format('o-W');
$patientCategories[] = $patient->getCreatedAt()->format('W');
if ($entityYearWeek === $yearWeek) {
$patientsData[$yearWeek]++;
}
// compte les patients inactifs (dernière consultation > 180j par rapport a la semaine en cours)
$patientConsultations = $this->em->getRepository(Consultation::class)->findBy(["patient" => $patient], ["date" => "ASC"]);
$lastConsultation = null;
foreach ($patientConsultations as $patientConsultation) {
if (!$lastConsultation) $lastConsultation = $patientConsultation;
else {
if ($patientConsultation->getDate() > $lastConsultation->getDate() && $lastConsultation->getDate()->format("o-W") <= $yearWeek) {
$lastConsultation = $patientConsultation;
}
}
}
if ($lastConsultation) {
$consultationDate = $lastConsultation->getDate();
$consultation180DaysAfter = (clone $consultationDate)->modify("+180 days")->format("o-W");
if ($consultation180DaysAfter === $yearWeek) {
if ($archivedPatientsData[$consultation180DaysAfter] >= 0) {
$archivedPatientsData[$consultation180DaysAfter]++;
$archivedPatientsCategories[] = $lastConsultation->getDate()->format('W');
}
}
}
}
// Passe à la semaine suivante
$currentDate->modify('+1 week');
}
// Retourne un tableau avec les résultats des consultations et des autres entités
return [[array_values($consultationsData), $consultationsCategories], [array_values($patientsData), $patientCategories], [array_values($archivedPatientsData), $archivedPatientsCategories]];
}
/**
* @Route("/support", name="support")
*/
public function support(Request $request, MailerInterface $mailer, UserRepository $userRepository)
{
$data = [];
$form = $this->createForm(SupportType::class, $data);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$datas = $request->request->all()['support'];
$message = $datas['message'];
$answer = $datas['answer'];
$email = $this->getUser()->getEmail();
$admins = $userRepository->findBy(array("medecin" => null));
$adminEmails = [];
// foreach ($admins as $a) {
// $adminEmails[] = $a->getEmail();
// }
$adminEmails[] = 'support@profil-diet.com';
$link = $this->generateUrl('user_index', [], UrlGeneratorInterface::ABSOLUTE_URL) . "?userId=" . $this->getUser()->getId();
$mail = (new Email())
->subject('Nouvelle demande du support technique')
->from(new Address($email))
->to(...$adminEmails)
->html($this->renderView('email/support.html.twig', ["user" => $this->getUser(), "message" => $message, "answer" => $answer, "link" => $link]));
$guideUrl = $this->generateUrl("aide", [], UrlGenerator::ABSOLUTE_URL);
$faqUrl = $this->generateUrl("faq", [], UrlGenerator::ABSOLUTE_URL);
$urls = array(
"faq" => $faqUrl,
"pdf" => $guideUrl
);
$answerMail = (new Email())
->subject('PROFIL-DIET : vous avez contacté le support technique')
->from(new Address($_ENV['MAILER_ADDRESS'], $_ENV['MAILER_NAME']))
->to(new Address($email))
->html($this->renderView('email/support_reponse.html.twig', ["user" => $this->getUser(), "urls" => $urls]));
$mailer->send($mail);
$mailer->send($answerMail);
$session = $request->getSession();
$session->getFlashBag()->add('success', "Nous avons bien reçu votre demande. Le support technique vous répondra sous 24h ouvrables. <br />
Vous pouvez aussi consulter notre <a class='text-decoration-underline color-inherit' href='" . $faqUrl . "'>FAQ</a> (Foire Aux Questions) ou le guide PDF (<a class='text-decoration-underline color-inherit' href='" . $guideUrl . "'>ici</a>).<br /><br />
À bientôt,<br />
La Team Profil-diet");
}
// Réponse AJAX
if ($form->isSubmitted() && !$form->isValid()) {
return new Response($this->json($form, Response::HTTP_BAD_REQUEST));
}
return $this->render('support/index.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @Route("/tutos", name="tutos")
*/
public function tutos(Request $request, MailerInterface $mailer, UserRepository $userRepository)
{
return $this->render('tutos/index.html.twig');
}
/**
* @Route("/aide", name="aide")
*/
public function help()
{
$filename = "guide-utilisation-profil-diet.pdf";
$dir = $this->getParameter('kernel.project_dir') . '/public/docs/';
$pdfPath = $dir . $filename;
if (!file_exists($pdfPath)) {
throw $this->createNotFoundException('Le fichier PDF demandé n\'existe pas.');
}
$response = new BinaryFileResponse($pdfPath);
$response->headers->set('Content-Type', 'application/pdf');
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, "Guide d'utilisation Profil-diet.pdf");
return $response;
}
/**
* @Route("/cgu", name="cgu")
*/
public function cgu(Request $request)
{
$filename = 'cgu.pdf';
$dir = $this->getParameter('kernel.project_dir') . '/public/uploads/documents/';
$pdf = file_get_contents($dir . $filename);
return new Response($pdf, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="file.pdf"'
]);
}
/**
* @Route("/rgpd", name="rgpd")
*/
public function rgpd(Request $request)
{
$filename = 'rgpd.pdf';
$dir = $this->getParameter('kernel.project_dir') . '/public/uploads/documents/';
$pdf = file_get_contents($dir . $filename);
return new Response($pdf, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="file.pdf"'
]);
}
}