src/Controller/TrajetController.php line 106

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Notes;
  4. use App\Entity\Reservation;
  5. use App\Form\NoteConducteurType;
  6. use App\Repository\UserRepository;
  7. use App\Service\AfficheService;
  8. use App\Service\NotificationService;
  9. use App\Service\MetaService;
  10. use App\Service\StripeConnectService;
  11. use App\Service\TrajetAnnulationService;
  12. use Carbon\Carbon;
  13. use App\Entity\Trajet;
  14. use App\Repository\NotesRepository;
  15. use App\Repository\TrajetRepository;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Symfony\Bridge\Twig\Mime\TemplatedEmail;
  18. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpFoundation\Response;
  21. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  22. use Symfony\Component\Mailer\MailerInterface;
  23. use Symfony\Component\Mime\Address;
  24. use Symfony\Component\Routing\Annotation\Route;
  25. use Stripe\Stripe;
  26. use Stripe\Account;
  27. use Stripe\Token;
  28. class TrajetController extends AbstractController
  29. {
  30.     /**
  31.      * @Route("/chercher", name="app_chercher")
  32.      */
  33.     public function chercher(Request $request): Response
  34.     {
  35.         $depart $request->query->get('select_departure');
  36.         $arrivee $request->query->get('select_arrival');
  37.         $date $request->query->get('date_trajet');
  38.         $heure $request->query->get('heure_trajet') ?? 'any';
  39.         $places $request->query->get('places_min') ?? 1;
  40.         if ($depart && $arrivee && $date && \DateTime::createFromFormat('Y-m-d'$date)) {
  41.             return $this->redirectToRoute('app_chercherResultats', [
  42.                 'depart' => $depart,
  43.                 'arrivee' => $arrivee,
  44.                 'date' => $date,
  45.                 'heure' => 'any',
  46.                 'places' => $places,
  47.             ]);
  48.         }
  49.         return $this->render('trajet/chercher.html.twig');
  50.     }
  51.     /**
  52.      * @Route("/chercher/{depart}/{arrivee}/{date}/{heure}/{places}", name="app_chercherResultats")
  53.      */
  54.     public function chercherResultats(string $departstring $arriveestring $datestring $heurestring $placesTrajetRepository $trajetRepository): Response
  55.     {
  56.         Carbon::setLocale('fr');
  57.         $trajets $trajetRepository->findByRecherche($depart$arrivee$date$places);
  58.         $dateFr Carbon::parse($date);
  59.         $dateTrajet $dateFr->translatedFormat('l d F Y');
  60.         $dateObj = new \DateTimeImmutable($date);
  61.         $autresTrajets $trajetRepository->createQueryBuilder('t')
  62.             ->where('t.dateTrajet = :date')
  63.             ->andWhere('t.arrivee = :arrivee')
  64.             ->andWhere('t.depart != :depart')
  65.             ->andWhere('t.annule != true'// ✅ Exclure les trajets annulés
  66.             ->setParameters([
  67.                 'date' => $dateObj,
  68.                 'arrivee' => $arrivee,
  69.                 'depart' => $depart
  70.             ])
  71.             ->getQuery()
  72.             ->getResult();
  73.         $villes json_decode(file_get_contents(__DIR__ '/../../public/cities.json'), true);
  74.         return $this->render('trajet/chercherResultats.html.twig', [
  75.             'depart' => $depart,
  76.             'arrivee' => $arrivee,
  77.             'dateTrajetFr' => $dateTrajet,
  78.             'dateTrajet' => $date,
  79.             'heure' => $heure,
  80.             'places' => $places,
  81.             'trajets' => $trajets,
  82.             'autresTrajets' => $autresTrajets,
  83.             'villages' => $villes,
  84.         ]);
  85.     }
  86.     /**
  87.      * @Route("/publier", name="app_publier", methods={"GET", "POST"})
  88.      */
  89.     public function publier(Request $requestSessionInterface $sessionEntityManagerInterface $emMailerInterface $mailerStripeConnectService $stripeConnectAfficheService $afficheServiceMetaService $publisher): Response
  90.     {
  91.         if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
  92.             $session->set('_security.main.target_path'$request->getUri());
  93.             $this->addFlash('error''Vous devez être connecté pour publier un trajet.');
  94.             return $this->redirectToRoute('app_login');
  95.         }
  96.         if ($request->isMethod('POST')) {
  97.             $user $this->getUser();
  98.             $rib $user->getDocumentByType('RIB');
  99.             $identite $user->getDocumentByType("identite");
  100.             if (!$rib || !$identite) {
  101.                 if (!$rib)
  102.                     $this->addFlash('error''Vous devez ajouter un RIB.');
  103.                 if (!$identite)
  104.                     $this->addFlash('error''Vous devez ajouter une pièce d’identité.');
  105.                 return $this->redirectToRoute('app_documents');
  106.             }
  107.             if ($rib->getStatus() !== 'approved' || $identite->getStatus() !== 'approved') {
  108.                 $this->addFlash('error''Vos documents doivent être validés par un administrateur.');
  109.                 return $this->redirectToRoute('app_documents');
  110.             }
  111.             $stripeConnect->creerCompteSiBesoin($user);
  112.             $trajet = new Trajet();
  113.             $trajet->setConducteur($user);
  114.             $trajet->setDepart($request->request->get('departure'));
  115.             $trajet->setArrivee($request->request->get('arrival'));
  116.             $trajet->setDateTrajet(new \DateTime($request->request->get('date')));
  117.             $trajet->setHeureTrajet(new \DateTime($request->request->get('heure')));
  118.             $trajet->setPlacesDisponibles((int) $request->request->get('places'));
  119.             $trajet->setPlaces((int) $request->request->get('places'));
  120.             $trajet->setPrix((float) $request->request->get('price'));
  121.             $trajet->setDescription($request->request->get('description'));
  122.             $em->persist($trajet);
  123.             $em->flush();
  124.             $email = (new TemplatedEmail())
  125.                 ->from(new Address('moussa@halogari.yt''HaloGari'))
  126.                 ->to($user->getEmail())
  127.                 ->subject('Votre trajet a été publié')
  128.                 ->htmlTemplate('emails/trajet_publie.html.twig')
  129.                 ->context([
  130.                     'user' => $user,
  131.                     'trajet' => $trajet,
  132.                 ])
  133.                 ->embedFromPath($this->getParameter('kernel.project_dir') . '/public/images/logo.png''logo_halogari');
  134.             $mailer->send($email);
  135.             $this->addFlash('success''Votre trajet a bien été publié !');
  136.             // GÉNÉRATION AFFICHE
  137.             $imagePath $afficheService->generate($trajet);
  138.             $localPath $this->getParameter('kernel.project_dir') . '/public' $imagePath;
  139.             // TEXTE À PUBLIER
  140.             $conducteur $trajet->getConducteur();
  141.             $prenom ucfirst($conducteur->getPrenom());
  142.             // Gestion de l’âge (null safe)
  143.             $age method_exists($conducteur'getAge') && $conducteur->getAge()
  144.                 ? $conducteur->getAge() . ' ans'
  145.                 null;
  146.             // Gestion de la note moyenne (null safe)
  147.             $note method_exists($conducteur'getNoteMoyenne') && $conducteur->getNoteMoyenne()
  148.                 ? number_format($conducteur->getNoteMoyenne(), 1','' ') . ' ⭐'
  149.                 null;
  150.             // Construire la ligne "conducteur"
  151.             $infosConducteur $prenom;
  152.             if ($age || $note) {
  153.                 $infosConducteur .= ' (';
  154.                 if ($age) {
  155.                     $infosConducteur .= $age;
  156.                 }
  157.                 if ($age && $note) {
  158.                     $infosConducteur .= ', ';
  159.                 }
  160.                 if ($note) {
  161.                     $infosConducteur .= $note;
  162.                 }
  163.                 $infosConducteur .= ')';
  164.             }
  165.             // Hashtags ou lien optionnel
  166.             $url sprintf(
  167.                 'https://halogari.yt/chercher/%s/%s/%s/any/1',
  168.                 $trajet->getDepart(),
  169.                 $trajet->getArrivee(),
  170.                 $trajet->getDateTrajet()->format('Y-m-d')
  171.             );
  172.             $hashtags sprintf(
  173.                 "#CovoiturageMayotte #Mayotte #976 #HaloGari #%s #%s",
  174.                 $trajet->getDepart(),
  175.                 $trajet->getArrivee(),
  176.             );
  177.             // Caption final
  178.             $caption sprintf(
  179.                 "🚗 %s\n🟠 %s → 🟢 %s\n📅 %s à %s\n💺 %d place%s dispo • 💰 %s €/place\n\n%s\n%s",
  180.                 $infosConducteur,
  181.                 $trajet->getDepart(),
  182.                 $trajet->getArrivee(),
  183.                 $trajet->getDateTrajet()->format('d/m/Y'),
  184.                 $trajet->getHeureTrajet()->format('H:i'),
  185.                 $trajet->getPlacesDisponibles(),
  186.                 $trajet->getPlacesDisponibles() > 's' '',
  187.                 number_format($trajet->getPrix(), 2','' '),
  188.                 $url,
  189.                 $hashtags
  190.             );
  191.             // PUBLICATION
  192.             try {
  193.                 $publisher->publierSurFacebook($localPath$caption);
  194.             } catch (\Exception $e) {
  195.                 $this->addFlash('warning''La publication Facebook a échoué. L’image a été supprimée automatiquement.');
  196.                 // Pour debug uniquement (désactiver en prod)
  197.                 if ($this->getParameter('kernel.environment') === 'dev') {
  198.                     $this->addFlash('danger''Erreur Facebook : ' $e->getMessage());
  199.                 }
  200.             } finally {
  201.                 if (file_exists($localPath)) {
  202.                     unlink($localPath);
  203.                 }
  204.             }
  205.             return $this->redirectToRoute('app_home');
  206.         }
  207.         return $this->render('trajet/publier.html.twig');
  208.     }
  209.     /**
  210.      * @Route("/trajet/{id}/{ledepart}/{larrive}/{nbPlaceReservee}", name="app_trajet_show")
  211.      */
  212.     public function show(int $idstring $ledepartstring $larrivestring $nbPlaceReserveeTrajetRepository $trajetRepositoryNotesRepository $notesRepository): Response
  213.     {
  214.         Carbon::setLocale('fr');
  215.         // affichage d'un trajet
  216.         $trajet $trajetRepository->findByID($id);
  217.         if ($trajet->isAnnule()) {
  218.             $this->addFlash('error''Ce trajet a été annulé et n\'est plus accessible.');
  219.             return $this->redirectToRoute('app_chercher');
  220.         }
  221.         $now = new \DateTimeImmutable();
  222.         $trajetDateTime = new \DateTimeImmutable($trajet->getDateTrajet()->format('Y-m-d') . ' ' $trajet->getHeureTrajet()->format('H:i'));
  223.         if ($trajetDateTime $now) {
  224.             $this->addFlash('warning''Ce trajet est déjà passé.');
  225.             return $this->redirectToRoute('app_chercher');
  226.         }
  227.         $moyenne $notesRepository->getMoyennePourUtilisateur($trajet->getConducteur());
  228.         $nombreAvis $notesRepository->countAvisPourUtilisateur($trajet->getConducteur());
  229.         $date Carbon::parse($trajet->getDateTrajet());
  230.         $dateTrajet $date->translatedFormat('l d F Y');
  231.         return $this->render('trajet/show.html.twig', [
  232.             'trajet' => $trajet,
  233.             'nbPlaceReservee' => $nbPlaceReservee,
  234.             'moyenne' => $moyenne,
  235.             'nombreAvis' => $nombreAvis,
  236.             'dateTrajet' => $dateTrajet,
  237.         ]);
  238.     }
  239.     /**
  240.      * @Route("/user/trajet/{trajetId}/noter-passager/{passagerId}", name="app_noter_passager")
  241.      */
  242.     public function noterPassager(
  243.         int $trajetId,
  244.         int $passagerId,
  245.         TrajetRepository $trajetRepo,
  246.         UserRepository $userRepo,
  247.         Request $request,
  248.         EntityManagerInterface $em
  249.     ): Response {
  250.         $conducteur $this->getUser();
  251.         $trajet $trajetRepo->find($trajetId);
  252.         $passager $userRepo->find($passagerId);
  253.         if (!$trajet || !$passager) {
  254.             throw $this->createNotFoundException();
  255.         }
  256.         if ($trajet->getConducteur() !== $conducteur) {
  257.             throw $this->createAccessDeniedException();
  258.         }
  259.         // Vérifier que ce passager a réservé ce trajet
  260.         $reservation $em->getRepository(Reservation::class)->findOneBy([
  261.             'trajet' => $trajet,
  262.             'passager' => $passager
  263.         ]);
  264.         if (!$reservation) {
  265.             throw $this->createAccessDeniedException('Ce passager n’a pas réservé ce trajet.');
  266.         }
  267.         // Vérifier s’il a déjà été noté
  268.         $existingNote $em->getRepository(Notes::class)->findOneBy([
  269.             'noteur' => $conducteur,
  270.             'notePour' => $passager,
  271.             'trajet' => $trajet
  272.         ]);
  273.         if ($existingNote) {
  274.             $this->addFlash('info''Vous avez déjà noté ce passager.');
  275.             return $this->redirectToRoute('app_user_trajet', ['id' => $trajetId]);
  276.         }
  277.         $note = new Notes();
  278.         $form $this->createForm(NoteConducteurType::class, $note);
  279.         $form->handleRequest($request);
  280.         if ($form->isSubmitted() && $form->isValid()) {
  281.             $note->setNoteur($conducteur);
  282.             $note->setNotePour($passager);
  283.             $note->setTrajet($trajet);
  284.             $em->persist($note);
  285.             $em->flush();
  286.             $this->addFlash('success''Note enregistrée pour ' $passager->getPrenom() . '.');
  287.             return $this->redirectToRoute('app_user_trajet', ['id' => $trajetId]);
  288.         }
  289.         return $this->render('notes/noter_passager.html.twig', [
  290.             'form' => $form->createView(),
  291.             'trajet' => $trajet,
  292.             'passager' => $passager
  293.         ]);
  294.     }
  295.     /**
  296.      * @Route("/user/trajet/{id}/noter-conducteur", name="app_noter_conducteur")
  297.      */
  298.     public function noterConducteur(
  299.         int $id,
  300.         TrajetRepository $trajetRepo,
  301.         Request $request,
  302.         EntityManagerInterface $em
  303.     ): Response {
  304.         $trajet $trajetRepo->find($id);
  305.         $user $this->getUser();
  306.         // Vérification que l'utilisateur est un passager de ce trajet
  307.         $reservation $em->getRepository(Reservation::class)->findOneBy([
  308.             'trajet' => $trajet,
  309.             'passager' => $user
  310.         ]);
  311.         if (!$reservation) {
  312.             throw $this->createAccessDeniedException('Vous n’avez pas réservé ce trajet.');
  313.         }
  314.         // Empêcher la double notation
  315.         $existingNote $em->getRepository(Notes::class)->findOneBy([
  316.             'noteur' => $user,
  317.             'notePour' => $trajet->getConducteur(),
  318.             'trajet' => $trajet
  319.         ]);
  320.         if ($existingNote) {
  321.             $this->addFlash('info''Vous avez déjà noté ce conducteur pour ce trajet.');
  322.             return $this->redirectToRoute('app_mes_reservations');
  323.         }
  324.         $note = new Notes();
  325.         $form $this->createForm(NoteConducteurType::class, $note);
  326.         $form->handleRequest($request);
  327.         if ($form->isSubmitted() && $form->isValid()) {
  328.             $note->setNoteur($user);
  329.             $note->setNotePour($trajet->getConducteur());
  330.             $note->setTrajet($trajet);
  331.             $em->persist($note);
  332.             $em->flush();
  333.             $this->addFlash('success''Merci pour votre avis !');
  334.             return $this->redirectToRoute('app_mes_reservations');
  335.         }
  336.         return $this->render('notes/noter_conducteur.html.twig', [
  337.             'form' => $form->createView(),
  338.             'trajet' => $trajet
  339.         ]);
  340.     }
  341.     /**
  342.      * Permet au conducteur d’annuler son trajet.
  343.      * @Route("/user/trajet/{id}/annuler", name="trajet_annuler", methods={"GET", "POST"})
  344.      */
  345.     public function annulerTrajet(
  346.         int $id,
  347.         TrajetRepository $trajetRepository,
  348.         TrajetAnnulationService $annulationService
  349.     ): Response {
  350.         $trajet $trajetRepository->find($id);
  351.         if (!$trajet || $trajet->getConducteur() !== $this->getUser()) {
  352.             throw $this->createAccessDeniedException("Accès non autorisé.");
  353.         }
  354.         $annulationService->annulerTrajet($trajet);
  355.         $this->addFlash('success''Le trajet a été annulé et les passagers ont été informés.');
  356.         return $this->redirectToRoute('app_mes_trajets');
  357.     }
  358. }