src/Controller/Front/CourseController.php line 147

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Front;
  3. use DateTime;
  4. use App\Entity\Alert;
  5. use App\Entity\Course;
  6. use App\Entity\Trainee;
  7. use App\Entity\SearchCourse;
  8. use App\Entity\FeaturedCourse;
  9. use App\Form\SearchCourseType;
  10. use App\Service\CourseService;
  11. use App\Service\GoogleService;
  12. use App\Entity\CourseViewsStat;
  13. use App\Entity\CourseAvailability;
  14. use App\Entity\SearchAvailability;
  15. use App\Repository\AlertRepository;
  16. use App\Form\SearchAvailabilityType;
  17. use App\Repository\BookingRepository;
  18. use App\Repository\CourseRepository;
  19. use App\Service\InternationalService;
  20. use Doctrine\Persistence\ObjectManager;
  21. use Doctrine\ORM\EntityManagerInterface;
  22. use Knp\Component\Pager\PaginatorInterface;
  23. use Symfony\Component\Serializer\Serializer;
  24. use App\Repository\CourseViewsStatRepository;
  25. use App\Repository\WebsiteLanguageRepository;
  26. use Symfony\Component\HttpFoundation\Request;
  27. use App\Repository\TranslatedCourseRepository;
  28. use Symfony\Component\HttpFoundation\Response;
  29. use Symfony\Component\Routing\Annotation\Route;
  30. use App\Repository\CourseAvailabilityRepository;
  31. use App\Service\ViewCounterService;
  32. use Symfony\Component\HttpFoundation\JsonResponse;
  33. use Symfony\Component\HttpFoundation\Session\Session;
  34. use Symfony\Component\Serializer\Encoder\JsonEncoder;
  35. use Symfony\Contracts\Translation\TranslatorInterface;
  36. use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
  37. use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
  38. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  39. use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
  40. #[Route(path'{_locale}/courses')]
  41. class CourseController extends AbstractController
  42. {
  43.     private $googleApiKeyBack;
  44.     public function __construct(
  45.         private AlertRepository $alertRepository
  46.         private EntityManagerInterface $entityManager
  47.         private CourseAvailabilityRepository $courseAvailabilityRepository
  48.         private PaginatorInterface $paginator
  49.         private TranslatorInterface $translator
  50.         private InternationalService $internationalService
  51.         private TranslatedCourseRepository $translatedCourseRepository
  52.         private WebsiteLanguageRepository $websiteLanguageRepository
  53.         private GoogleService $googleService,
  54.         private CourseService $courseService,
  55.         private ContainerBagInterface $params
  56.     ){
  57.         $this->googleApiKeyBack $this->params->get('api_key_google_back');
  58.     }
  59.     function isSearchNull(SearchCourse $search) {
  60.         if ($search->getPlace() == null && count($search->getSports()) == && $search->getBegin() == null && count($search->getAges()) == && count($search->getLevels()) == && count($search->getLanguages()) == && $search->getHasLabels() == false) {
  61.             return true;
  62.         }
  63.         return false;
  64.     }
  65.     /*
  66.     #[Route(path: '/translate/courses', name: 't_courses')]
  67.     public function t_courses(EntityManagerInterface $manager, CourseRepository $courseRepository)
  68.     {
  69.         $activeCourses = $courseRepository->findBy(['status' => 'active']);
  70.         foreach ($activeCourses as $course) {
  71.             
  72.             $translatedCourses = $course->getTranslatedContents();
  73.             $baseTranslatedCourse = $translatedCourses->first();
  74.             $websiteLanguages = $this->websiteLanguageRepository->findAll();
  75.             foreach ($websiteLanguages as $language) {
  76.                 $languageSlug = $language->getSlug();
  77.                 
  78.                 $translatedCourse = $this->translatedCourseRepository->findOneBy(['course' => $course, 'language' => $languageSlug]);
  79.                 if ($translatedCourse == null) {
  80.                     $translatedCourse = new TranslatedCourse;
  81.                     try {
  82.                         $nameTranslate = $this->googleService->translateWithGoogle($baseTranslatedCourse->getName(), $languageSlug);
  83.                         $descriptionTranslate = $this->googleService->translateWithGoogle($baseTranslatedCourse->getDescription(), $languageSlug);
  84.     
  85.                         if($baseTranslatedCourse->getOthers()) {
  86.                             $othersTranslate = $this->googleService->translateWithGoogle($baseTranslatedCourse->getOthers(), $languageSlug);
  87.                         }
  88.     
  89.                         foreach($baseTranslatedCourse->getPlannings() as $planning){
  90.     
  91.                             $planningTranslate = new Planning;
  92.     
  93.                             $titlePlanningTranslate = $this->googleService->translateWithGoogle($planning->getTitle(), $languageSlug);
  94.                             $descriptionPlanningTranslate = $this->googleService->translateWithGoogle($planning->getDescription(), $languageSlug);
  95.     
  96.                             $planningTranslate->setTitle($titlePlanningTranslate)
  97.                                               ->setDescription($descriptionPlanningTranslate);
  98.     
  99.                             $translatedCourse->addPlanning($planningTranslate);
  100.     
  101.                         }
  102.     
  103.                         $translatedCourse->setName($nameTranslate)
  104.                             ->setDescription($descriptionTranslate)
  105.                             ->setOthers($othersTranslate ?? "")
  106.                             ->setLanguage($language->getSlug())
  107.                             ->setCourse($course);
  108.     
  109.                         $this->entityManager->persist($translatedCourse);
  110.     
  111.                     }
  112.                     catch(Exception $e) {
  113.                         // Créer une exeption;
  114.                     }
  115.                 }
  116.             }
  117.         }
  118.         $this->entityManager->flush();
  119.         dd("fait");
  120.     }
  121.     */
  122.     
  123.     #[Route(path'/{view}'name'courses'defaults: ['view' => 'list'])]
  124.     public function listCourses($viewCourseRepository $courseRepositoryPaginatorInterface $paginatorRequest $requestEntityManagerInterface $managerTranslatorInterface $translatorGoogleService $googleService): Response
  125.     {
  126.         $search = new SearchCourse();
  127.         $startingDate null;
  128.         $noSearchResult false;
  129.         $otherResult false;
  130.         $form $this->createForm(SearchCourseType::class, $search);
  131.         $form->handleRequest($request);
  132.         if ($request->query->get('search') && $this->isSearchNull($search)) {
  133.             return $this->redirectToRoute('courses', [
  134.                 'view' => $view
  135.             ]);
  136.         }
  137.         
  138.         if ($form->isSubmitted() && $search->getPlace() != "undefined") {
  139.             if ($view == 'map' && $search->getPlace() == null) {
  140.                 return $this->redirectToRoute('courses', [
  141.                     'view' => 'list'
  142.                 ]);
  143.             }
  144.             // Create alert for trainee
  145.             if ($request->query->get('search') == null) {
  146.                 try {
  147.                     $this->createAlert($search);
  148.                 } catch (\Throwable $th) {
  149.                     //throw $th;
  150.                 }
  151.             }
  152.             $startingDate $search->getBegin();
  153.             $coursesSearch $courseRepository->searchCourses($search);
  154.             if(count($coursesSearch) == 0) {
  155.                 $countryCode null;
  156.                 $noSearchResult true;
  157.                 if ($search->getPlace() != null && $googleService->getPlaceCountryCode($search->getPlace())) {
  158.                     $countryCode $googleService->getPlaceCountryCode($search->getPlace());
  159.                     
  160.                     $coursesSearch $courseRepository->searchCourses($search$countryCode);
  161.                     if (count($coursesSearch) > 0) {
  162.                         $otherResult true;
  163.                     }
  164.                 }
  165.                 $searchBooster $courseRepository->findFeaturedCourses(null'research'$countryCode);
  166.             }
  167.             
  168.             $courses $this->sortCourseByNextDate($coursesSearch);
  169.         } 
  170.         
  171.         else {
  172.             $courses $this->sortCourseByNextDate($courseRepository->findLatestCourses());
  173.             $search null;
  174.         }
  175.         $courses $paginator->paginate(
  176.             $courses,
  177.             $request->query->getInt('page'1),
  178.             24
  179.         );
  180.         $template 'front/course/search-course.html.twig';
  181.         if ($view == 'map') {
  182.             $template 'front/course/search-course-map.html.twig';
  183.         }
  184.         $response $this->render($template, [
  185.             'menu' => 'courses',
  186.             'courses' => $courses,
  187.             'noSearchResult' => $noSearchResult,
  188.             'otherResult' => $otherResult,
  189.             'form' => $form->createView(),
  190.             'startingDate' => $startingDate,
  191.             'criteria' => $search,
  192.             'searchBooster' => $searchBooster ?? 0,
  193.             'view' => $view
  194.         ]);
  195.     
  196.         if ($search != null) {
  197.             // Ajouter l'en-tête X-Robots-Tag
  198.             $response->headers->set('X-Robots-Tag''noindex, nofollow');
  199.         }
  200.     
  201.         return $response;
  202.         
  203.     }
  204.     
  205.     #[Route(path'-details/{token}'name'view_course')]
  206.     public function courseDetails(Course $courseViewCounterService $viewCounterRequest $requestCourseViewsStatRepository $courseViewsStatRepositoryEntityManagerInterface $managerBookingRepository $bookingRepository): Response
  207.     {
  208.         
  209.         if ($course->getOwner()->getStatus() != 'online') {
  210.             $this->addFlash(
  211.                 'info',
  212.                 $this->translator->trans("flashes.course_controller.unknown_course")
  213.             );
  214.             return $this->redirectToRoute('homepage');
  215.         }
  216.         if ($course->getStatus() == 'pending' && $course->getOwner() != $this->getUser()) {
  217.             return $this->redirectToRoute('homepage');
  218.         }
  219.         $session $request->getSession();
  220.         $translatedCourse $course->getTranslatedContent($request->getLocale());
  221.         if ($session->get('seenCourses')) {
  222.             $seenCourses $session->get('seenCourses');
  223.         } else {
  224.             $seenCourses = [];
  225.         }
  226.         $seenCourses[] = $course->getToken();
  227.         
  228.         $session->set('seenCourses'$seenCourses);
  229.         $page $request->query->getInt('page'1);
  230.         $search = new SearchAvailability();
  231.         $startingDate null;
  232.         $form $this->createForm(SearchAvailabilityType::class, $search);
  233.         $form->handleRequest($request);
  234.         if ($form->isSubmitted() && $form->isValid()) {
  235.             $startingDate $search->getBegin();
  236.         }
  237.         $availabilities $this->getAvailabilities($course$page$startingDate);
  238.         $encoder = new JsonEncoder();
  239.         $defaultContext = [
  240.             AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object$json$context) {
  241.                 return $object;
  242.             },
  243.         ];
  244.         $normalizer = new ObjectNormalizer(nullnullnullnullnullnull$defaultContext);
  245.         $serializer = new Serializer([$normalizer], [$encoder]);
  246.         $encodedAvailabilities $serializer->serialize($availabilities->getItems(), 'json');
  247.         if ($request->query->getInt('page')) {
  248.             $response = new Response();
  249.             $response->setContent($encodedAvailabilities);
  250.             $response->headers->set('Content-Type''application/json');
  251.             return $response;
  252.         }
  253.         //View stat
  254.         $viewCounter->countView($course'course');
  255.         $traineeHasPendingBooking false;
  256.         if ($this->getUser() && $this->getUser() instanceof Trainee) {
  257.             $trainee $this->getUser();
  258.             $traineePendingBooking $bookingRepository->traineeCoursePendingBooking($trainee$course);
  259.             if ($traineePendingBooking) {
  260.                 $traineeHasPendingBooking true;
  261.             }
  262.         }
  263.         return $this->render('front/course/course-details.html.twig', [
  264.             'course' => $course,
  265.             'translatedCourse' => $translatedCourse,
  266.             'availabilities' => $availabilities,
  267.             'encodedAvailabilities' => $encodedAvailabilities,
  268.             'traineeHasPendingBooking' => $traineeHasPendingBooking,
  269.             'form' => $form->createView(),
  270.             'startingDate' => $startingDate
  271.         ]);
  272.     }
  273.     public function getAvailabilities(Course $course$page$startingDate null)
  274.     {
  275.         
  276.         $nextAvailabilities $this->courseService->getAvailabilities($course'multiple'$startingDate);
  277.         usort($nextAvailabilities, array($this"cmp"));
  278.         $sortedAvailabilities $this->paginator->paginate(
  279.             $nextAvailabilities,
  280.             $page,
  281.             8
  282.         );
  283.         return $sortedAvailabilities;
  284.     }
  285.     function cmp($a$b)
  286.     {
  287.         $aBegin date_create_from_format('d.m.y'$a->getBegin());
  288.         $bBegin date_create_from_format('d.m.y'$b->getBegin());
  289.         return ($aBegin $bBegin);
  290.     }
  291.     #[Route(path'/add-course-to-favorite/{id}'name'add_course_favorite'methods: ['POST'])]
  292.     public function addToFavorite(Course $courseObjectManager $managerRequest $request)
  293.     {
  294.         $user $this->getUser();
  295.         $data json_decode($request->getContent(), true);
  296.         if($this->isCsrfTokenValid('favorite'.$course->getId(), $data['_token']))
  297.         {
  298.             if ($user instanceof Trainee) {
  299.                 if($course->getTraineesFavorites()->contains($user))
  300.                 {
  301.                     $user->removeFavorite($course);
  302.                 }
  303.                 else
  304.                 {
  305.                     $user->addFavorite($course);
  306.                 }
  307.                 $manager->flush();
  308.             }
  309.             return new JsonResponse(['success' => 1]);
  310.         }
  311.         else 
  312.         {
  313.             return new JsonResponse(['error' => 'token invalid'], 400);
  314.         }
  315.     }
  316.     #[Route(path'/set-search-destination/in-session'name'set_search_destination')]
  317.     public function setSearchDestination(Request $request)
  318.     {
  319.         $data json_decode($request->getContent(), true);
  320.         $destination $data['searchDestination'];
  321.         $session = new Session();
  322.         $session->set('destination'$destination);
  323.         return new JsonResponse(['ok' => 'ok']);
  324.     }
  325.     private function getNextDate(Course $course$startingDate null)
  326.     {
  327.         if ($startingDate == null) {
  328.             $fromDate = new DateTime();
  329.             $fromDate->setTimestamp(strtotime('today midnight'));
  330.         } else {
  331.             $fromDate date_create_from_format('d/m/Y'$startingDate);
  332.         }
  333.         $date null;
  334.         $nextAvailability = new CourseAvailability();
  335.         $frequency $course->getFrequency();
  336.         if ($frequency == 'punctual') {
  337.             foreach ($course->getAvailabilities() as $availability) {
  338.                 $begin date_create_from_format('d/m/Y'$availability->getBegin());
  339.                 if ($begin $fromDate && ($date == null || $date $begin)) {
  340.                     $date $begin;
  341.                     $nextAvailability->setDuration($availability->getDuration())
  342.                         ->setPrice($availability->getPrice())
  343.                         ->setBegin($begin->format('d.m.y'))
  344.                         ->setEnd(date_create_from_format('d/m/Y'$availability->getEnd())->format('d.m.y'));
  345.                 }
  346.             }
  347.         } else {
  348.             foreach ($course->getAvailabilities() as $availability) {
  349.                 $begin date_create_from_format('d/m/Y'$availability->getBegin());
  350.                 $endDate null;
  351.                 if ($availability->getEnd() != null) {
  352.                     $endDate date_create_from_format('d/m/Y'$availability->getEnd());
  353.                 }
  354.                 if ($endDate == null || $endDate $fromDate) {
  355.                     $startDate $availability->getStartDate();
  356.                     $recurrence $availability->getRecurrence();
  357.                     $currentDate $begin;
  358.                     switch ($startDate) {
  359.                         case 'mon':
  360.                             $nextDay 'monday';
  361.                             break;
  362.                         case 'tue':
  363.                             $nextDay 'tuesday';
  364.                             break;
  365.                         case 'wed':
  366.                             $nextDay 'wednesday';
  367.                             break;
  368.                         case 'thu':
  369.                             $nextDay 'thursday';
  370.                             break;
  371.                         case 'fri':
  372.                             $nextDay 'friday';
  373.                             break;
  374.                         case 'sat':
  375.                             $nextDay 'saturday';
  376.                             break;
  377.                         case 'sun':
  378.                             $nextDay 'sunday';
  379.                             break;
  380.                     }
  381.                     if($nextDay) {
  382.                         $currentDate->modify("next {$nextDay}");
  383.                     }
  384.                     switch ($recurrence) {
  385.                         case 'weekly':
  386.                             $nextRecurrence "next {$nextDay}";
  387.                             break;
  388.                         case 'monthly':
  389.                             $dayPosition $availability->getDayPosition();
  390.                             if ($dayPosition == 1) {
  391.                                 $nextRecurrence "first {$nextDay} of next month";
  392.                             } else if ($dayPosition == 2) {
  393.                                 $nextRecurrence "second {$nextDay} of next month";
  394.                             } else if ($dayPosition == 3) {
  395.                                 $nextRecurrence "third {$nextDay} of next month";
  396.                             } else {
  397.                                 $nextRecurrence "fourth {$nextDay} of next month";
  398.                             }
  399.                             break;
  400.                     }
  401.                     while ($currentDate $fromDate) {
  402.                         $currentDate->modify($nextRecurrence);
  403.                     }
  404.                     if ($date == null || $date > ($currentDate && ($endDate == null || $endDate $date))) {
  405.                         $end = clone ($currentDate);
  406.                         $end->modify("+{$availability->getDuration()} days");
  407.                         $date $currentDate;
  408.                         $nextAvailability->setDuration($availability->getDuration())
  409.                             ->setPrice($availability->getPrice())
  410.                             ->setBegin($begin->format('d.m.y'))
  411.                             ->setEnd($end->format('d.m.y'));
  412.                     }
  413.                 }
  414.             }
  415.         }
  416.         return $nextAvailability;
  417.     }
  418.     private function sortCourseByNextDate($courses$limit null)
  419.     {
  420.         $boostCourse array_filter($courses, function($course){
  421.             if(count($course->getFeatureds()) == 0){
  422.                 return false;
  423.             }
  424.             /**
  425.              * @var FeaturedCourse $featured
  426.              */
  427.             foreach($course->getFeatureds() as $featured)
  428.             {
  429.                 if($featured->getStatus() == 'active' && $featured->getFeaturedOffer()->getType() == "research"){
  430.                     return true;
  431.                 }
  432.             }
  433.             return false;
  434.         });
  435.         $noBoostCourse array_filter($courses, function($course){
  436.             if(count($course->getFeatureds()) == 0){
  437.                 return true;
  438.             }
  439.             /**
  440.              * @var FeaturedCourse $featured
  441.              */
  442.             foreach($course->getFeatureds() as $featured)
  443.             {
  444.                 if($featured->getStatus() == 'active' && $featured->getFeaturedOffer()->getType() == "research"){
  445.                     return false;
  446.                 }
  447.             }
  448.             return true;
  449.         });
  450.         //Boost
  451.         $availabilitiesSort = [];
  452.         foreach ($boostCourse as $course) {
  453.             $nextAvailability $this->getNextDate($course)->setCourse($course);
  454.             $availabilitiesSort[] = $nextAvailability;
  455.         }
  456.         usort($availabilitiesSort, function($a$b) {
  457.             $ad DateTime::createFromFormat('d.m.y'$a->getBegin());
  458.             $bd DateTime::createFromFormat('d.m.y'$b->getBegin());
  459.             if ($ad == $bd) {
  460.                 return 0;
  461.             }
  462.             return $ad $bd ? -1;
  463.         });
  464.         $lastedCoursesBoost = [];
  465.         foreach ($availabilitiesSort as $availability)
  466.         {
  467.             $lastedCoursesBoost[] = $availability->getCourse();
  468.         }
  469.         //NoBoost
  470.         $availabilitiesSort = [];
  471.         foreach ($noBoostCourse as $course) {
  472.             $nextAvailability $this->getNextDate($course)->setCourse($course);
  473.             $availabilitiesSort[] = $nextAvailability;
  474.         }
  475.         usort($availabilitiesSort, function($a$b) {
  476.             $ad DateTime::createFromFormat('d.m.y'$a->getBegin());
  477.             $bd DateTime::createFromFormat('d.m.y'$b->getBegin());
  478.             if ($ad == $bd) {
  479.                 return 0;
  480.             }
  481.             return $ad $bd ? -1;
  482.         });
  483.         $lastedCoursesNoBoost = [];
  484.         foreach ($availabilitiesSort as $availability)
  485.         {
  486.             $lastedCoursesNoBoost[] = $availability->getCourse();
  487.         }
  488.         $coursesSort array_merge($lastedCoursesBoost$lastedCoursesNoBoost);
  489.         return $coursesSort;
  490.     }
  491.     private function createAlert(SearchCourse $search)
  492.     {
  493.         $trainee $this->getUser();   
  494.         
  495.         if (!$trainee instanceof Trainee) {
  496.             return;
  497.         }
  498.         
  499.         $alert = new Alert();
  500.         $countryCode null;
  501.         $placeName null;
  502.         if ($search->getPlace() != null) {
  503.             $response file_get_contents("https://maps.googleapis.com/maps/api/place/details/json?place_id={$search->getPlace()}&key={$this->googleApiKeyBack}");
  504.             $resultJson json_decode($response);
  505.             $placeName $resultJson->result->formatted_address;
  506.             $addressComponents count($resultJson->result->address_components);
  507.             $countryCode $resultJson->result->address_components[$addressComponents 1]->short_name;
  508.         }
  509.         $numberAlert $this->alertRepository->getNumberAlert($trainee);
  510.         $alert->setTrainee($trainee)
  511.             ->setTitle("#" $numberAlert 1)
  512.             ->setPlace($search->getPlace())
  513.             ->setPlaceName($placeName)
  514.             ->setCountryCode($countryCode)
  515.             ->setBegin($search->getBegin())
  516.             ->setEmailActivated(true)
  517.             ->setCreatedAt(new DateTime());
  518.         foreach ($search->getAges() as $age) {
  519.             $alert->addAge($age);
  520.         }
  521.         foreach ($search->getSports() as $sport) {
  522.             $alert->addSport($sport);
  523.         }
  524.         foreach ($search->getLevels() as $level) {
  525.             $alert->addLevel($level);
  526.         }
  527.         foreach ($search->getLanguages() as $language) {
  528.             $alert->addLanguage($language);
  529.         }
  530.         $this->entityManager->persist($alert);
  531.         $this->entityManager->flush();
  532.         $this->addFlash(
  533.             'success',
  534.             $this->translator->trans("flashes.course_controller.alert_created")
  535.         );
  536.     }
  537. }