<?php
namespace App\Controller\Page;
use App\Entity\Company;
use App\Entity\Option;
use App\Entity\Site;
use App\Entity\Vacancy;
use App\Event\VacancyEvent;
use App\Exception\UserExistsException;
use App\Form\BaseVacancyCompanyType;
use App\Form\VacancyFormDecorator;
use App\Model\Vacancy\VacancyWrapper;
use App\Renderer\Page;
use App\Renderer\VacancyRenderer;
use App\Service\UserService;
use App\Service\VacancyService;
use Doctrine\ORM\EntityManagerInterface;
use Flagception\Manager\FeatureManagerInterface;
use FOS\HttpCacheBundle\Configuration\Tag;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
#[Route(path: '/vacature')]
class VacancyController extends AbstractController
{
public const URL_PARAM_COVID_19 = 'covid-19';
private Page $pageRenderer;
private VacancyService $service;
private VacancyFormDecorator $vacancyFormDecorator;
private FeatureManagerInterface $featureManager;
private UserService $userService;
private TranslatorInterface $translator;
private EventDispatcherInterface $eventDispatcher;
private VacancyRenderer $vacancyRenderer;
public function __construct(
Page $pageRenderer,
VacancyService $service,
VacancyFormDecorator $vacancyFormDecorator,
FeatureManagerInterface $featureManager,
UserService $userService,
TranslatorInterface $translator,
EventDispatcherInterface $eventDispatcher,
VacancyRenderer $vacancyRenderer
) {
$this->pageRenderer = $pageRenderer;
$this->service = $service;
$this->vacancyFormDecorator = $vacancyFormDecorator;
$this->featureManager = $featureManager;
$this->userService = $userService;
$this->translator = $translator;
$this->eventDispatcher = $eventDispatcher;
$this->vacancyRenderer = $vacancyRenderer;
}
#[Route(path: '/solliciteer/{id}', name: 'external_apply_action')]
public function externalAction(Request $request, int|string $id): Response
{
$request->query->add(['apply' => 1]);
return $this->detailWithExternalId($request, $id);
}
/**
* @Tag("vacancies", expression="'vacancies-'~id")
*
* @param int|string $id the external id
*/
#[Route(path: '/external/{id}', name: 'vacancy_detail_external_id', options: ['expose' => true])]
public function detailWithExternalId(Request $request, int|string $id): Response
{
$vacancy = $this->getDoctrine()->getRepository(Vacancy::class)
->findOneBy(['externalId' => $id])
;
if (!$vacancy) {
$vacancy = $this->getDoctrine()->getRepository(Vacancy::class)
->findOneBy(['externalReference' => $id])
;
}
if (!$vacancy) {
$vacancy = $this->getDoctrine()->getRepository(Vacancy::class)
->findOneBy(['displayableExternalId' => $id])
;
}
if (!$vacancy) {
throw new HttpException('404');
}
$routeParams = array_merge([
'id' => $vacancy->getId(),
'slug' => $vacancy->getSlug(),
], $request->query->all());
return $this->redirectToRoute('vacancy_detail', $routeParams);
}
/**
* @Tag("vacancies")
* @Tag("vacancy-detail", expression="'vacancies-'~id")
*
* @throws LoaderError
* @throws RuntimeError
* @throws SyntaxError
*/
public function detailAction(Request $request): Response
{
$vacancyWrapper = $this->service->getVacancyFromRequest($request);
$vacancy = $vacancyWrapper?->vacancy;
if ($vacancyWrapper && $externalDetailUrl = $vacancyWrapper->vacancy->getExternalDetailUrl()) {
return $this->redirect($externalDetailUrl);
}
// If no vacancy wrapper is created, vacancy is not found
if (!$vacancyWrapper instanceof VacancyWrapper) {
throw $this->createNotFoundException();
}
// If FEATURE_TRANSLATION is enabled, vacancy.title can be falsy which means the vacancy is untranslated
if (!(bool) $vacancy?->getTitle()) {
throw $this->createNotFoundException();
}
return $this->vacancyRenderer
->renderDetail(
$request,
$vacancyWrapper
)
;
}
/**
* @throws LoaderError
* @throws RuntimeError
* @throws SyntaxError
*/
public function create(Request $request, array $config = []): Response
{
if (!$this->featureManager->isActive('feature_vacancy_without_account')) {
return $this->redirectToRoute('homepage');
}
$isCovidVacancy = !empty($config[self::URL_PARAM_COVID_19]) ? $config[self::URL_PARAM_COVID_19] : false;
/** @var Option $covidOption */
$covidOption = $this->getDoctrine()->getRepository(Option::class)->findOneBy([
'internalName' => self::URL_PARAM_COVID_19,
]);
$site = null;
if ($siteId = $request->get('site')) {
$site = $this->getDoctrine()->getRepository(Site::class)->find($siteId);
}
$vacancy = new Vacancy();
$form = $this->createForm(BaseVacancyCompanyType::class, null, [
'decorator' => $this->vacancyFormDecorator,
'vacancy' => $vacancy,
'site' => $site,
'action' => $this->generateUrl($isCovidVacancy ? 'vacancy_create_without_account_covid' : 'vacancy_create_without_account', $request->query->all()),
'covid' => $isCovidVacancy,
]);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
/**
* @var Vacancy $vacancy
* @var Company $company
*/
$vacancy = $form->get('vacancy')->getData();
if ($isCovidVacancy && !$covidOption->getValues()->isEmpty()) {
$vacancy = $vacancy
->addOptionValue($covidOption->getValues()->first())
;
}
$company = $form->get('company')->getData();
$email = $company->getEmail();
$vacancy->setActive(false);
$vacancy->setCompany($company);
try {
$user = $this->userService->createUserFromEmail(
$email,
['ROLE_SITE_COMPANY_USER'],
true,
$config
);
$entityManager = $this->getDoctrine()->getManager();
if ($state = $entityManager->getFilters()->isEnabled('softdeleteable')) {
$entityManager->getFilters()->disable('softdeleteable');
}
$entityManager->persist($company);
$entityManager->persist($vacancy);
$entityManager->flush();
$user->addCompany($company);
$entityManager->persist($user);
$entityManager->flush();
if ($state) {
$entityManager->getFilters()->enable('softdeleteable');
}
$this->eventDispatcher->dispatch(
new VacancyEvent($vacancy),
VacancyEvent::VACANCY_CREATED_WITHOUT_ACCOUNT
);
// redirect to thanks page
try {
return $this->redirectToRoute('vacancy_create_without_account_thanks', ['v' => $vacancy->getId()]);
} catch (\Exception) {
$route = 'vacancy_create_without_account';
if ($isCovidVacancy) {
$route = 'vacancy_create_without_account_covid';
}
return $this->redirectToRoute($route);
}
} catch (UserExistsException) {
$form->get('company')
->get('email')
->addError(
new FormError($this->translator->trans('User already exists'))
);
}
}
$this->addFlash('danger', $this->translator->trans('Cannot create vacancy'));
}
$response = $this->pageRenderer
->renderPage(
'{vacancy_create}',
'@default/pages/create_vacancy.html.twig',
[
'form' => $form->createView(),
'isCovid' => $isCovidVacancy,
]
);
$response->setSharedMaxAge(0);
return $response;
}
/**
* @throws LoaderError
* @throws RuntimeError
* @throws SyntaxError
*/
public function thanks(Request $request, EntityManagerInterface $entityManager): Response
{
$vacancyID = $request->get('v');
$vacancy = $entityManager->getRepository(Vacancy::class)->find($vacancyID);
if (!$vacancy instanceof Vacancy) {
throw $this->createNotFoundException();
}
$response = $this->pageRenderer
->renderPage(
'{vacancy_create_thanks}',
'@default/pages/create_vacancy_thanks.html.twig',
['vacancy' => $vacancy]
);
$response->setSharedMaxAge(0);
return $response;
}
}