src/Controller/CareerController.php line 76

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller;
  4. use App\Api\GoogleCaptchaApi;
  5. use App\Assert\BadRequestAssert;
  6. use App\Entity\Job;
  7. use App\Entity\JobApplicationInterface;
  8. use App\Enum\LocationEnum;
  9. use App\Factory\JobApplicationFactory;
  10. use App\Form\Type\JobApplicationFormType;
  11. use App\Generator\TokenGeneratorInterface;
  12. use App\Repository\JobRepositoryInterface;
  13. use App\Service\EmailSender;
  14. use Carbon\Carbon;
  15. use Doctrine\ORM\EntityManagerInterface;
  16. use Psr\Log\LoggerInterface;
  17. use RuntimeException;
  18. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  19. use Symfony\Component\Form\FormError;
  20. use Symfony\Component\HttpFoundation\File\UploadedFile;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\Mailer\MailerInterface;
  24. use Symfony\Component\Mime\Address;
  25. use Symfony\Component\Mime\Email;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. use Symfony\Contracts\Translation\TranslatorInterface;
  28. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  29. use Symfony\Component\String\Slugger\AsciiSlugger;
  30. use Twig\Environment;
  31. class CareerController extends AbstractController
  32. {
  33.     private EntityManagerInterface $entityManager;
  34.     private JobApplicationFactory $jobApplicationFactory;
  35.     private JobRepositoryInterface $jobRepository;
  36.     private TokenGeneratorInterface $tokenGenerator;
  37.     private Environment $twig;
  38.     private EmailSender $emailSender;
  39.     private GoogleCaptchaApi $googleCaptchaApi;
  40.     private TranslatorInterface $translator;
  41.     public function __construct(
  42.         EntityManagerInterface $entityManager,
  43.         JobApplicationFactory $jobApplicationFactory,
  44.         JobRepositoryInterface $jobRepository,
  45.         TokenGeneratorInterface $tokenGenerator,
  46.         Environment $twig,
  47.         EmailSender $emailSender,
  48.         GoogleCaptchaApi $googleCaptchaApi,
  49.         TranslatorInterface $translator
  50.     ) {
  51.         $this->entityManager $entityManager;
  52.         $this->jobApplicationFactory $jobApplicationFactory;
  53.         $this->jobRepository $jobRepository;
  54.         $this->tokenGenerator $tokenGenerator;
  55.         $this->twig $twig;
  56.         $this->emailSender $emailSender;
  57.         $this->googleCaptchaApi $googleCaptchaApi;
  58.         $this->translator $translator;
  59.     }
  60.     /**
  61.      * @Route("/career", name="career_index")
  62.      */
  63.     public function index(): Response
  64.     {
  65.         $jobs $this->jobRepository->findActive();
  66.         return $this->render('page/career/index/index.html.twig', [
  67.             'jobs' => $jobs,
  68.             'filters' => LocationEnum::toChoices(),
  69.         ]);
  70.     }
  71.     /**
  72.      * @Route("/career/{job}", name="career_show")
  73.      */
  74.     public function show(Request $requestJob $job): Response
  75.     {
  76.         $jobApplication $this->jobApplicationFactory->createForJob($job);
  77.         $form $this->createForm(JobApplicationFormType::class, $jobApplication);
  78.         $form->handleRequest($request);
  79.         if ($form->isSubmitted()) {
  80.             $captchaResponse $this->googleCaptchaApi->getResponse(
  81.                 $request->request->get('g-recaptcha-response') ?? "",
  82.                 $request->getClientIp()
  83.             );
  84.             // Capture the time the form was initially rendered
  85.             $formRenderedAt $request->request->get('form_rendered_at');
  86.             // Calculate the time difference in seconds between when the form was displayed and when it was submitted
  87.             $interactionTime time() - intval($formRenderedAt);
  88.             // Capture the value from the honeypot field
  89.             $honeypotFieldValue $request->request->get('email_repeat');
  90.             if (!$this->googleCaptchaApi->isValid($captchaResponse$interactionTime$honeypotFieldValue)) {
  91.                 $form->addError(new FormError('Invalid captcha!'));
  92.             } elseif ($form->isValid()) {
  93.                 /** @var JobApplicationInterface $jobApplication */
  94.                 $jobApplication $form->getData();
  95.                 /** @var UploadedFile $uploadedFile */
  96.                 $uploadedFile $form->get('cvFile')->getData();
  97.                 BadRequestAssert::same($uploadedFile->getError(), UPLOAD_ERR_OK);
  98.                 $path sprintf(
  99.                     '%s/public/uploads/%s/',
  100.                     $this->getParameter('kernel.project_dir'),
  101.                     $this->getParameter('app.directory.cvs')
  102.                 );
  103.                 if (!is_dir($path) && !mkdir($path0775true) && !is_dir($path)) {
  104.                     throw new RuntimeException(sprintf('Directory "%s" was not created'$path));
  105.                 }
  106.                 $fileName sprintf(
  107.                     '%s.%s',
  108.                     $this->tokenGenerator->generate(),
  109.                     $uploadedFile->getExtension() ?: $uploadedFile->getClientOriginalExtension()
  110.                 );
  111.                 $slugger = new AsciiSlugger();
  112.                 $slug $slugger
  113.                     ->slug(strtolower($jobApplication->getName()))
  114.                     ->toString();
  115.                 $slug substr($slug0max(255 strlen($fileName) - 10));
  116.                 if (!empty($slug)) {
  117.                     $fileName sprintf('%s-%s'$slug$fileName);
  118.                 }
  119.                 $uploadedFile->move($path$fileName);
  120.                 $jobApplication->setCvFilePath($fileName);
  121.                 $jobApplication->setCreatedAt(Carbon::now());
  122.                 $this->entityManager->persist($jobApplication);
  123.                 $this->entityManager->flush();
  124.                 $this->sendEmail(
  125.                     $jobApplication,
  126.                     sprintf('%s/%s'$path$fileName),
  127.                     $request->getUri(),
  128.                     $captchaResponse
  129.                 );
  130.                 $translatedMessage $this->translator->trans('careers.upload_success', [], 'messages');
  131.                 $this->addFlash('success'"$translatedMessage");
  132.                 return $this->renderForm('page/career/show/show.html.twig', [
  133.                     'job' => $job,
  134.                     'form' => $form,
  135.                 ]);
  136.             }
  137.         }
  138.         return $this->renderForm('page/career/show/show.html.twig', [
  139.             'job' => $job,
  140.             'form' => $form,
  141.         ]);
  142.     }
  143.     private function sendEmail(
  144.         JobApplicationInterface $jobApplication,
  145.         string $fullPath,
  146.         string $url,
  147.         array $captchaResponse
  148.     ): void {
  149.         $job $jobApplication->getJob();
  150.         $recipient $job->getLocation()->getMessageEmail();
  151.         if (empty($recipient)) {
  152.             return;
  153.         }
  154.         $content $this->twig->render(
  155.             'email/job_application.html.twig',
  156.             ['jobApplication' => $jobApplication]
  157.         );
  158.         $email = (new Email())
  159.             ->from(new Address('info@icftechnology.com''ICFTechnology.com')) // TODO: .env
  160.             ->to($recipient)
  161.             ->replyTo(new Address($jobApplication->getEmail(), $jobApplication->getName()))
  162.             ->subject('Job application contact form')
  163.             ->attachFromPath($fullPath)
  164.             ->html($content);
  165.         $this->emailSender->send($email$url$captchaResponse);
  166.     }
  167. }