<?php
namespace App\Controller;
use App\Entity\FormPageInterface;
use App\Entity\Lead;
use App\Entity\PageInterface;
use App\Form\LeadType;
use App\Message\FacebookPageViewConversionMessage;
use App\Repository\LeadRepository;
use App\Repository\PageRepository;
use App\Service\SiteManager;
use App\Service\CookieConsentCookieManager;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
class PageController extends AbstractController
{
private const UPLOAD_DIR = 'uploads';
protected SiteManager $siteManager;
protected Request $request;
public function __construct(SiteManager $siteManager, RequestStack $requestStack) {
$this->siteManager = $siteManager;
$this->request = $requestStack->getCurrentRequest();
}
public function __invoke(PageInterface $contentDocument, ManagerRegistry $doctrine, PageRepository $pageRepository, LeadRepository $leadRepository, MessageBusInterface $bus): Response
{
$page = $contentDocument;
$isPost = $this->request->isMethod('POST');
if ($isPost) {
// Forward API requests to a dedicated controller.
$submittedData = $this->request->request->all();
$submittedToken = $submittedData['_token'] ?? null;
if (!isset($submittedData['_token'])) {
// We assume a submission without CSRF protection is a signed API request.
$response = $this->forward('App\Controller\ApiController', [
'contentDocument' => $contentDocument,
'managerRegistry' => $doctrine,
'pageRepository' => $pageRepository,
'leadRepository' => $leadRepository,
'messageBusInterface' => $bus,
'request' => $this->request,
]);
return $response;
}
}
if (!$page) {
throw $this->createNotFoundException('The page does not exist');
}
if (!$page->isPublished() && null === $this->getUser()) {
throw $this->createAccessDeniedException('The page does not exist');
}
// Prepare templates variables.
$queryParams = $this->request->query->all();
$templateBasePath = self::UPLOAD_DIR.'/'.$page->getFilesystemPath().DIRECTORY_SEPARATOR;
// Manage forms.
if ($page instanceof FormPageInterface) {
$formConfig = $page->getFormConfig();
// Deny access to the form page if no email field is defined and no query param. defines it neither.
if (!isset($formConfig['email']) && !isset($queryParams['email']) && !isset($queryParams['mail'])) {
throw $this->createNotFoundException('This page does not exist');
}
// Start managing form submission.
if ($isPost) {
// Submissions can be validated though a CSRF token,
// or, if programmatically posted, via a computed sihgnature.
$validSubmission = FALSE;
// Manually verify the CSRF token.
// https://symfony.com/doc/current/security/csrf.html#generating-and-checking-csrf-tokens-manually
if ($submittedToken && $this->isCsrfTokenValid($page->getMachineName(), $submittedToken)) {
unset($submittedData['_token']);
$validSubmission = true;
}
if ($validSubmission) {
// Instanciate and start populate a Lead.
$lead = new Lead;
$lead->setFormPage($page);
$lead->setQueryParams($queryParams);
$cookies = $this->request->cookies->all();
$cookies = array_filter($cookies, function($key) {
return in_array($key, ['CookieConsent']);
}, ARRAY_FILTER_USE_KEY);
if (!empty($cookies['CookieConsent'])) {
$cookies['CookieConsent'] = CookieConsentCookieManager::parse($cookies['CookieConsent']);
}
$lead->setCookies($cookies);
$form = $this->createForm(LeadType::class, $lead, [
'config' => $page->getFormConfig(),
'data_class' => Lead::class,
]);
$form->submit($submittedData);
// Validate form values.
if ($form->isSubmitted() && $form->isValid()) {
// Manage duplicates.
$email = $lead->getEmail();
if (!$email || ($email && !$clone = $leadRepository->findDuplicate($email))) {
$entityManager = $doctrine->getManager();
$entityManager->persist($lead);
$entityManager->flush();
}
// Render the conformation template.
return $this->render($templateBasePath.$page->getConfirmationTemplateFilename(), [
'lead' => $clone ?? $lead,
'page' => $page,
'query_params' => $lead->getQueryParams(),
]);
}
}
}
$config = $page->getConfig()->getFacebook();
$accessToken = $config->getAccessToken();
$pixelId = $config->getPixelId();
if ($accessToken && $pixelId) {
$bus->dispatch(new FacebookPageViewConversionMessage(
$page->getId(),
$accessToken,
$pixelId,
$this->request->getClientIp(),
$this->request->headers->get('User-Agent'),
$this->request->query->get('fbclid'),
$this->request->cookies->get('_fbp')
));
}
}
// Render the page template.
return $this->render($templateBasePath.$page->getTemplateFilename(), [
'page' => $page,
'query_params' => $queryParams,
]);
}
}