src/Controller/Athena/DefaultController.php line 634

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Athena;
  3. use App\Entity\Athena\Page;
  4. use App\Entity\Athena\User;
  5. use App\Entity\Athena\VideoTutorial;
  6. use App\Form\Athena\DeleteForm;
  7. use App\Service\Asclepios\ClinicService;
  8. use App\Service\Athena\ComingSoonLogoutService;
  9. use App\Service\Athena\ContextService;
  10. use App\Service\Athena\DatatableService;
  11. use App\Service\Athena\PageService;
  12. use App\Service\Athena\TranslationService;
  13. use App\Service\Hephaistos\DateService;
  14. use Doctrine\Persistence\ObjectRepository;
  15. use Exception;
  16. use ReflectionClass;
  17. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  18. use Symfony\Component\HttpFoundation\Cookie;
  19. use Symfony\Component\HttpFoundation\HeaderUtils;
  20. use Symfony\Component\HttpFoundation\JsonResponse;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\RequestStack;
  23. use Symfony\Component\HttpFoundation\Response;
  24. use Symfony\Component\HttpKernel\Profiler\Profiler;
  25. use Symfony\Component\Routing\Annotation\Route;
  26. use Symfony\Component\Security\Core\Security;
  27. use Symfony\Contracts\Translation\TranslatorInterface;
  28. class DefaultController extends AbstractController
  29. {
  30.     const DEFAULT_TEMPLATE 'Athena/index';
  31.     const TEMPLATE_EXTENSION '.html.twig';
  32.     const STATUS_MESSAGE 'message';
  33.     const STATUS_WARNING 'warning';
  34.     const STATUS_ERROR 'error';
  35.     const STATUS_EXCEPTION 'exception';
  36.     const TAG_BREADCRUMB 'a-breadcrumb';
  37.     const TAG_BUTTONS 'a-buttons';
  38.     const TAG_JAVASCRIPT 'a-javascript';
  39.     const TAG_KEEP_MODAL_OPENED 'a-keep-modal-opened';
  40.     const TAG_MAIN 'a-main';
  41.     const TAG_MAIN_OVERTITLE 'a-main-overtitle';
  42.     const TAG_MAIN_SUBTITLE 'a-main-subtitle';
  43.     const TAG_MAIN_TITLE 'a-main-title';
  44.     const TAG_MODAL_TITLE 'a-modal-title';
  45.     const TAG_MODAL_CONTENT 'a-modal-content';
  46.     const TAG_MODAL_CLOSABLE 'a-modal-closable';
  47.     const TAG_ERROR_TITLE 'a-error-title';
  48.     const TAG_ERROR_CONTENT 'a-error-content';
  49.     const TAG_PREVENT_URL_UPDATE 'a-prevent-url-update';
  50.     const TAG_REDIRECT 'a-redirect';
  51.     const TAG_REDIRECT_WITHOUT_LOADER 'a-redirect-without-loader';
  52.     const TAG_REDRAW_BRICK_ID 'a-redraw-brick-id';
  53.     const TAG_REDRAW_BRICK_DATAS 'a-redraw-brick-datas';
  54.     const TAG_RELOAD_IFRAME 'a-reload-iframe';
  55.     const TAG_SET_VALUE 'a-set-value';
  56.     const TAG_STATUS 'a-status';
  57.     const TAG_TARGET_BLANK 'a-target-blank';
  58.     const TAG_FORM_BLANK 'a-form-blank';
  59.     const TAG_FORM_BLANK_DATAS 'a-form-blank-datas';
  60.     const TAG_FUNCTION_ON_LOAD 'a-function-on-load';
  61.     const TAG_SCROLL_TO_TOP 'a-scroll-content-to-top';
  62.     const TAG_KEEP_SIDEBAR_MODAL_OPENED 'a-keep-sidebar-modal-opened';
  63.     const TAG_SIDEBAR_MODAL_TITLE 'a-sidebar-modal-title';
  64.     const TAG_SIDEBAR_MODAL_CONTENT 'a-sidebar-modal-content';
  65.     const TAG_HIDE_MAIN_TITLE 'a-hide-main-title';
  66.     const TAG_SIDEBAR_MODAL_ICON 'a-sidebar-modal-icon';
  67.     const TAG_ONBOARDING 'a-onboarding';
  68.     const TAG_SET_INNER_HTML 'a-set-inner-html';
  69.     const TAG_VIDEO_TUTORIAL 'a-video-tutorial';
  70.     protected array $args;
  71.     protected array $cookies;
  72.     protected ClinicService $clinicService;
  73.     protected ContextService $context;
  74.     protected DateService $dateService;
  75.     protected DatatableService $datatableService;
  76.     protected string $domain;
  77.     protected string $entityClass;
  78.     protected string $entityName;
  79.     protected string $file;
  80.     protected string $fileDisposition HeaderUtils::DISPOSITION_ATTACHMENT;
  81.     protected string $fileName;
  82.     protected bool $isJson;
  83.     protected array $otherData;
  84.     protected array $extractData;
  85.     protected PageService $pageService;
  86.     protected ?Request $request;
  87.     protected string $routePrefix;
  88.     protected ?Security $security;
  89.     protected string $template;
  90.     protected TranslationService $translationService;
  91.     protected TranslatorInterface $translator;
  92.     private ComingSoonLogoutService $comingSoonLogoutService;
  93.     private static array $messagesFromService;
  94.     public function __construct(
  95.         ClinicService           $clinicService,
  96.         DatatableService        $datatableService,
  97.         DateService             $dateService,
  98.         PageService             $pageService,
  99.         RequestStack            $requestStack,
  100.         Security                $security,
  101.         TranslationService      $translationService,
  102.         TranslatorInterface     $translator,
  103.         ContextService          $context,
  104.         ComingSoonLogoutService $comingSoonLogoutService
  105.     )
  106.     {
  107.         $this->comingSoonLogoutService $comingSoonLogoutService;
  108.         if ($this->comingSoonLogoutService->isComingSoon()) {
  109.             $this->comingSoonLogoutService->logoutAllConnectedUser();
  110.         }
  111.         $this->args = [];
  112.         $this->cookies = [];
  113.         $this->clinicService $clinicService;
  114.         $this->dateService $dateService;
  115.         $this->datatableService $datatableService;
  116.         $this->file '';
  117.         $this->fileName '';
  118.         $this->otherData = [];
  119.         $this->extractData = [];
  120.         $this->isJson false;
  121.         $this->pageService $pageService;
  122.         $this->request $requestStack->getCurrentRequest();
  123.         $this->security $security;
  124.         $this->template self::DEFAULT_TEMPLATE;
  125.         $this->translationService $translationService;
  126.         $this->translator $translator;
  127.         self::$messagesFromService = [];
  128.         $reflection = new ReflectionClass(get_class($this));
  129.         foreach ($reflection->getAttributes() as $attribute) {
  130.             if (isset($attribute->getArguments()['name'])) {
  131.                 if ('Symfony\Component\Routing\Annotation\Route' === $attribute->getName()) {
  132.                     $this->routePrefix $attribute->getArguments()['name'];
  133.                 } else {
  134.                     switch ($attribute->getArguments()[0]) {
  135.                         case 'entity':
  136.                             $this->entityClass $attribute->getArguments()['name'];
  137.                             $tabEntity explode('\\'$this->entityClass);
  138.                             $this->entityName end($tabEntity);
  139.                             break;
  140.                         case 'domain':
  141.                             $this->domain $attribute->getArguments()['name'];
  142.                             break;
  143.                     }
  144.                 }
  145.             }
  146.         }
  147.         $this->context $context;
  148.     }
  149.     public function getResponse(): Response
  150.     {
  151.         $clinicDatas = ['sign' => null];
  152.         if ($clinic $this->getContext()->get('clinic')) {
  153.             $clinicDatas = [
  154.                 'sign' => $clinic->getSign(),
  155.                 'slug' => $this->getParameter('prestashop.url') . '/mon-veterinaire/' $clinic->getSlug(),
  156.                 'hasShop' => $clinic->getClubvetShop(),
  157.                 'hasWebSite' => $clinic->getClubvetWeb(),
  158.                 'clinicSiteUrl' => $clinic->getClubvetWeb() ? $this->clinicService->getClinicDomain($clinic) : '',
  159.                 'hasAdvPhoneNumber' => $this->clinicService->getClinicSalesman($clinic)?->getAdvPhoneNumber() ?? false,
  160.                 'isVeterinary' =>
  161.                     in_array('ROLE_VETERINARY'$this->getUser()->getRoles()) ||
  162.                     in_array('ROLE_ASV_LIGHT'$this->getUser()->getRoles()) ||
  163.                     in_array('ROLE_ASV'$this->getUser()->getRoles()),
  164.                 'hasBusinessSoftware' => $this->security->isGranted('IS_IMPERSONATOR') ? true : (bool)$clinic->getBusinessSoftware(),
  165.             ];
  166.         }
  167.         foreach (self::$messagesFromService as $message) {
  168.             $this->addStatus($message['text'], $message['severity'], $message['domain']);
  169.         }
  170.         if ($this->file && $this->fileName) {
  171.             $response = new Response($this->file);
  172.             $response->headers->set('Content-Disposition'HeaderUtils::makeDisposition(
  173.                 $this->fileDisposition,
  174.                 $this->fileNamepreg_replace('#^.*\.#'md5($this->fileName) . '.'$this->fileName)
  175.             ));
  176.             if ($this->fileDisposition === HeaderUtils::DISPOSITION_INLINE) {
  177.                 $fileName explode('.'$this->fileName);
  178.                 $response->headers->set('Content-Type''application/' array_pop($fileName));
  179.             }
  180.             return $response;
  181.         }
  182.         if ('fetch' === $this->request->headers->get('A-Sending-Method') || $this->isJson) {
  183.             if (
  184.                 str_contains($this->request->getRequestUri(), 'admin/clinic') &&
  185.                 str_contains($this->request->getRequestUri(), 'choose') &&
  186.                 !str_contains($this->request->getRequestUri(), 'choosePricePlan')
  187.             ) {
  188.                 $this->setContent('searchClinicsUrl'$this->generateUrl('adminClinicSearchClinics'));
  189.                 $this->setContent('a-switch-clinic'$clinicDatas);
  190.             }
  191.             if ($page $this->getRepository(Page::class)->findOneByPath($this->request->getRequestUri())) {
  192.                 $breadcrumb = [];
  193.                 while ($page) {
  194.                     $breadcrumb[] = ['link' => $page->getPath(), 'label' => $this->translationService->getContent($page'label')];
  195.                     $page $page->getParent();
  196.                 }
  197.                 $this->args[self::TAG_BREADCRUMB] = array_reverse($breadcrumb);
  198.             }
  199.             if ($this->security->getUser() === null) {
  200.                 $response $this->json(['a-reload' => true]);
  201.             } else {
  202.                 if ('true' === $this->request->headers->get('A-Fetching-Menu')) {
  203.                     $this->setContent('a-pages'$this->pageService->getPages());
  204.                 }
  205.                 if (self::DEFAULT_TEMPLATE != $this->template) {
  206.                     $this->args[self::TAG_MAIN] = $this->renderView(
  207.                         $this->template self::TEMPLATE_EXTENSION,
  208.                         $this->args
  209.                     );
  210.                 }
  211.                 if (
  212.                     empty($this->args[self::TAG_PREVENT_URL_UPDATE])
  213.                     && !empty($this->args[self::TAG_MAIN])
  214.                 ) {
  215.                     // display video tutorial, if any, in header
  216.                     $this->args[self::TAG_VIDEO_TUTORIAL] = $this->getVideoTutorialUrl();
  217.                 }
  218.                 if ($clinic
  219.                     && $clinic->getClubvetShop()
  220.                     && empty($this->args[self::TAG_MODAL_CONTENT])
  221.                     && empty($this->args[self::TAG_REDIRECT])
  222.                     && empty($this->args[self::TAG_REDIRECT_WITHOUT_LOADER])
  223.                     && !$this->request->cookies->get('alertHolidaySummer2025')
  224.                 ) {
  225.                     $this->addCookie('alertHolidaySummer2025''1');
  226.                     if ($this->request->get('_route') !== 'adminAdministrationHolidayIndex') {
  227.                         $this->setModal(
  228.                             'Vous partez aussi en vacances ?',
  229.                             '
  230.                                 <p class="mb-1">N’oubliez pas d’activer le mode vacances directement depuis votre espace vétérinaire ClubVET Shop afin d’avertir vos clients de votre absence.</p>
  231.                                 <p class="mb-1">
  232.                                     <span class="font-bold">Bon à savoir</span> : les commandes d’abonnement de vos clients, prévues pendant la période de fermeture de la clinique, seront annulées.<br/>
  233.                                     Les clients sont informés par e-mail à deux reprises : une première fois lors de l’envoi de votre message de congés, puis une seconde fois lors de l’annulation automatique, 3 jours avant la date prévue de réception.
  234.                                 </p>
  235.                                 <p class="flex justify-between gap-2">
  236.                                     <a
  237.                                         href="https://xs4xg.mjt.lu/nl3/IrJhnnAzmvnKaFmRsULMRQ?m=AUAAAU7EgGAAAAAAAAAAAKpkxpMAAAAAF1AAAAAAAA27zwBmqMe-pZ-NByaTSG-YlD08x2njaAANpOw&b=1e897e7e&e=dfc0cc58&x=clFl3uxmAix1csWcfeNWGg"
  238.                                         target="_blank"
  239.                                         class="bg-secondary text-center text-white rounded-lg align-middle cursor-pointer inline-flex items-center justify-center min-h-10 px-3"
  240.                                     >
  241.                                         <span class="material-symbols-outlined flex justify-center mr-2">help</span>
  242.                                         Tutoriel
  243.                                     </a>
  244.                                     <a
  245.                                         href="' $this->generateUrl('adminAdministrationHolidayIndex') . '"
  246.                                         a-click="fetch"
  247.                                         a-modal="closer"
  248.                                         class="bg-secondary text-center text-white rounded-lg align-middle cursor-pointer inline-flex items-center justify-center min-h-10 px-3"
  249.                                     >
  250.                                         <span class="material-symbols-outlined flex justify-center mr-2">beach_access</span>
  251.                                         Activer le mode vacances
  252.                                     </a>
  253.                                 '
  254.                         );
  255.                     }
  256.                 }
  257.                 $response $this->json($this->args);
  258.             }
  259.         } else {
  260.             if ($user $this->security->getUser()) {
  261.                 $this->args['user'] = [
  262.                     'firstname' => $user->getFirstname(),
  263.                     'lastname' => $user->getLastname(),
  264.                     'avatar' => $user->getAvatar()?->getUrl(),
  265.                     'onboardingStep' => $user->getOnboardingStep(),
  266.                     'screenResolutions' => $user->getScreenResolutions(),
  267.                 ];
  268.             }
  269.             $this->setContent('searchClinicsUrl'$this->generateUrl('adminClinicSearchClinics'));
  270.             $this->setContent('a-switch-clinic'$clinicDatas);
  271.             $this->setContent('canEditVideoTutorial'$this->canEditVideoTutorial());
  272.             $response $this->render(
  273.                 $this->template self::TEMPLATE_EXTENSION,
  274.                 $this->args
  275.             );
  276.         }
  277.         if (count($this->cookies)) {
  278.             try {
  279.                 $expire $this->dateService->getDate(interval'P1Y');
  280.                 foreach ($this->cookies as $name => $value) {
  281.                     $response->headers->setCookie(new Cookie($name$value$expire));
  282.                 }
  283.             } catch (Exception $exception) {
  284.                 $this->addException($exception);
  285.             }
  286.         }
  287.         return $response;
  288.     }
  289.     public function setContent(string $keymixed $content, ?array $args null, ?string $domain null): self
  290.     {
  291.         $this->args[$key] = (is_null($args) ?
  292.             (is_string($content) ? $this->trans($content$domain) : $content) :
  293.             $this->renderView(
  294.                 $content self::TEMPLATE_EXTENSION,
  295.                 $args
  296.             )
  297.         );
  298.         return $this;
  299.     }
  300.     public function setMain(string $content, ?array $args null): self
  301.     {
  302.         return $this->setContent(self::TAG_MAIN$content$args);
  303.     }
  304.     public function setMainTitle(string $content, ?string $domain null): self
  305.     {
  306.         return $this->setContent(self::TAG_MAIN_TITLE$this->trans($content$domain));
  307.     }
  308.     public function hideMainTitle(): self
  309.     {
  310.         return $this->setContent(self::TAG_HIDE_MAIN_TITLEtrue);
  311.     }
  312.     public function setMainSubTitle(string $content, ?string $domain null): self
  313.     {
  314.         return $this->setContent(self::TAG_MAIN_SUBTITLE$this->trans($content$domain));
  315.     }
  316.     public function setMainOverTitle(string $content, ?string $domain null): self
  317.     {
  318.         return $this->setContent(self::TAG_MAIN_OVERTITLE$this->trans($content$domain));
  319.     }
  320.     public function setRedirect(string $url): self
  321.     {
  322.         return $this->setContent(self::TAG_REDIRECT$url);
  323.     }
  324.     public function setRedirectWithoutLoader(string $url): self
  325.     {
  326.         return $this->setContent(self::TAG_REDIRECT_WITHOUT_LOADER$url);
  327.     }
  328.     public function setModal(string $titlestring $content, ?array $args null, ?string $domain null): self
  329.     {
  330.         return $this
  331.             ->setContent(self::TAG_MODAL_TITLE$this->trans($title$domain))
  332.             ->setContent(self::TAG_MODAL_CONTENT$content$args)
  333.             ->setContent(self::TAG_MODAL_CLOSABLEtrue);
  334.     }
  335.     public function setUnclosableModal(string $titlestring $content, ?array $args null, ?string $domain null): self
  336.     {
  337.         return $this
  338.             ->setContent(self::TAG_MODAL_TITLE$this->trans($title$domain))
  339.             ->setContent(self::TAG_MODAL_CONTENT$content$args)
  340.             ->setContent(self::TAG_MODAL_CLOSABLEfalse);
  341.     }
  342.     public function setWaitingModal(string $filesstring $subjectstring $bodybool $plural false): self
  343.     {
  344.         return $this
  345.             ->addJS('Athena.programDeferredDeliveryCheck();')
  346.             ->setContent(self::TAG_MODAL_TITLE, ($plural 'Vos fichiers sont' 'Votre fichier est') . ' en cours de préparation')
  347.             ->setcontent(self::TAG_MODAL_CONTENT'Athena/DeferredDelivery/waitingModal', [
  348.                 'files' => $files,
  349.                 'plural' => $plural,
  350.                 'subject' => $subject,
  351.                 'body' => $body,
  352.             ])
  353.             ->setContent(self::TAG_MODAL_CLOSABLEfalse);
  354.     }
  355.     public function setSidebarModal(string $titlestring $contentstring $iconSb, ?array $args null, ?string $domain null): self
  356.     {
  357.         return $this
  358.             ->setContent(self::TAG_SIDEBAR_MODAL_TITLE$this->trans($title$domain))
  359.             ->setContent(self::TAG_SIDEBAR_MODAL_CONTENT$content$args)
  360.             ->setContent(self::TAG_SIDEBAR_MODAL_ICON$iconSb);
  361.     }
  362.     public function setError(string $titlestring $content, ?array $args null, ?string $domain null): self
  363.     {
  364.         return $this
  365.             ->setContent(self::TAG_ERROR_TITLE$this->trans($title$domain))
  366.             ->setContent(self::TAG_ERROR_CONTENT$content$args);
  367.     }
  368.     public function setTemplate(string $template): self
  369.     {
  370.         $this->template $template;
  371.         return $this;
  372.     }
  373.     public function setReloadIframe(): self
  374.     {
  375.         $this->args[self::TAG_RELOAD_IFRAME] = true;
  376.         return $this;
  377.     }
  378.     /**
  379.      * @param $key string|array
  380.      * @param $value ?string
  381.      * @return $this
  382.      */
  383.     public function setValue($key$value null): self
  384.     {
  385.         if (is_array($key)) {
  386.             $this->args[self::TAG_SET_VALUE] = json_encode($key);
  387.         } else {
  388.             $this->args[self::TAG_SET_VALUE] = json_encode(['key' => $key'value' => $value]);
  389.         }
  390.         return $this;
  391.     }
  392.     public function setInnerHTML(array $data): self
  393.     {
  394.         if (isset($this->args[self::TAG_SET_INNER_HTML])) {
  395.             $data array_merge(json_decode($this->args[self::TAG_SET_INNER_HTML], true), $data);
  396.         }
  397.         $this->args[self::TAG_SET_INNER_HTML] = json_encode($data);
  398.         return $this;
  399.     }
  400.     public function preventUrlUpdate(): self
  401.     {
  402.         $this->args[self::TAG_PREVENT_URL_UPDATE] = true;
  403.         return $this;
  404.     }
  405.     public function addCookie(string $namestring $value): self
  406.     {
  407.         $this->cookies[$name] = $value;
  408.         return $this;
  409.     }
  410.     public function addStatus(
  411.         string  $message,
  412.         string  $type self::STATUS_MESSAGE,
  413.         ?string $domain null
  414.     ): self
  415.     {
  416.         if (!isset($this->args[self::TAG_STATUS])) {
  417.             $this->args[self::TAG_STATUS] = [];
  418.         }
  419.         $this->args[self::TAG_STATUS][] = [
  420.             'text' => $this->trans($message$domain),
  421.             'severity' => $type,
  422.         ];
  423.         return $this;
  424.     }
  425.     public static function addStatusFromService(
  426.         string  $message,
  427.         string  $type self::STATUS_MESSAGE,
  428.         ?string $domain null
  429.     ): void
  430.     {
  431.         self::$messagesFromService[] = [
  432.             'text' => $message,
  433.             'severity' => $type,
  434.             'domain' => $domain,
  435.         ];
  436.     }
  437.     public function addButton(
  438.         string  $url,
  439.         string  $label,
  440.         string  $icon,
  441.         string  $class '',
  442.         ?string $domain null,
  443.         string  $wrapper '',
  444.         bool    $fetch true
  445.     ): self
  446.     {
  447.         if (!isset($this->args[self::TAG_BUTTONS])) {
  448.             $this->args[self::TAG_BUTTONS] = [];
  449.         }
  450.         $this->args[self::TAG_BUTTONS][] = [
  451.             'url' => $url,
  452.             'label' => $this->trans($label$domain),
  453.             'icon' => $icon,
  454.             'class' => $class,
  455.             'wrapper' => $wrapper,
  456.             'fetch' => $fetch,
  457.         ];
  458.         return $this;
  459.     }
  460.     public function addException(Exception $exception): self
  461.     {
  462.         return $this->setError('Exception'$exception->getMessage());
  463.     }
  464.     public function addJS(string $js): self
  465.     {
  466.         if (!isset($this->args[self::TAG_JAVASCRIPT])) {
  467.             $this->args[self::TAG_JAVASCRIPT] = '';
  468.         }
  469.         $this->args[self::TAG_JAVASCRIPT] .= $js;
  470.         return $this;
  471.     }
  472.     public function getRepository(string $class): ObjectRepository
  473.     {
  474.         return $this->getDoctrine()->getManager()->getRepository($class);
  475.     }
  476.     public function persist(): self
  477.     {
  478.         foreach (func_get_args() as $entity) {
  479.             $this->getDoctrine()->getManager()->persist($entity);
  480.         }
  481.         return $this;
  482.     }
  483.     public function remove(): self
  484.     {
  485.         foreach (func_get_args() as $entity) {
  486.             $this->getDoctrine()->getManager()->remove($entity);
  487.         }
  488.         return $this;
  489.     }
  490.     public function clear(): self
  491.     {
  492.         foreach (func_get_args() as $entity) {
  493.             $this->getDoctrine()->getManager()->clear($entity);
  494.         }
  495.         return $this;
  496.     }
  497.     public function detach(): self
  498.     {
  499.         foreach (func_get_args() as $entity) {
  500.             $this->getDoctrine()->getManager()->detach($entity);
  501.         }
  502.         return $this;
  503.     }
  504.     public function flush(): self
  505.     {
  506.         if (count(func_get_args())) {
  507.             foreach (func_get_args() as $entity) {
  508.                 $this->getDoctrine()->getManager()->flush($entity);
  509.             }
  510.         } else {
  511.             $this->getDoctrine()->getManager()->flush();
  512.         }
  513.         return $this;
  514.     }
  515.     public function trans(string $stringstring $domain null, array $args = [], ?string $locale null): string
  516.     {
  517.         return $this->translator->trans($string$args$domain$locale);
  518.     }
  519.     public function keepModalOpened(): self
  520.     {
  521.         $this->args[self::TAG_KEEP_MODAL_OPENED] = true;
  522.         return $this;
  523.     }
  524.     public function keepSideBarModalOpened(): self
  525.     {
  526.         $this->args[self::TAG_KEEP_SIDEBAR_MODAL_OPENED] = true;
  527.         return $this;
  528.     }
  529.     public function scrollToTop(): self
  530.     {
  531.         $this->args[self::TAG_SCROLL_TO_TOP] = true;
  532.         return $this;
  533.     }
  534.     public function openOnboarding($datas): self
  535.     {
  536.         $this->args[self::TAG_ONBOARDING] = json_encode($datas);
  537.         return $this;
  538.     }
  539.     public function redirectByFetch(string $url): Response
  540.     {
  541.         return $this
  542.             ->setMain(
  543.                 'Athena/redirect',
  544.                 [
  545.                     'url' => $url,
  546.                 ]
  547.             )
  548.             ->getResponse();
  549.     }
  550.     public function redirectToRouteByFetch(string $route, array $parameters = []): Response
  551.     {
  552.         return $this->redirectByFetch($this->generateUrl($route$parameters));
  553.     }
  554.     #[Route('/'name'home')]
  555.     public function home(): Response
  556.     {
  557.         return $this->redirectToRoute('admin');
  558.     }
  559.     #[Route('/admin'name'admin')]
  560.     public function admin(): Response
  561.     {
  562.         return $this->getResponse();
  563.     }
  564.     #[Route('/health_check'name'healthCheck')]
  565.     public function healthCheck(?Profiler $profiler): Response
  566.     {
  567.         $profiler?->disable();
  568.         $return = [];
  569.         try {
  570.             if (!$this->getRepository(User::class)->find(1)) {
  571.                 throw new \Exception('Problème de connexion à la DB'1null);
  572.             }
  573.             $return['DB'] = 'OK';
  574.         } catch (\Exception $e) {
  575.             return new Response(json_encode(['error' => $e->getCode(), 'message' => $e->getMessage(), 'line' => $e->getLine()]), 500);
  576.         }
  577.         return new Response(json_encode($return), 200);
  578.     }
  579.     public function handleGenericForm(
  580.         Request $request,
  581.         mixed   $object,
  582.         string  $type,
  583.         array   $optionsForRoute = [],
  584.         bool    $delete false,
  585.         array   $options = [],
  586.         ?object $service null,
  587.         ?string $preProcess null,
  588.         ?string $postProcess null,
  589.         ?string $updateProcess null,
  590.         ?string $validateProcess null,
  591.     ): object
  592.     {
  593.         if (is_string($object)) {
  594.             $object = new $object();
  595.         }
  596.         $form $this->createForm(
  597.             $type,
  598.             $object,
  599.             array_merge(
  600.                 ['action' => $this->generateUrl($request->attributes->get('_route'), $optionsForRoute)],
  601.                 $options
  602.             )
  603.         );
  604.         $form->handleRequest($request);
  605.         if ($form->isSubmitted()) {
  606.             if ($service && $validateProcess) {
  607.                 $service->$validateProcess($object$form);
  608.             }
  609.             if ($form->isValid()) {
  610.                 if ($service && $preProcess) {
  611.                     try {
  612.                         $service->$preProcess($object$form);
  613.                     } catch (\Exception $e) {
  614.                         $this->addException($e);
  615.                         return $form;
  616.                     }
  617.                 }
  618.                 if ($service && $updateProcess) {
  619.                     try {
  620.                         $service->$updateProcess($object$form);
  621.                     } catch (\Exception $e) {
  622.                         $this->addException($e);
  623.                         return $form;
  624.                     }
  625.                 } elseif ($object) {
  626.                     if ($delete) {
  627.                         $this->remove($object)->flush();
  628.                     } else {
  629.                         $this->persist($object)->flush();
  630.                     }
  631.                 }
  632.                 if ($service && $postProcess) {
  633.                     try {
  634.                         $service->$postProcess($object$form$this);
  635.                     } catch (\Exception $e) {
  636.                         $this->addException($e);
  637.                         return $form;
  638.                     }
  639.                 }
  640.                 return $object;
  641.             }
  642.         }
  643.         return $form;
  644.     }
  645.     public function getAvailableRoles(): array
  646.     {
  647.         $result = [];
  648.         foreach ($this->getParameter('security.role_hierarchy.roles') as $role => $roles) {
  649.             $result[$this->trans('User.controller.User.Roles.' $role'Athena')] = $role;
  650.         }
  651.         krsort($result);
  652.         if (!$this->security->isGranted('ROLE_SUPER_ADMIN')) {
  653.             unset($result['ROLE_SUPER_ADMIN']);
  654.         }
  655.         return $result;
  656.     }
  657.     public function getTranslatedAvailableRoles(): array
  658.     {
  659.         $result = [];
  660.         foreach ($this->getParameter('security.role_hierarchy.roles') as $role => $roles) {
  661.             $result[$role] = $this->trans('User.controller.User.Roles.' $role'Athena');
  662.         }
  663.         ksort($result);
  664.         if (!$this->security->isGranted('ROLE_SUPER_ADMIN')) {
  665.             unset($result['ROLE_SUPER_ADMIN']);
  666.         }
  667.         return $result;
  668.     }
  669.     public function _datatableIndex(
  670.         string  $template 'Athena/datatable',
  671.         bool    $addButton true,
  672.         bool    $searchField true,
  673.         array   $additionalButton = [],
  674.         ?string $getDatatableUrl null,
  675.         ?string $createUrl null
  676.     ): Response
  677.     {
  678.         $this
  679.             ->setMainTitle(
  680.                 $this->translator->trans(
  681.                     $this->entityName '.controller.' $this->entityName '.main_title',
  682.                     [],
  683.                     $this->domain
  684.                 )
  685.             )
  686.             ->setMain(
  687.                 $template,
  688.                 [
  689.                     'datatableUrl' => $getDatatableUrl ?: $this->generateUrl($this->routePrefix 'GetDatatable'),
  690.                     'other' => $this->otherData,
  691.                     'searchField' => (int)$searchField
  692.                 ]
  693.             );
  694.         if ($addButton) {
  695.             $this->addButton(
  696.                 $createUrl ?: $this->generateUrl($this->routePrefix 'Create'),
  697.                 $this->entityName '.controller.' $this->entityName '.buttons.create',
  698.                 'add_circle_outline',
  699.                 '',
  700.                 $this->domain
  701.             );
  702.         }
  703.         if (!empty($additionalButton)) {
  704.             $this->addButton(
  705.                 $additionalButton['url'] ?? '',
  706.                 $additionalButton['text'] ?? '',
  707.                 $additionalButton['icon'] ?? '',
  708.                 '',
  709.                 $this->domain
  710.             );
  711.         }
  712.         return $this->getResponse();
  713.     }
  714.     public function _datatable(
  715.         int             $page 1,
  716.         int             $limit 1,
  717.         string          $sort 'none',
  718.         string          $search '',
  719.         string          $datatableTemplate 'Default',
  720.         ?ContextService $context null,
  721.         ?array          $preLoadedDatas null,
  722.         string          $templateForPreload '',
  723.         array           $optionsForPreload = [],
  724.         array           $additionalSearchField = [],
  725.         int             $countForPreload = -1
  726.     ): Response
  727.     {
  728.         $session $this->request->getSession();
  729.         $datatablesFilters $session->get('datatablesFilters', []);
  730.         if ($this->request->get('firstLoad'false)) {
  731.             if (isset($datatablesFilters[$this->routePrefix])) {
  732.                 $search $datatablesFilters[$this->routePrefix]['search'] ?? '';
  733.                 $additionalSearchField $datatablesFilters[$this->routePrefix]['additionalSearchField'] ?? [];
  734.             }
  735.         } else {
  736.             $datatablesFilters[$this->routePrefix] = [
  737.                 'search' => $search,
  738.                 'additionalSearchField' => $additionalSearchField,
  739.             ];
  740.             $session->set('datatablesFilters'$datatablesFilters);
  741.         }
  742.         $this->setContent(
  743.             'entity',
  744.             $this->translator->trans(
  745.                 $this->entityName '.template.index.entity.plural',
  746.                 [],
  747.                 $this->domain
  748.             )
  749.         );
  750.         $datatable $this->datatableService->buildDatatable(
  751.             $this->entityClass,
  752.             $page,
  753.             $limit,
  754.             $sort,
  755.             $search,
  756.             $datatableTemplate,
  757.             $context,
  758.             $preLoadedDatas,
  759.             $templateForPreload,
  760.             $optionsForPreload,
  761.             $additionalSearchField,
  762.             $countForPreload
  763.         );
  764.         foreach ($datatable as $key => $val) {
  765.             $this->setContent($key$val);
  766.         }
  767.         return $this->getResponse();
  768.     }
  769.     public function _create(
  770.         Request $request,
  771.         string  $formClass,
  772.         array   $optionsForRoute = [],
  773.         bool    $delete false,
  774.         array   $options = [],
  775.         ?object $service null,
  776.         ?string $preProcess null,
  777.         ?string $postProcess null,
  778.         ?string $updateProcess null,
  779.         ?string $validateProcess null,
  780.         bool    $modal true,
  781.         string  $content 'Athena/genericType',
  782.         array   $args = [],
  783.         bool    $returnRequest false,
  784.         string  $postUpdateMessage null,
  785.         string  $postUpdateStatus null,
  786.         array   $buttonAttribute = [],
  787.         ?string $entityName null,
  788.         ?object $object null,
  789.         ?string $postRedirectUrl null,
  790.     )
  791.     {
  792.         $return $this->handleGenericForm(
  793.             $request,
  794.             $object ?: $this->entityClass,
  795.             $formClass,
  796.             $optionsForRoute,
  797.             $delete,
  798.             $options,
  799.             $service,
  800.             $preProcess,
  801.             $postProcess,
  802.             $updateProcess,
  803.             $validateProcess
  804.         );
  805.         if ($return instanceof $this->entityClass) {
  806.             if ($postUpdateMessage) {
  807.                 $this->addStatus($postUpdateMessage$postUpdateStatus ?? self::STATUS_MESSAGE);
  808.             }
  809.             if ($postRedirectUrl) {
  810.                 return $this
  811.                     ->setRedirect($postRedirectUrl)
  812.                     ->getResponse();
  813.             } elseif ($returnRequest) {
  814.                 return $this->index($request);
  815.             } else {
  816.                 return $this->index();
  817.             }
  818.         } else {
  819.             if ($modal) {
  820.                 $this->setModal(
  821.                     ($entityName ?? $this->entityName) . '.controller.' . ($entityName ?? $this->entityName) . '.modal.createTitle',
  822.                     $content,
  823.                     array_merge($args, ['form' => $return->createView(), 'entity' => ($entityName ?? $this->entityName)]),
  824.                     $this->domain
  825.                 );
  826.             } else {
  827.                 $this->setMainTitle(
  828.                     $this->translator->trans(
  829.                         $this->entityName '.controller.' $this->entityName '.main.createTitle',
  830.                         [],
  831.                         $this->domain
  832.                     )
  833.                 )
  834.                     ->setMain(
  835.                         $content,
  836.                         array_merge($args, ['form' => $return->createView(), 'entity' => $this->entityName])
  837.                     );
  838.                 if ($buttonAttribute && !empty($buttonAttribute)) {
  839.                     $this->addButton(
  840.                         $this->generateUrl($buttonAttribute['url']),
  841.                         $this->entityName '.controller.' $this->entityName '.buttons.' $buttonAttribute['label'],
  842.                         $buttonAttribute['icon'],
  843.                         $buttonAttribute['class'],
  844.                         $buttonAttribute['transDomain']
  845.                     );
  846.                 }
  847.             }
  848.             return $this->getResponse();
  849.         }
  850.     }
  851.     public function _update(
  852.         Request $request,
  853.         object  $object,
  854.         string  $formClass,
  855.         array   $optionsForRoute = [],
  856.         bool    $delete false,
  857.         array   $options = [],
  858.         ?object $service null,
  859.         ?string $preProcess null,
  860.         ?string $postProcess null,
  861.         ?string $updateProcess null,
  862.         ?string $validateProcess null,
  863.         bool    $modal true,
  864.         string  $content 'Athena/genericType',
  865.         array   $args = [],
  866.         bool    $returnRequest false,
  867.         string  $postUpdateMessage null,
  868.         string  $postUpdateStatus null,
  869.         ?string $entityName null,
  870.         ?string $postRedirectUrl null,
  871.     ): Response
  872.     {
  873.         $return $this->handleGenericForm(
  874.             $request,
  875.             $object,
  876.             $formClass,
  877.             $optionsForRoute,
  878.             $delete,
  879.             $options,
  880.             $service,
  881.             $preProcess,
  882.             $postProcess,
  883.             $updateProcess,
  884.             $validateProcess
  885.         );
  886.         if ($return instanceof $this->entityClass) {
  887.             if ($postUpdateMessage) {
  888.                 $this->addStatus($postUpdateMessage$postUpdateStatus ?? self::STATUS_MESSAGE);
  889.             }
  890.             if ($postRedirectUrl) {
  891.                 return $this
  892.                     ->setRedirect($postRedirectUrl)
  893.                     ->getResponse();
  894.             } elseif ($returnRequest) {
  895.                 return $this->index($request);
  896.             } else {
  897.                 return $this->index();
  898.             }
  899.         } else {
  900.             if ($modal) {
  901.                 $this
  902.                     ->setModal(
  903.                         ($entityName ?? $this->entityName) . '.controller.' . ($entityName ?? $this->entityName) . '.modal.updateTitle',
  904.                         $content,
  905.                         array_merge($args, ['form' => $return->createView(), 'entity' => ($entityName ?? $this->entityName)]),
  906.                         $this->domain
  907.                     );
  908.             } else {
  909.                 $this->setMainTitle(
  910.                     $this->translator->trans(
  911.                         $this->entityName '.controller.' $this->entityName '.main.updateTitle',
  912.                         [],
  913.                         $this->domain
  914.                     )
  915.                 )
  916.                     ->setMain(
  917.                         $content,
  918.                         array_merge($args, ['form' => $return->createView(), 'entity' => $this->entityName])
  919.                     );
  920.             }
  921.             return $this->getResponse();
  922.         }
  923.     }
  924.     public function _delete(
  925.         Request $request,
  926.         object  $object,
  927.                 $optionsForRoute,
  928.         string  $postUpdateMessage null,
  929.         string  $postUpdateStatus null,
  930.         array   $options = [],
  931.         ?object $service null,
  932.         ?string $preProcess null,
  933.         ?string $postProcess null,
  934.         ?string $updateProcess null,
  935.         ?string $validateProcess null,
  936.         bool    $returnRequest false,
  937.         ?string $entityName null,
  938.         ?string $postRedirectUrl null,
  939.     )
  940.     {
  941.         if (($return $this->handleGenericForm(
  942.                 $request,
  943.                 $object,
  944.                 DeleteForm::class,
  945.                 $optionsForRoute,
  946.                 true,
  947.                 $options,
  948.                 $service,
  949.                 $preProcess,
  950.                 $postProcess,
  951.                 $updateProcess,
  952.                 $validateProcess
  953.             )) instanceof $this->entityClass) {
  954.             if ($postUpdateMessage) {
  955.                 $this->addStatus($postUpdateMessage$postUpdateStatus ?? self::STATUS_MESSAGE);
  956.             }
  957.             if ($postRedirectUrl) {
  958.                 return $this
  959.                     ->setRedirect($postRedirectUrl)
  960.                     ->getResponse();
  961.             } elseif ($returnRequest) {
  962.                 return $this->index($request);
  963.             } else {
  964.                 return $this->index();
  965.             }
  966.         } else {
  967.             return $this
  968.                 ->setModal(
  969.                     ($entityName ?? $this->entityName) . '.controller.' . ($entityName ?? $this->entityName) . '.modal.deleteTitle',
  970.                     'Athena/deleteType',
  971.                     [
  972.                         'form' => $return->createView(),
  973.                         'entity' => $this->translator->trans(
  974.                             ($entityName ?? $this->entityName) . '.controller.' . ($entityName ?? $this->entityName) . '.modal.entity',
  975.                             [],
  976.                             $this->domain
  977.                         ),
  978.                     ],
  979.                     $this->domain
  980.                 )
  981.                 ->getResponse();
  982.         }
  983.     }
  984.     public function _autocomplete(string $search, ?string $entityClass null): JsonResponse
  985.     {
  986.         $result = array();
  987.         if ($search) {
  988.             foreach ($this->getRepository($entityClass ?? $this->entityClass)->getAutocomplete($search) as $object) {
  989.                 $result[] = ['id' => $object->getId(), 'text' => $object->_toAutocomplete()];
  990.             }
  991.         }
  992.         return $this->json($result);
  993.     }
  994.     public function _show(
  995.         string $content,
  996.         bool   $modal false,
  997.         array  $args = [],
  998.         array  $translateParameters = []
  999.     ): Response
  1000.     {
  1001.         if ($modal) {
  1002.             $this
  1003.                 ->setModal(
  1004.                     $this->entityName '.controller.' $this->entityName '.modal.showTitle',
  1005.                     $content,
  1006.                     array_merge($args, ['entity' => $this->entityName]),
  1007.                     $this->domain
  1008.                 );
  1009.         } else {
  1010.             $this->setMainTitle(
  1011.                 $this->translator->trans(
  1012.                     $this->entityName '.controller.' $this->entityName '.main.showTitle',
  1013.                     $translateParameters,
  1014.                     $this->domain
  1015.                 )
  1016.             )
  1017.                 ->setMain(
  1018.                     $content,
  1019.                     array_merge($args, ['entity' => $this->entityName])
  1020.                 );
  1021.         }
  1022.         return $this->getResponse();
  1023.     }
  1024.     public function getContext(): ContextService
  1025.     {
  1026.         return $this->context;
  1027.     }
  1028.     public function setTargetBlank(string $url, ?array $args null): self
  1029.     {
  1030.         return $this->setContent(self::TAG_TARGET_BLANK$url$args);
  1031.     }
  1032.     public function setFormTargetBlank(string $urlstring $datas, ?array $args null): self
  1033.     {
  1034.         return $this
  1035.             ->setContent(self::TAG_FORM_BLANK$url$args)
  1036.             ->setContent(self::TAG_FORM_BLANK_DATAS$datas$args);
  1037.     }
  1038.     public function setFunctionOnLoad(string $function): self
  1039.     {
  1040.         return $this->setContent(self::TAG_FUNCTION_ON_LOAD$function);
  1041.     }
  1042.     public function _extract(
  1043.         Request $request,
  1044.         mixed   $class '',
  1045.         string  $filename '',
  1046.         string  $search '',
  1047.         array   $additionalSearchFields = [],
  1048.         string  $datatableTemplate '',
  1049.                 $context null
  1050.     )
  1051.     {
  1052.         if (is_array($class)) {
  1053.             $object $class['data'];
  1054.             if (isset($request->request->all()['extract_fields'])) {
  1055.                 $columns = [];
  1056.                 foreach ($request->request->all() as $key => $value) {
  1057.                     if ($key !== 'extract_fields' && $value == 'on') {
  1058.                         $columns[] = $this->trans($key'fields');
  1059.                     }
  1060.                 }
  1061.                 if (empty($columns)) {
  1062.                     return $this->addStatus("Vous devez sélectionner une colonne pour l'extraction!"self::STATUS_ERROR)->setRedirect($this->generateUrl($this->routePrefix 'Index'))->getResponse();
  1063.                 } else {
  1064.                     $res $this->datatableService->filterArray($object$columns);
  1065.                     foreach ($res as &$line) {
  1066.                         foreach ($line as $key => $val) {
  1067.                             if (isset($class['options']['extract']['fields'][$key])) {
  1068.                                 $line[$this->trans($class['options']['extract']['fields'][$key], 'fields')] = $val;
  1069.                                 unset($line[$key]);
  1070.                             }
  1071.                         }
  1072.                     }
  1073.                     $fileName $this->datatableService->export_data_to_csv($res$filename);
  1074.                     $this->setTargetBlank($this->generateUrl($this->routePrefix 'DownloadExtract', ['filename' => $fileName]));
  1075.                     return $this->addStatus("Le fichier a bien été téléchargé!"self::STATUS_MESSAGE)->setRedirect($this->generateUrl($this->routePrefix 'Index'))
  1076.                         ->getResponse();
  1077.                 }
  1078.             }
  1079.             $params '';
  1080.             foreach ($additionalSearchFields as $param) {
  1081.                 $params $params '/' $param;
  1082.             }
  1083.             if (!empty($search)) {
  1084.                 $params $params '/' $search;
  1085.             }
  1086.             return $this
  1087.                 ->setModal(
  1088.                     $this->entityName '.controller.' $this->entityName '.modal.extractTitle',
  1089.                     'Athena/extractFields',
  1090.                     [
  1091.                         'url' => $this->generateUrl($this->routePrefix 'Extract') . $params,
  1092.                         'options' => $class['options']
  1093.                     ],
  1094.                     $this->domain
  1095.                 )
  1096.                 ->getResponse();
  1097.         } else {
  1098.             $object = new $class;
  1099.             if (isset($request->request->all()['extract_fields'])) {
  1100.                 $columns = [];
  1101.                 foreach ($request->request->all() as $key => $value) {
  1102.                     if ($key !== 'extract_fields' && $value == 'on') {
  1103.                         $columns[] = $key;
  1104.                     }
  1105.                 }
  1106.                 if (empty($columns)) {
  1107.                     return $this->addStatus("Vous devez sélectionner une colonne pour l'extraction!"self::STATUS_ERROR)->setRedirect($this->generateUrl($this->routePrefix 'Index'))->getResponse();
  1108.                 } else {
  1109.                     $dat $this->getRepository($class)->getDatatableForDownload($search$datatableTemplate$context$additionalSearchFields);
  1110.                     $arrayDat $this->datatableService->entityToArray($dat$columns$class);
  1111.                     $fileName $this->datatableService->export_data_to_csv($arrayDat$filename);
  1112.                     $this->setTargetBlank($this->generateUrl($this->routePrefix 'DownloadExtract', ['filename' => $fileName]));
  1113.                     return $this->addStatus("Le fichier a bien été téléchargé!"self::STATUS_MESSAGE)->setRedirect($this->generateUrl($this->routePrefix 'Index'))
  1114.                         ->getResponse();
  1115.                 }
  1116.             }
  1117.             $params '';
  1118.             foreach ($additionalSearchFields as $param) {
  1119.                 $params $params '/' $param;
  1120.             }
  1121.             if (!empty($search)) {
  1122.                 $params $params '/' $search;
  1123.             }
  1124.             return $this
  1125.                 ->setModal(
  1126.                     $this->entityName '.controller.' $this->entityName '.modal.extractTitle',
  1127.                     'Athena/extractFields',
  1128.                     [
  1129.                         'url' => $this->generateUrl($this->routePrefix 'Extract') . $params,
  1130.                         'options' => $object->_getMetadataDefault()
  1131.                     ],
  1132.                     $this->domain
  1133.                 )
  1134.                 ->getResponse();
  1135.         }
  1136.     }
  1137.     public function handleS3Files(array $datasstring $subjectstring $body): Response
  1138.     {
  1139.         if (isset($datas['s3Files'])) {
  1140.             $this->setFormTargetBlank($this->generateUrl('adminAwsS3Download'), json_encode($datas));
  1141.         } elseif (isset($datas['files'])) {
  1142.             $this->setWaitingModal(json_encode($datas['files']), $subject$body);
  1143.         } else {
  1144.             $this->addStatus('Une erreur est survenue lors de la création du fichier : ' print_r($datas1), self::STATUS_ERROR);
  1145.         }
  1146.         return $this->getResponse();
  1147.     }
  1148.     /**
  1149.      * @return false|string
  1150.      */
  1151.     public function getVideoTutorialUrl(?string $route null): string|false
  1152.     {
  1153.         $route ??= $this->request->attributes->get('_route');
  1154.         $videoTutorial $this->getRepository(VideoTutorial::class)->findOneByRoute($route);
  1155.         return $videoTutorial $this->generateUrl(
  1156.             'adminVideoViewerIndex',
  1157.             [
  1158.                 'videoUrl' => $videoTutorial->getUrl(),
  1159.                 'title' => $videoTutorial->getTitle() ?: 'Tutoriel vidéo',
  1160.             ]
  1161.         ) : false;
  1162.     }
  1163.     private function canEditVideoTutorial(): string
  1164.     {
  1165.         $user $this->getUser();
  1166.         if ($this->security->isGranted('IS_IMPERSONATOR')) {
  1167.             $user $this->security->getToken()->getOriginalToken()->getUser();
  1168.         }
  1169.         return in_array('ROLE_SUPER_ADMIN'$user?->getRoles(), true) ? '1' '0';
  1170.     }
  1171. }