<?php
namespace App\Controller\Page\User;
use App\Decorator\CompanyDecorator;
use App\Entity\Company;
use App\Entity\Page;
use App\Entity\SiteUserData;
use App\Entity\User;
use App\Entity\Vacancy;
use App\Event\CompanyCreatedEvent;
use App\EventListener\FeatureFlagListener;
use App\Form\CompanyType;
use App\Form\RegisterUserType;
use App\Renderer\Page as PageRenderer;
use App\Translation\RuntimeTranslator;
use App\Widget\UserDashboard\UserDashboardWidgetCollection;
use Doctrine\ORM\EntityManagerInterface;
use Flagception\Manager\FeatureManagerInterface;
use FOS\UserBundle\Controller\ResettingController;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Form\Factory\FactoryInterface;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Model\UserInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Error\LoaderError as Twig_Error_Loader;
use Twig\Error\RuntimeError as Twig_Error_Runtime;
use Twig\Error\SyntaxError as Twig_Error_Syntax;
class UserController extends AbstractController
{
public const ROLE_MAPPING = [
'user' => 'ROLE_SITE_USER',
'company' => 'ROLE_SITE_COMPANY_USER',
'mobility' => 'ROLE_SITE_MOBILITY_USER',
];
/** @param RuntimeTranslator $translator */
public function __construct(
private readonly UserManagerInterface $userManager,
private readonly EventDispatcherInterface $eventDispatcher,
private readonly FactoryInterface $registrationFormFactory,
private readonly TranslatorInterface $translator,
private readonly PageRenderer $pageRenderer,
private readonly ResettingController $resettingController,
private readonly CompanyDecorator $companyDecorator,
private readonly FeatureManagerInterface $featureManager,
private readonly RouterInterface $router,
private readonly ParameterBagInterface $parameterBag,
private readonly EntityManagerInterface $entityManager,
private readonly UserDashboardWidgetCollection $widgetCollection,
) {
}
/**
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/
#[Route(path: '/', name: 'pages_user_dashboard')]
public function defaultAction(): Response
{
/** @var User $user */
$user = $this->getUser();
if (
$this->featureManager->isActive(FeatureFlagListener::FEATURE_MOBILITY_PLATFORM) &&
$user->hasRole(self::ROLE_MAPPING['mobility'])
) {
return $this->renderMobilityDashboard();
}
if ($user->hasRole(self::ROLE_MAPPING['company'])) {
return $this->getCompanyDashboard();
}
if ($user->hasRole(self::ROLE_MAPPING['user'])) {
if (!$this->parameterBag->get('site_user_active')) {
return $this->redirectToRoute('homepage');
}
return $this->getUserDashboard();
}
throw new AccessDeniedException();
}
/**
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/
#[Route(path: '/register/{type}', name: 'pages_user_register', requirements: ['type' => 'user|company'])]
public function registerAction(Request $request, string $type): Response
{
if ('company' === $type && !$this->parameterBag->get('site_user_enable_company_registration')) {
$this->addFlash('error', $this->translator->trans('This action is not permitted'));
return $this->redirectToRoute('user_login');
}
/** @var User $user */
$user = $this->userManager->createUser();
$user->setEnabled(true);
$event = new GetResponseUserEvent($user, $request);
$this->eventDispatcher->dispatch($event, FOSUserEvents::REGISTRATION_INITIALIZE);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $this->createForm(RegisterUserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$event = new FormEvent($form, $request);
$this->eventDispatcher->dispatch($event, FOSUserEvents::REGISTRATION_SUCCESS);
$user->setRoles([self::ROLE_MAPPING[$type]]);
$this->userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_registration_confirmed');
$response = new RedirectResponse($url);
}
$this->eventDispatcher->dispatch(
new FilterUserResponseEvent($user, $request, $response),
FOSUserEvents::REGISTRATION_COMPLETED
);
if ('company' === $type) {
$response = new RedirectResponse($this->generateUrl('user_login'));
}
$this->addFlash('success', str_replace(
'%email%',
$user->getEmail(),
$this->translator->getCatalogue()->get('registration.check_email', 'FOSUserBundle')
));
return $response;
}
$page = (new Page())
->setTitle('register')
->setBody($this->renderView('@default/pages/user_register.html.twig', [
'form' => $form->createView(),
'type' => $type,
]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
#[Route('register_headless/{type}', name: 'register_user_headless')]
public function headless(Request $request, string $type): Response
{
/** @var User $user */
$user = $this->userManager->createUser();
$user->setEnabled(true);
$event = new GetResponseUserEvent($user, $request);
$this->eventDispatcher->dispatch($event, FOSUserEvents::REGISTRATION_INITIALIZE);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $this->createForm(RegisterUserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$event = new FormEvent($form, $request);
$url = $this->generateUrl('fos_user_registration_confirmed');
$this->eventDispatcher->dispatch($event, FOSUserEvents::REGISTRATION_SUCCESS);
$user->setRoles([self::ROLE_MAPPING[$type]]);
$this->userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$response = new JsonResponse([
'redirect' => $url,
]);
}
$this->eventDispatcher->dispatch(
new FilterUserResponseEvent($user, $request, $response),
FOSUserEvents::REGISTRATION_COMPLETED
);
if ('company' === $type) {
$response = new JsonResponse([
'redirect' => $this->generateUrl('user_login'),
]);
}
$this->addFlash('success', str_replace(
'%email%',
$user->getEmail(),
$this->translator->getCatalogue()->get('registration.check_email', 'FOSUserBundle')
));
if ($request->isXmlHttpRequest()) {
return $response;
}
return new RedirectResponse($url);
}
return $this->render('@default/pages/form/register_user_form_headless.html.twig', [
'form' => $form->createView(),
]);
}
#[Route(path: '/reset/{token}', name: 'fos_user_resetting_reset')]
public function resetAction(Request $request, $token): Response
{
if (!$user = $this->userManager->findUserByConfirmationToken($token)) {
return new RedirectResponse($this->router->generate('user_login'));
}
$event = new GetResponseUserEvent($user, $request);
$this->eventDispatcher->dispatch($event, FOSUserEvents::RESETTING_RESET_INITIALIZE);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $this->registrationFormFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$event = new FormEvent($form, $request);
$this->eventDispatcher->dispatch($event, FOSUserEvents::RESETTING_RESET_SUCCESS);
$this->userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('pages_user_dashboard');
$response = new RedirectResponse($url);
}
$this->eventDispatcher->dispatch(
new FilterUserResponseEvent($user, $request, $response),
FOSUserEvents::RESETTING_RESET_COMPLETED
);
return $response;
}
$page = (new Page())
->setTitle('Check your email')
->setBody($this->renderView('pages/user_reset.html.twig', [
'token' => $token,
'form' => $form->createView(),
]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
#[Route(path: '/check-email', name: 'fos_user_resetting_check_email')]
public function checkMailAction(): Response
{
$page = (new Page())
->setTitle('Check you email')
->setBody($this->renderView('pages/check_email.html.twig', [
'tokenLifetime' => ceil($this->parameterBag->get('fos_user.resetting.retry_ttl') / 3600),
]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
#[Route(path: '/forgot-password', name: 'pages_user_forgot_password')]
public function forgotPasswordAction(Request $request): Response
{
if ($request->get('username')) {
$response = $this->resettingController->sendEmailAction($request);
if ($response instanceof RedirectResponse) {
return $response;
}
}
$page = (new Page())
->setTitle('Forgot password')
->setBody($this->renderView('pages/forgot_password.html.twig'))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
/**
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/
#[Route(path: '/company/create', name: 'pages_users_create_company')]
public function createCompanyAction(Request $request): Response
{
if ($this->getUser()?->getCompanies()->count() > 0) {
$this->addFlash('info', $this->translator->trans('A company is already registered for your account', [], 'company'));
return $this->redirectToRoute('pages_user_dashboard');
}
$company = new Company();
$form = $this->createForm(
CompanyType::class,
$company,
['decorator' => $this->companyDecorator]
);
$form->remove('canonicalUrl');
$form->remove('hero');
$form->remove('overviewImage');
$form->remove('optionValues');
$form->remove('metaTitle');
$form->remove('metaDescription');
$form->get('logo')->remove('metaInformation');
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$this->entityManager->persist($company);
$this->entityManager->flush();
/** @var User $user */
$user = $this->getUser();
$user->addCompany($company);
$this->entityManager->persist($user);
$this->entityManager->flush();
$this->addFlash('success', $this->translator->trans('Company is created', [], 'company'));
$this->eventDispatcher->dispatch(new CompanyCreatedEvent($company), CompanyCreatedEvent::CREATED_BY_USER);
return $this->redirectToRoute('pages_user_dashboard');
}
$this->addFlash('danger', $this->translator->trans('Form is not valid', [], 'company'));
}
$page = (new Page())
->setTitle('register')
->setBody($this->renderView('@default/pages/company_form.html.twig', [
'form' => $form->createView(),
]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
#[Route(path: '/user/delete', name: 'pages_users_user_delete')]
public function deleteUserAction(): Response
{
if (!$user = $this->getUser()) {
throw $this->createNotFoundException();
}
$userSiteData = $this->entityManager
->getRepository(SiteUserData::class)->findOneBy(['user' => $user]);
if ($userSiteData) {
$this->entityManager->remove($userSiteData);
}
$this->entityManager->remove($user);
$this->entityManager->flush();
$this->addFlash('success', 'Your account has been deleted!');
return $this->redirectToRoute('user_login');
}
/**
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/
private function getCompanyDashboard(): Response
{
$companyIds = $this->getUser()?->getCompanies()->map(function (Company $company) {
return $company->getId();
})->toArray();
if (empty($companyIds)) {
$this->addFlash(
'info',
$this->translator->trans('Register your company before adding vacancies', [], 'company')
);
return $this->redirectToRoute('pages_users_create_company');
}
$latestVacancies = $this->entityManager->getRepository(Vacancy::class)->findBy([
'company' => $companyIds,
], ['created' => 'desc'], 5);
$page = (new Page())
->setTitle('User dashboard')
->setBody($this->renderView('@default/pages/company_dashboard.html.twig', [
'latest_vacancies' => $latestVacancies,
'company' => $this->getUser()?->getCompanies()->first(),
]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
private function getUserDashboard(): Response
{
$siteUserData = $this->entityManager->getRepository(SiteUserData::class)->findOneBy(['user' => $this->getUser()]);
$page = (new Page())
->setTitle('User dashboard')
->setBody($this->renderView('@default/pages/user_dashboard.html.twig', [
'siteUserData' => $siteUserData, // Legacy
'widgets' => $this->widgetCollection->getActiveWidgets(),
]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
#[Route(path: '/register/confirm/{token}', name: 'fos_user_registration_confirm')]
public function confirmAction(Request $request): Response
{
return $this->forward(
'fos_user.registration.controller:confirmAction',
$request->get('_route_params')
);
}
#[Route(path: 'register/confirmed', name: 'fos_user_registration_confirmed')]
public function confirmedAction(): Response
{
$user = $this->getUser();
if (!\is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
$page = (new Page())
->setTitle('User dashboard')
->setBody($this->renderView('@default/pages/confirmed.html.twig', [
'user' => $user,
]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
#[Route(path: '/validate_email', name: 'user_validate_email', options: ['expose' => true])]
public function validateEmailAddress(Request $request): Response
{
if (!$email = $request->get('email')) {
return new JsonResponse([
'success' => false,
'message' => 'No email address was provided',
], 400);
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $email]);
return new JsonResponse([
'success' => true,
'exists' => !empty($user),
]);
}
private function renderMobilityDashboard(): Response
{
$user = $this->getUser();
$page = (new Page())
->setTitle('Mobility dashboard')
->setBody($this->renderView('@default/pages/mobility_dashboard.html.twig', ['user' => $user]))
;
return $this->render('@default/pages/pages_index.html.twig', [
'header' => $this->pageRenderer->getHeader(),
'footer' => $this->pageRenderer->getFooter(),
'page' => $page,
]);
}
}