src/EventSubscriber/PageTemplateFileSubscriber.php line 38

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace App\EventSubscriber;
  3. use App\Entity\PageInterface;
  4. use App\Entity\FormPageInterface;
  5. use Vich\UploaderBundle\Event\Event;
  6. use Vich\UploaderBundle\Event\Events;
  7. use Symfony\Component\DomCrawler\Crawler;
  8. use Symfony\Component\Filesystem\Filesystem;
  9. use Symfony\Component\HttpFoundation\File\File;
  10. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  11. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  12. class PageTemplateFileSubscriber implements EventSubscriberInterface
  13. {
  14.     private $filesystem;
  15.     private $privateTemplatesPath;
  16.     public function __construct(Filesystem $filesystemParameterBagInterface $params)
  17.     {
  18.         $this->filesystem $filesystem;
  19.         $this->privateTemplatesPath $params->get('private_templates_path');
  20.     }
  21.     public static function getSubscribedEvents(): array
  22.     {
  23.         return [
  24.             Events::POST_UPLOAD => ['onVichUploaderPostUpload']
  25.         ];
  26.     }
  27.     /**
  28.      * Alters template files contents.
  29.      *
  30.      * @param Event $event
  31.      * @return void
  32.      */
  33.     public function onVichUploaderPostUpload(Event $event)
  34.     {
  35.         $entity $event->getObject();
  36.         $mappingName $event->getMapping()->getMappingName();
  37.         $supportedMappingName = ['page_template''page_confirmation_template''page_lead_email'];
  38.         if (!$entity instanceof PageInterface ||  !in_array($mappingName$supportedMappingName)) {
  39.             return;
  40.         }
  41.         switch ($mappingName) {
  42.             case 'page_template':
  43.                 /** @var PageInterface $entity */
  44.                 $this->processTemplate($entity$entity->getTemplateFile(), $mappingName);
  45.                 break;
  46.             case 'page_confirmation_template':
  47.                 /** @var FormPageInterface $entity */
  48.                 $this->processTemplate($entity$entity->getConfirmationTemplateFile(), $mappingName);
  49.                 break;
  50.             case 'page_lead_email':
  51.                 /** @var FormPageInterface $entity */
  52.                 $this->copyTemplate($entity$entity->getLeadEmailTemplateFile());
  53.                 break;
  54.         }
  55.     }
  56.     /**
  57.      * Twigifies template file.
  58.      *
  59.      * @param PageInterface $page
  60.      * @param File $file
  61.      * @param string $mappingName
  62.      * @return void
  63.      */
  64.     protected function processTemplate(PageInterface $pageFile $filestring $mappingName) {
  65.         $fileContents file_get_contents($file->getRealPath());
  66.         // Add some custom code.
  67.         $meta '';
  68.         $meta .= '<meta name="robots" content="noarchive, nofollow, noimageindex, noindex, noodp, nosnippet, notranslate, noydir">';
  69.         $meta .= "\n";
  70.         $meta .= '<meta name="desciption" content="{{ page.description }}">';
  71.         $pageHeadEndInclude '{% include("inc/page_head_end.html.twig") %}';
  72.         $fileContents preg_replace('/(<head[^>]*>)(.*?)(<\/head>)/is'"$1 $2 \n $meta \n $pageHeadEndInclude \n $3"$fileContents);
  73.         $pageBodyEndInclude '{% include("inc/page_body_top.html.twig") %}';
  74.         $fileContents preg_replace('/(<body[^>]*>)(.*?)(<\/body>)/is'"$1 \n $pageBodyEndInclude \n $2 $3"$fileContents);
  75.         // Add a csrf token related input.
  76.         // See https://symfony.com/doc/current/security/csrf.html#generating-and-checking-csrf-tokens-manually)
  77.         $csrfInput '<input type="hidden" name="_token" value="{{ csrf_token(\''.$page->getMachineName().'\') }}">';
  78.         $fileContents preg_replace('/(<form[^>]*>)(.*?)(<\/form>)/is'"$1 $2 \n  $csrfInput \n $3"$fileContents);
  79.         // Make the page title dynamic.
  80.         $fileContents preg_replace('/(<title>).*(<\/title>)/is''${1}{{ page.title }}${2}'$fileContents);
  81.         // Restore assets related paths.
  82.         // The tricky thing is about managing srcset.
  83.         // $archiveFilenamePathParts = pathinfo($page->getAssetsArchiveFilename());
  84.         $assetsDirPath 'uploads/assets/'.$page->getFilesystemPath(); //.'/'.$archiveFilenamePathParts['filename'];
  85.         $fileContents preg_replace('/("|,\s)(\.\/)?(dist\/)?(images\/.*?)(\s|")/'"$1{{ asset('$assetsDirPath/$3$4') }}$5"$fileContents);
  86.         $fileContents preg_replace('/(")(\.\/)?(dist\/)?(css\/[^"]*.css|js\/[^"]*.js)(")/'"$1{{ asset('$assetsDirPath/$3$4') }}$5"$fileContents);
  87.         // Add some custom code on the confirmation pages.
  88.         if ('page_confirmation_template' === $mappingName) {
  89.             $fileContents preg_replace('/(<body[^>]*>)(.*?)(<\/body>)/s'"$1 $2 \n {% include('inc/confirm_body_end.html.twig') %} $3"$fileContents);
  90.             $fileContents preg_replace('/(<div id="maniterm-data"[^>]*>)(.*?)(<\/div>)/s'"$1 $2 \n {% include('inc/maniterm_data.html.twig') %} $3"$fileContents);
  91.         } elseif ('page_confirmation_template' !== $mappingName && $page instanceof FormPageInterface)  {
  92.             $this->setFormConfig($page$fileContents);
  93.         }
  94.         $this->copyTemplate($page$file$fileContents);
  95.     }
  96.     /**
  97.      * Crawls the main FormPage template to set
  98.      * a form config. from fields and their attributes.
  99.      *
  100.      * @param FormPageInterface $page
  101.      * @param string $html
  102.      * @return void
  103.      */
  104.     protected function setFormConfig(FormPageInterface $pagestring $html) {
  105.         $formConfig = [];
  106.         $crawler = new Crawler($html);
  107.         // Parse HTML inputs.
  108.         foreach (['input''textarea'] as $tag) {
  109.             $inputs $crawler->filter($tag);
  110.             /** @var \DOMElement $input */
  111.             foreach ($inputs as $input) {
  112.                 $inputType $input->getAttribute('type');
  113.                 $inputName $input->getAttribute('name');
  114.                 if ('submit' === $inputType || '_token' === $inputName) {
  115.                     continue;
  116.                 }
  117.                 // "radio" type must be rendered via ChoiceType.
  118.                 if ($inputType === 'radio') {
  119.                     $inputValue $input->getAttribute('value');
  120.                     if (isset($formConfig[$inputName])) {
  121.                         $formConfig[$inputName]['choices'][$inputValue] = $inputValue;
  122.                     }
  123.                     else {
  124.                         $formConfig[$inputName] = [
  125.                             'type' => 'choice',
  126.                             'required' => $input->hasAttribute('required'),
  127.                             'expanded' => TRUE,
  128.                             'novalidate' => $input->hasAttribute('data-chordflow-novalidate')
  129.                         ];
  130.                         $formConfig[$inputName]['choices'][$inputValue] = $inputValue;
  131.                     }
  132.                 }
  133.                 else {
  134.                     $formConfig[$input->getAttribute('name')] = [
  135.                         'type' => $inputType,
  136.                         'required' => $input->hasAttribute('required'),
  137.                         'pattern' => $input->getAttribute('pattern'),
  138.                     ];
  139.                 }
  140.             }
  141.         }
  142.         // Parse HTML selects.
  143.         $selects $crawler->filter('select');
  144.         /** @var \DOMElement $select */
  145.         foreach ($selects as $select) {
  146.             $selectName $select->getAttribute('name');
  147.             $formConfig[$selectName] = [
  148.                 'type' => 'choice',
  149.                 'required' => $select->hasAttribute('required'),
  150.             ];
  151.             /** @var \DOMElement $option */
  152.             foreach ($crawler->filter('[name="'.$selectName.'"]>option') as $option) {
  153.                 $optionValue $option->getAttribute('value');
  154.                 !$optionValue ?: $formConfig[$selectName]['choices'][$optionValue] = $optionValue;
  155.             }
  156.         }
  157.         $page->setFormConfig($formConfig);
  158.     }
  159.     /**
  160.      * Copy the updated template file into private folder.
  161.      *
  162.      * @param PageInterface $page
  163.      * @param File $file
  164.      * @param string|null $newContent
  165.      * @return void
  166.      */
  167.     private function copyTemplate(PageInterface $pageFile $file, ?string $newContent null): void
  168.     {
  169.         // Creates a file copy in template folder and dump content into the copy
  170.         $newPath implode(DIRECTORY_SEPARATOR, [$this->privateTemplatesPath$page->getFilesystemPath(), $file->getFilename()]);
  171.         $this->filesystem->copy($file->getPathname(), $newPath);
  172.         if ($newContent) {
  173.             $this->filesystem->dumpFile($newPath$newContent);
  174.         }
  175.     }
  176. }