src/Controller/Frontend/ProfileController.php line 21

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Frontend;
  3. use App\Annotation\Log;
  4. use App\Constant\Common;
  5. use App\Entity\Campaign;
  6. use App\Entity\Profile;
  7. use App\Entity\Status;
  8. use App\Exception\BadRequestException;
  9. use App\Misc\CaptchaHelper;
  10. use App\Service\ProfileFileService;
  11. use App\Utilities\ServiceUtil;
  12. use Psr\Log\LoggerInterface;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\Routing\Annotation\Route;
  15. use Symfony\Contracts\Translation\TranslatorInterface;
  16. class ProfileController extends BaseFrontendController
  17. {
  18.     /**
  19.      * @Route("/{_locale}/dossier-inscription/step1", name="profile.step1", methods={"GET"})
  20.      */
  21.     public function profileStep1(TranslatorInterface $translator)
  22.     {
  23.         $siteName $translator->trans('siteName');
  24.         $this->addTitle($translator->trans(
  25.             'profile_step1.title',
  26.             [
  27.                 '%siteName%' => $siteName
  28.             ]
  29.         ));
  30.         $this->setDescription($translator->trans(
  31.             'profile_step1.desc',
  32.             [
  33.                 '%siteName%' => $siteName
  34.             ]
  35.         ));
  36.         // get profile logged in
  37.         $data['formData'] = [
  38.             'errors' => [],
  39.             'inputValues' => []
  40.         ];
  41.         if ($this->getUser()) {
  42.             $data['formData']['inputValues'] = $this->currentService->getProfileByUserId($this->getUser()->getId());
  43.         }
  44.         $data array_merge($data$this->stepData());
  45.         if (isset($data['formData']['inputValues']['year'])) {
  46.             $data['year'] = $data['formData']['inputValues']['year'];
  47.         }
  48.         return $this->render('user/profile/profile_step1.html.twig'$data);
  49.     }
  50.     /**
  51.      * @Route("/{_locale}/dossier-inscription/step2", name="profile.step2", methods={"GET"})
  52.      */
  53.     public function profileStep2(TranslatorInterface $translator)
  54.     {
  55.         if (!$this->getUser()) {
  56.             return $this->redirectToRoute('profile.step1');
  57.         }
  58.         $siteName $translator->trans('siteName');
  59.         $this->addTitle($translator->trans(
  60.             'profile_step1.title',
  61.             [
  62.                 '%siteName%' => $siteName
  63.             ]
  64.         ));
  65.         $this->setDescription($translator->trans(
  66.             'profile_step1.desc',
  67.             [
  68.                 '%siteName%' => $siteName
  69.             ]
  70.         ));
  71.         $data['formData'] = [
  72.             'errors' => [],
  73.             'inputValues' => $this->currentService->getProfileByUserId($this->getUser()->getId())
  74.         ];
  75.         $data array_merge($data$this->stepData());
  76.         if (isset($data['formData']['inputValues']['year'])) {
  77.             $data['year'] = $data['formData']['inputValues']['year'];
  78.         }
  79.         return $this->render('user/profile/profile_step2.html.twig'$data);
  80.     }
  81.     /**
  82.      * @Route("/{_locale}/dossier-inscription/step3", name="profile.step3", methods={"GET"})
  83.      */
  84.     public function profileStep3(TranslatorInterface $translator)
  85.     {
  86.         if (!$this->getUser()) {
  87.             return $this->redirectToRoute('profile.step1');
  88.         }
  89.         $siteName $translator->trans('siteName');
  90.         $this->addTitle($translator->trans(
  91.             'profile_step1.title',
  92.             [
  93.                 '%siteName%' => $siteName
  94.             ]
  95.         ));
  96.         $this->setDescription($translator->trans(
  97.             'profile_step1.desc',
  98.             [
  99.                 '%siteName%' => $siteName
  100.             ]
  101.         ));
  102.         $data['formData'] = [
  103.             'errors' => [],
  104.             'inputValues' => $this->currentService->getProfileByUserId($this->getUser()->getId())
  105.         ];
  106.         $data array_merge($data$this->stepData());
  107.         if (isset($data['formData']['inputValues']['year'])) {
  108.             $data['year'] = $data['formData']['inputValues']['year'];
  109.         }
  110.         return $this->render('user/profile/profile_step3.html.twig'$data);
  111.     }
  112.     /**
  113.      * @Route("/{_locale}/dossier-inscription/step4", name="profile.step4", methods={"GET"})
  114.      */
  115.     public function profileStep4(TranslatorInterface $translator)
  116.     {
  117.         if (!$this->getUser()) {
  118.             return $this->redirectToRoute('profile.step1');
  119.         }
  120.         $siteName $translator->trans('siteName');
  121.         $this->addTitle($translator->trans(
  122.             'profile_step1.title',
  123.             [
  124.                 '%siteName%' => $siteName
  125.             ]
  126.         ));
  127.         $this->setDescription($translator->trans(
  128.             'profile_step1.desc',
  129.             [
  130.                 '%siteName%' => $siteName
  131.             ]
  132.         ));
  133.         $data['formData'] = [
  134.             'errors' => [],
  135.             'inputValues' => $this->currentService->getProfileByUserId($this->getUser()->getId())
  136.         ];
  137.         $data array_merge($data$this->stepData());
  138.         if (isset($data['formData']['inputValues']['year'])) {
  139.             $data['year'] = $data['formData']['inputValues']['year'];
  140.         }
  141.         return $this->render('user/profile/profile_step4.html.twig'$data);
  142.     }
  143.     /**
  144.      * @Route("/{_locale}/profile/step1", name="profile.step1_save", methods={"POST", "PUT"})
  145.      * @Log
  146.      */
  147.     public function profileStep1Save(
  148.         Request $request,
  149.         CaptchaHelper $captchaHelper,
  150.         TranslatorInterface $translator
  151.     ) {
  152.         // new profile
  153.         if ($request->getMethod() === 'POST') {
  154.             // Check captcha is valid
  155.             if ($this->getParameter('captcha_enabled') && !$captchaHelper->isCaptchaValid($request)) {
  156.                 return $this->json(ServiceUtil::processFailed([
  157.                     'errorMessage' => $translator->trans('message.captcha_is_not_valid')
  158.                 ]));
  159.             }
  160.             $campaign $this->campaignRepo->findOneBy(['id' => Campaign::APPLICATION]);
  161.             if ($campaign) {
  162.                 $request->request->set('campaign'$campaign->getId());
  163.             }
  164.             if(!$request->get('programs')){
  165.                 $data $this->stepData();
  166.                 $data['formData'] = [
  167.                     'errors' => [],
  168.                     'inputValues' => $request->request->all()
  169.                 ];
  170.                 $data['valid_programs'] = $translator->trans('message.programme_is_not_valid');
  171.                 return $this->render('user/profile/profile_step1.html.twig'$data);
  172.             }
  173.             try {
  174.                 $this->currentService->addProfile($request);
  175.                 return $this->redirectToRoute('profile.step2', ['new_user'=> 1]);
  176.             } catch (BadRequestException $badRequestException) {
  177.                 $data $this->stepData();
  178.                 $data['formData'] = [
  179.                     'errors' => [],
  180.                     'inputValues' => $request->request->all()
  181.                 ];
  182.                 $error $badRequestException->getMessages();
  183.                 if ($error['entityName'] === 'User') {
  184.                     foreach ($error['data'] as $field => $message) {
  185.                         $data['formData']['errors']['user[' $field ']'] = $message;
  186.                     }
  187.                 }
  188.                 $data['validated'] = true;
  189.                 return $this->render('user/profile/profile_step1.html.twig'$data);
  190.             }
  191.         }
  192.         // update step 1  and ?? go to step 2 ?
  193.         $this->userService->updateProfileUser($request->get('user'));
  194.         $this->currentService->updateProfile($request);
  195.         return $this->redirectToRoute('profile.step2');
  196.     }
  197.     /**
  198.      * @Route("/{_locale}/profile/step2", name="profile.step2_save", methods={"PUT"})
  199.      */
  200.     public function profileStep2Save(Request $request)
  201.     {
  202.         $this->currentService->updateProfile($request'App\DTO\Profile\UpdateProfileStep2Input');
  203.         return $this->redirectToRoute('profile.step3');
  204.     }
  205.     /**
  206.      * @Route("/{_locale}/profile/step3", name="profile.step3_save", methods={"PUT"})
  207.      */
  208.     public function profileStep3Save(Request $request)
  209.     {
  210.         $this->currentService->updateProfile($request'App\DTO\Profile\UpdateProfileStep3Input');
  211.         return $this->redirectToRoute('profile.step4');
  212.     }
  213.     /**
  214.      * @Route("/{_locale}/profile/step4", name="profile.step4_save", methods={"PUT"})
  215.      */
  216.     public function profileStep4Save(Request $request)
  217.     {
  218.         $isSent $request->get('isSent');
  219.         // Step 4 has both plain text user[...] fields (from analyzed document data,
  220.         // landed in the POST body) and a user[media] file upload (landed in the
  221.         // files bag). Merge both so neither is silently dropped.
  222.         $userInput array_merge(
  223.             (array) $request->get('user'),
  224.             array_filter((array) $request->files->get('user'), static fn($f) => null !== $f)
  225.         );
  226.         $this->userService->updateProfileUser($userInput);
  227.         $request->files->remove('user');
  228.         $this->currentService->updateProfile($request'App\DTO\Profile\UpdateProfileStep4Input'true);
  229.         $param = [];
  230.         if(!$isSent){
  231.             $param = ['new_user'=> 1];
  232.         }
  233.         return $this->redirectToRoute('user.application'$param);
  234.     }
  235.     public function stepData()
  236.     {
  237.         $data = [];
  238.         $data['studyLevels'] = $this->studyLevelRepository->findAll();
  239.         $data['cursuses'] = $this->cursusRepository->findAll();
  240.         $data['programsByLevel'] = $this->programService->getActiveProgramGroupByLevel();
  241.         $france $this->countryRepo->find(1);
  242.         $data['countries'] = array_merge([$france], $this->countryRepo->getAll(['except_id' => 1'sort_asc' => 'name'], 'ENTITY'));
  243.         $data['departments'] = array_map(function ($department) {
  244.             return ['value' => $department'text' => $department];
  245.         }, $this->commonService->frenchDepartments);
  246.         $data['campuses'] = $this->campusRepository->getAll(['filter_status' => 1'memberOf_programs' => 'notNull','sort_asc' => 'ordering'], 'ENTITY');
  247.         $year date("Y");
  248.         if (date("Y-m-d") > date("Y") . '-10-01') {
  249.             $data['year'] = date('Y'strtotime('+1 year')) . '-' date('Y'strtotime('+2 year'));
  250.         } else {
  251.             $data['year'] = $year '-' date('Y'strtotime('+1 year'));
  252.         }
  253.         return $data;
  254.     }
  255.     /**
  256.      * @Route("/{_locale}/fiche-de-renseigenement-alternance", name="fiche_de_renseigenement", methods={"GET"})
  257.      */
  258.     public function ficheDeRenseigenement(Request $request)
  259.     {
  260.         $token $request->get('token');
  261.         if (!$token) {
  262.             return $this->render('pages/404.html.twig');
  263.         }
  264.         $tokenStorage explode('_MpTKRipu85cN'$token);
  265.         if (is_array($tokenStorage)) {
  266.             $profile $this->profileRepo->find(base64_decode($tokenStorage[0]));
  267.         } else {
  268.             return $this->render('pages/404.html.twig');
  269.         }
  270.         $data = [];
  271.         $data['profile'] = $this->currentService->autoMapper->map($profile'App\DTO\Profile\ProfileOutput');
  272.         // dd($data['profile']);
  273.         $data['session'] = (int) $profile->getYear() ? explode('-'$profile->getYear())[0] : null;
  274.         $data['contractTypes'] = Common::contractTypes();
  275.         $data['specificPrivate'] = Common::CONTRACT_SPECIFIC_TYPES;
  276.         $data['specificPublic'] = Common::CONTRACT_SPECIFIC_PUBLIC_TYPES;
  277.         $data['employers'] = Common::CONTRACT_SPECIFIC_EMPLOYERS;
  278.         //set default list specifics
  279.         $data['specifics'] =  Common::CONTRACT_SPECIFIC_TYPES;
  280.         if (isset($data['profile']->entreprise['entreprise']['type']) && $data['profile']->entreprise['entreprise']['type'] == 2) {
  281.             $data['specifics'] =  Common::CONTRACT_SPECIFIC_PUBLIC_TYPES;
  282.         }
  283.         $data['sendMail'] = 0;
  284.         if ($request->get('mode') == 'public') {
  285.             $data['sendMail'] = 1;
  286.         }
  287.         return $this->render('fiche/index.html.twig'$data);
  288.     }
  289.     /**
  290.      * @Route("/{_locale}/fiche-save", name="fiche.save", methods={"PUT"})
  291.      */
  292.     public function ficheSave(Request $request)
  293.     {
  294.         $contract $request->get('contract');
  295.         if ($contract) {
  296.             $fullSupport 0;
  297.             $annualCompanyTotal 0;
  298.             if (isset($contract['contract']['annualSupport1'])) {
  299.                 if ($contract['contract']['annualSupport1']) {
  300.                     $fullSupport $fullSupport $contract['contract']['annualSupport1'];
  301.                 }
  302.                 if ($contract['contract']['annualCompany1']) {
  303.                     $annualCompanyTotal $annualCompanyTotal $contract['contract']['annualCompany1'];
  304.                 }
  305.             }
  306.             if (isset($contract['contract']['annualSupport2'])) {
  307.                 if ($contract['contract']['annualSupport2']) {
  308.                     $fullSupport $fullSupport $contract['contract']['annualSupport2'];
  309.                 }
  310.                 if ($contract['contract']['annualCompany2']) {
  311.                     $annualCompanyTotal $annualCompanyTotal $contract['contract']['annualCompany2'];
  312.                 }
  313.             }
  314.             if (isset($contract['contract']['annualSupport3'])) {
  315.                 if ($contract['contract']['annualSupport3']) {
  316.                     $fullSupport $fullSupport $contract['contract']['annualSupport3'];
  317.                 }
  318.                 if ($contract['contract']['annualCompany3']) {
  319.                     $annualCompanyTotal $annualCompanyTotal $contract['contract']['annualCompany3'];
  320.                 }
  321.             }
  322.             $contract['contract']['fullSupport'] = $fullSupport;
  323.             $contract['contract']['annualCompanyTotal'] = $annualCompanyTotal;
  324.             $contract['contract']['totalTrainingCost'] = $fullSupport $annualCompanyTotal;
  325.         }
  326.         $conditions $request->get('entreprise');
  327.         $trainingHours 0;
  328.         if ($conditions) {
  329.             if (isset($conditions['contract']['conditions'])) {
  330.                 foreach ($conditions['contract']['conditions'] as $condition) {
  331.                     $trainingHours $trainingHours $condition['hour'];
  332.                 }
  333.             }
  334.             $contract['contract']['trainingHours'] = $trainingHours;
  335.         }
  336.         $request->request->set('contract'$contract);
  337.         $profile $this->currentService->updateProfile($request'App\DTO\Profile\UpdateProfileFicheInput');
  338.         if ($request->get('sendMail')) {
  339.             $this->userService->sendFicheEmail($this->currentService->autoMapper->map($profile'App\DTO\Profile\ProfileOutput'), 'private');
  340.         }
  341.         return $this->json(ServiceUtil::processSuccessful());
  342.     }
  343.     /**
  344.      * @Route("/qcm-result", name="qcm_result.save", methods={"POST"})
  345.      */
  346.     public function QcmResult(Request $request)
  347.     {
  348.         $response json_decode($request->getContent(), 1);
  349.         if ($response['token'] && $response['email']) {
  350.             $profile $this->currentRepo->getProfileByToken($response['email'], $response['token']);
  351.             if ($profile) {
  352.                 $dataQcmResults = [
  353.                     'isDoneTest' => $response['isDoneTest'],
  354.                     'questions' => $response['questions']
  355.                 ];
  356.                 $profile->setQcmResults($dataQcmResults);
  357.                 $this->currentRepo->save($profile);
  358.             } else {
  359.                 return $this->json(ServiceUtil::processFailed([BadRequestException::NO_ENTITY]));
  360.             }
  361.         } else {
  362.             return $this->json(ServiceUtil::processFailed([BadRequestException::WRONG_INPUT]));
  363.         }
  364.         return $this->json(ServiceUtil::processSuccessful());
  365.     }
  366.     /**
  367.      * @Route("/{_locale}/scolarite", requirements={"_locale": "en|fr"}, defaults={"_locale"="fr"}, name="user.scolarite")
  368.      */
  369.     public function scolarite(TranslatorInterface $translator)
  370.     {
  371.         if (!$this->getUser()) return $this->redirectToRoute('home');
  372.         $userId $this->getUser()->getId();
  373.         $profile $this->profileRepo->getProfileByUserId(['filter_id' => $userId]);
  374.         if($profile['status']['id'] != Status::STATUS_STUDENT_ENROLLED) return $this->redirectToRoute('home');
  375.         $siteName $this->getParameter('site_name');
  376.         $this->addTitle($translator->trans(
  377.             'scolarite.title',
  378.             [
  379.                 '%siteName%' => $siteName
  380.             ]
  381.         ));
  382.         $this->setDescription($translator->trans(
  383.             'scolarite.desc',
  384.             [
  385.                 '%siteName%' => $siteName
  386.             ]
  387.         ));
  388.         return $this->render('scolarite/index.html.twig', ['profile' => $profile]);
  389.     }
  390.     /**
  391.      * @Route("/{_locale}/inscription", requirements={"_locale": "en|fr"}, defaults={"_locale"="fr"}, name="user.inscription")
  392.      */
  393.     public function inscription(TranslatorInterface $translator)
  394.     {
  395.         if (!$this->getUser()) return $this->redirectToRoute('home');
  396.         $userId $this->getUser()->getId();
  397.         $profile $this->profileRepo->getProfileByUserId(['filter_id' => $userId]);
  398.         if($profile['status']['id'] != Status::STATUS_STUDENT_ELIGIBLE) return $this->redirectToRoute('home');
  399.         $siteName $this->getParameter('site_name');
  400.         $this->addTitle($translator->trans(
  401.             'inscription.title',
  402.             [
  403.                 '%siteName%' => $siteName
  404.             ]
  405.         ));
  406.         $this->setDescription($translator->trans(
  407.             'inscription.desc',
  408.             [
  409.                 '%siteName%' => $siteName
  410.             ]
  411.         ));
  412.         if($profile['selectedProgram']['level'] == 3){
  413.             $fileInscription 'Contrat_d_inscription_MASTER_ESTIAM_2026-2027_Paris_new.docx';
  414.         } else{
  415.             $fileInscription 'Contrat_d_inscription_BACHELOR_ESTIAM_2026-2027_Paris_new.docx';
  416.         }
  417.         return $this->render('inscription/index.html.twig', ['fileInscription' => $fileInscription]);
  418.     }
  419.     /**
  420.      * @Route("/profile/upload-file", name="profile.upload_file")
  421.      */
  422.     public function uploadFile(Request $request)
  423.     {
  424.         if (!$this->getUser())  return $this->json(ServiceUtil::processFailed(['message' => "Unauthorized"]));
  425.         $userId $this->getUser()->getId();
  426.         $profile $this->profileRepo->findOneBy(['user' => $userId]);
  427.         $result $this->profileFileService->saveFiles($profile$request);
  428.         $renderedMacro $this->render('scolarite/wapper.macro.twig.html', ['item' => $result[0]]);
  429.         return $this->json(ServiceUtil::processSuccessful([$renderedMacro]));
  430.     }
  431.     /**
  432.      * @Route("/profile/remove-file", name="profile.remove_file")
  433.      */
  434.     public function removeFile(Request $requestTranslatorInterface $translator)
  435.     {
  436.         if (!$this->getUser())  return $this->json(ServiceUtil::processFailed(['message' => "Unauthorized"]));
  437.         $profileFile $this->profileFileService->get($request->request->get('id'));
  438.         $this->profileFileService->removeProfileFilesByProfileFilesId($profileFile);
  439.         return $this->json(ServiceUtil::processSuccessful());
  440.     }
  441.     /**
  442.      * @Route("/api/analyze-file", name="profile.analyze_file", methods={"POST"})
  443.      *
  444.      * Starts document analysis and returns quickly (dedup-cache hit, or a
  445.      * pending token) instead of blocking on the full OpenAI call, which can
  446.      * take longer than the server's request timeout. The actual analysis
  447.      * runs after the response is flushed to the client (see
  448.      * fastcgi_finish_request below); the frontend polls analyzeFileStatus()
  449.      * with the returned token until it's done.
  450.      */
  451.     public function analyzeFile(Request $requestProfileFileService $profileFileService)
  452.     {
  453.         $file $request->files->get('file');
  454.         if (!$file) {
  455.             return $this->json(ServiceUtil::processFailed(['message' => "No file uploaded"]));
  456.         }
  457.         try {
  458.             $result $profileFileService->startAnalyzeFile($file);
  459.         } catch (\Exception $e) {
  460.             return $this->json(ServiceUtil::processFailed(['message' => "Error analyzing file: " $e->getMessage()]));
  461.         }
  462.         if ($result['cached']) {
  463.             return $this->json(ServiceUtil::processSuccessful([$result['data']]));
  464.         }
  465.         $response $this->json(ServiceUtil::processSuccessful([
  466.             ['status' => 'pending''token' => $result['token']]
  467.         ]));
  468.         $response->send();
  469.         if (function_exists('fastcgi_finish_request')) {
  470.             fastcgi_finish_request();
  471.         }
  472.         $profileFileService->runAnalysis($result['mediaId']);
  473.         return $response;
  474.     }
  475.     /**
  476.      * @Route("/api/analyze-file/status/{token}", name="profile.analyze_file_status", methods={"GET"}, requirements={"token"=".+"})
  477.      */
  478.     public function analyzeFileStatus(string $tokenProfileFileService $profileFileService)
  479.     {
  480.         try {
  481.             $status $profileFileService->getAnalysisStatus($token);
  482.             return $this->json(ServiceUtil::processSuccessful([$status]));
  483.         } catch (\Exception $e) {
  484.             return $this->json(ServiceUtil::processFailed(['message' => $e->getMessage()]));
  485.         }
  486.     }
  487. }