vendor/contao/core-bundle/src/Resources/contao/pages/PageRegular.php line 75

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. use Contao\CoreBundle\Exception\NoLayoutSpecifiedException;
  11. use Contao\CoreBundle\Routing\ResponseContext\CoreResponseContextFactory;
  12. use Contao\CoreBundle\Routing\ResponseContext\HtmlHeadBag\HtmlHeadBag;
  13. use Contao\CoreBundle\Routing\ResponseContext\JsonLd\ContaoPageSchema;
  14. use Contao\CoreBundle\Routing\ResponseContext\JsonLd\JsonLdManager;
  15. use Contao\CoreBundle\Routing\ResponseContext\ResponseContext;
  16. use Contao\CoreBundle\Routing\ResponseContext\ResponseContextAccessor;
  17. use Contao\CoreBundle\Util\LocaleUtil;
  18. use Symfony\Component\HttpFoundation\Response;
  19. /**
  20.  * Provide methods to handle a regular front end page.
  21.  *
  22.  * @author Leo Feyer <https://github.com/leofeyer>
  23.  */
  24. class PageRegular extends Frontend
  25. {
  26.     /**
  27.      * @var ResponseContext
  28.      */
  29.     protected $responseContext;
  30.     /**
  31.      * Generate a regular page
  32.      *
  33.      * @param PageModel $objPage
  34.      * @param boolean   $blnCheckRequest
  35.      */
  36.     public function generate($objPage$blnCheckRequest=false)
  37.     {
  38.         $this->prepare($objPage);
  39.         $this->Template->output($blnCheckRequest);
  40.     }
  41.     /**
  42.      * Return a response object
  43.      *
  44.      * @param PageModel $objPage
  45.      * @param boolean   $blnCheckRequest
  46.      *
  47.      * @return Response
  48.      */
  49.     public function getResponse($objPage$blnCheckRequest=false)
  50.     {
  51.         $this->prepare($objPage);
  52.         $response $this->Template->getResponse($blnCheckRequest);
  53.         // Finalize the response context so it cannot be used anymore
  54.         System::getContainer()->get(ResponseContextAccessor::class)->finalizeCurrentContext($response);
  55.         return $response;
  56.     }
  57.     /**
  58.      * Generate a regular page
  59.      *
  60.      * @param PageModel $objPage
  61.      *
  62.      * @internal Do not call this method in your code. It will be made private in Contao 5.0.
  63.      */
  64.     protected function prepare($objPage)
  65.     {
  66.         $GLOBALS['TL_KEYWORDS'] = '';
  67.         $GLOBALS['TL_LANGUAGE'] = LocaleUtil::formatAsLanguageTag($objPage->language);
  68.         $locale LocaleUtil::formatAsLocale($objPage->language);
  69.         $container System::getContainer();
  70.         $container->get('request_stack')->getCurrentRequest()->setLocale($locale);
  71.         $container->get('translator')->setLocale($locale);
  72.         $this->responseContext $container->get(CoreResponseContextFactory::class)->createContaoWebpageResponseContext($objPage);
  73.         System::loadLanguageFile('default');
  74.         // Static URLs
  75.         $this->setStaticUrls();
  76.         // Get the page layout
  77.         $objLayout $this->getPageLayout($objPage);
  78.         /** @var ThemeModel $objTheme */
  79.         $objTheme $objLayout->getRelated('pid');
  80.         // Set the default image densities
  81.         $container->get('contao.image.picture_factory')->setDefaultDensities($objLayout->defaultImageDensities);
  82.         // Store the layout ID
  83.         $objPage->layoutId $objLayout->id;
  84.         // Set the layout template and template group
  85.         $objPage->template $objLayout->template ?: 'fe_page';
  86.         $objPage->templateGroup $objTheme->templates ?? null;
  87.         // Minify the markup
  88.         $objPage->minifyMarkup $objLayout->minifyMarkup;
  89.         // Initialize the template
  90.         $this->createTemplate($objPage$objLayout);
  91.         // Initialize modules and sections
  92.         $arrCustomSections = array();
  93.         $arrSections = array('header''left''right''main''footer');
  94.         $arrModules StringUtil::deserialize($objLayout->modules);
  95.         $arrModuleIds = array();
  96.         // Filter the disabled modules
  97.         foreach ($arrModules as $module)
  98.         {
  99.             if ($module['enable'] ?? null)
  100.             {
  101.                 $arrModuleIds[] = (int) $module['mod'];
  102.             }
  103.         }
  104.         // Get all modules in a single DB query
  105.         $objModules ModuleModel::findMultipleByIds($arrModuleIds);
  106.         if ($objModules !== null || \in_array(0$arrModuleIdstrue))
  107.         {
  108.             $arrMapper = array();
  109.             // Create a mapper array in case a module is included more than once (see #4849)
  110.             if ($objModules !== null)
  111.             {
  112.                 while ($objModules->next())
  113.                 {
  114.                     $arrMapper[$objModules->id] = $objModules->current();
  115.                 }
  116.             }
  117.             foreach ($arrModules as $arrModule)
  118.             {
  119.                 // Disabled module
  120.                 if (!BE_USER_LOGGED_IN && !($arrModule['enable'] ?? null))
  121.                 {
  122.                     continue;
  123.                 }
  124.                 // Replace the module ID with the module model
  125.                 if ($arrModule['mod'] > && isset($arrMapper[$arrModule['mod']]))
  126.                 {
  127.                     $arrModule['mod'] = $arrMapper[$arrModule['mod']];
  128.                 }
  129.                 // Generate the modules
  130.                 if (\in_array($arrModule['col'], $arrSections))
  131.                 {
  132.                     // Filter active sections (see #3273)
  133.                     if ($objLayout->rows != '2rwh' && $objLayout->rows != '3rw' && $arrModule['col'] == 'header')
  134.                     {
  135.                         continue;
  136.                     }
  137.                     if ($objLayout->cols != '2cll' && $objLayout->cols != '3cl' && $arrModule['col'] == 'left')
  138.                     {
  139.                         continue;
  140.                     }
  141.                     if ($objLayout->cols != '2clr' && $objLayout->cols != '3cl' && $arrModule['col'] == 'right')
  142.                     {
  143.                         continue;
  144.                     }
  145.                     if ($objLayout->rows != '2rwf' && $objLayout->rows != '3rw' && $arrModule['col'] == 'footer')
  146.                     {
  147.                         continue;
  148.                     }
  149.                     $this->Template->{$arrModule['col']} .= $this->getFrontendModule($arrModule['mod'], $arrModule['col']);
  150.                 }
  151.                 else
  152.                 {
  153.                     if (!isset($arrCustomSections[$arrModule['col']]))
  154.                     {
  155.                         $arrCustomSections[$arrModule['col']] = '';
  156.                     }
  157.                     $arrCustomSections[$arrModule['col']] .= $this->getFrontendModule($arrModule['mod'], $arrModule['col']);
  158.                 }
  159.             }
  160.         }
  161.         $this->Template->sections $arrCustomSections;
  162.         // Mark RTL languages (see #7171, #3360)
  163.         if ((\ResourceBundle::create($locale'ICUDATA'true)['layout']['characters'] ?? null) == 'right-to-left')
  164.         {
  165.             $this->Template->isRTL true;
  166.         }
  167.         // HOOK: modify the page or layout object
  168.         if (isset($GLOBALS['TL_HOOKS']['generatePage']) && \is_array($GLOBALS['TL_HOOKS']['generatePage']))
  169.         {
  170.             foreach ($GLOBALS['TL_HOOKS']['generatePage'] as $callback)
  171.             {
  172.                 $this->import($callback[0]);
  173.                 $this->{$callback[0]}->{$callback[1]}($objPage$objLayout$this);
  174.             }
  175.         }
  176.         // Set the page title and description AFTER the modules have been generated
  177.         $this->Template->mainTitle $objPage->rootPageTitle;
  178.         $this->Template->pageTitle htmlspecialchars($this->responseContext->get(HtmlHeadBag::class)->getTitle());
  179.         // Remove shy-entities (see #2709)
  180.         $this->Template->mainTitle str_replace('[-]'''$this->Template->mainTitle);
  181.         $this->Template->pageTitle str_replace('[-]'''$this->Template->pageTitle);
  182.         // Meta robots tag
  183.         $this->Template->robots $this->responseContext->get(HtmlHeadBag::class)->getMetaRobots();
  184.         // Do not search the page if the query has a key that is in TL_NOINDEX_KEYS
  185.         if (preg_grep('/^(' implode('|'$GLOBALS['TL_NOINDEX_KEYS']) . ')$/'array_keys($_GET)))
  186.         {
  187.             /** @var JsonLdManager $jsonLdManager */
  188.             $jsonLdManager $this->responseContext->get(JsonLdManager::class);
  189.             if ($jsonLdManager->getGraphForSchema(JsonLdManager::SCHEMA_CONTAO)->has(ContaoPageSchema::class))
  190.             {
  191.                 /** @var ContaoPageSchema $schema */
  192.                 $schema $jsonLdManager->getGraphForSchema(JsonLdManager::SCHEMA_CONTAO)->get(ContaoPageSchema::class);
  193.                 $schema->setNoSearch(true);
  194.             }
  195.         }
  196.         // Fall back to the default title tag
  197.         if (!$objLayout->titleTag)
  198.         {
  199.             $objLayout->titleTag '{{page::pageTitle}} - {{page::rootPageTitle}}';
  200.         }
  201.         // Assign the title and description
  202.         $this->Template->title strip_tags($this->replaceInsertTags($objLayout->titleTag));
  203.         $this->Template->description htmlspecialchars($this->responseContext->get(HtmlHeadBag::class)->getMetaDescription());
  204.         // Body onload and body classes
  205.         $this->Template->onload trim($objLayout->onload);
  206.         $this->Template->class trim($objLayout->cssClass ' ' $objPage->cssClass);
  207.         // Execute AFTER the modules have been generated and create footer scripts first
  208.         $this->createFooterScripts($objLayout$objPage);
  209.         $this->createHeaderScripts($objPage$objLayout);
  210.     }
  211.     /**
  212.      * Get a page layout and return it as database result object
  213.      *
  214.      * @param PageModel $objPage
  215.      *
  216.      * @return LayoutModel
  217.      */
  218.     protected function getPageLayout($objPage)
  219.     {
  220.         $objLayout LayoutModel::findByPk($objPage->layout);
  221.         // Die if there is no layout
  222.         if (null === $objLayout)
  223.         {
  224.             $this->log('Could not find layout ID "' $objPage->layout '"'__METHOD__TL_ERROR);
  225.             throw new NoLayoutSpecifiedException('No layout specified');
  226.         }
  227.         $objPage->hasJQuery $objLayout->addJQuery;
  228.         $objPage->hasMooTools $objLayout->addMooTools;
  229.         // HOOK: modify the page or layout object (see #4736)
  230.         if (isset($GLOBALS['TL_HOOKS']['getPageLayout']) && \is_array($GLOBALS['TL_HOOKS']['getPageLayout']))
  231.         {
  232.             foreach ($GLOBALS['TL_HOOKS']['getPageLayout'] as $callback)
  233.             {
  234.                 $this->import($callback[0]);
  235.                 $this->{$callback[0]}->{$callback[1]}($objPage$objLayout$this);
  236.             }
  237.         }
  238.         return $objLayout;
  239.     }
  240.     /**
  241.      * Create a new template
  242.      *
  243.      * @param PageModel   $objPage
  244.      * @param LayoutModel $objLayout
  245.      */
  246.     protected function createTemplate($objPage$objLayout)
  247.     {
  248.         $this->Template = new FrontendTemplate($objPage->template);
  249.         $this->Template->viewport '';
  250.         $this->Template->framework '';
  251.         $arrFramework StringUtil::deserialize($objLayout->framework);
  252.         // Generate the CSS framework
  253.         if (\is_array($arrFramework) && \in_array('layout.css'$arrFramework))
  254.         {
  255.             $strFramework '';
  256.             if (\in_array('responsive.css'$arrFramework))
  257.             {
  258.                 $this->Template->viewport '<meta name="viewport" content="width=device-width,initial-scale=1.0">' "\n";
  259.             }
  260.             // Wrapper
  261.             if ($objLayout->static)
  262.             {
  263.                 $arrSize StringUtil::deserialize($objLayout->width);
  264.                 if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  265.                 {
  266.                     $arrMargin = array('left'=>'0 auto 0 0''center'=>'0 auto''right'=>'0 0 0 auto');
  267.                     $strFramework .= sprintf('#wrapper{width:%s;margin:%s}'$arrSize['value'] . $arrSize['unit'], $arrMargin[$objLayout->align]);
  268.                 }
  269.             }
  270.             // Header
  271.             if ($objLayout->rows == '2rwh' || $objLayout->rows == '3rw')
  272.             {
  273.                 $arrSize StringUtil::deserialize($objLayout->headerHeight);
  274.                 if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  275.                 {
  276.                     $strFramework .= sprintf('#header{height:%s}'$arrSize['value'] . $arrSize['unit']);
  277.                 }
  278.             }
  279.             $strContainer '';
  280.             // Left column
  281.             if ($objLayout->cols == '2cll' || $objLayout->cols == '3cl')
  282.             {
  283.                 $arrSize StringUtil::deserialize($objLayout->widthLeft);
  284.                 if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  285.                 {
  286.                     $strFramework .= sprintf('#left{width:%s;right:%s}'$arrSize['value'] . $arrSize['unit'], $arrSize['value'] . $arrSize['unit']);
  287.                     $strContainer .= sprintf('padding-left:%s;'$arrSize['value'] . $arrSize['unit']);
  288.                 }
  289.             }
  290.             // Right column
  291.             if ($objLayout->cols == '2clr' || $objLayout->cols == '3cl')
  292.             {
  293.                 $arrSize StringUtil::deserialize($objLayout->widthRight);
  294.                 if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  295.                 {
  296.                     $strFramework .= sprintf('#right{width:%s}'$arrSize['value'] . $arrSize['unit']);
  297.                     $strContainer .= sprintf('padding-right:%s;'$arrSize['value'] . $arrSize['unit']);
  298.                 }
  299.             }
  300.             // Main column
  301.             if ($strContainer)
  302.             {
  303.                 $strFramework .= sprintf('#container{%s}'substr($strContainer0, -1));
  304.             }
  305.             // Footer
  306.             if ($objLayout->rows == '2rwf' || $objLayout->rows == '3rw')
  307.             {
  308.                 $arrSize StringUtil::deserialize($objLayout->footerHeight);
  309.                 if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  310.                 {
  311.                     $strFramework .= sprintf('#footer{height:%s}'$arrSize['value'] . $arrSize['unit']);
  312.                 }
  313.             }
  314.             // Add the layout specific CSS
  315.             if ($strFramework)
  316.             {
  317.                 $this->Template->framework Template::generateInlineStyle($strFramework) . "\n";
  318.             }
  319.         }
  320.         // Overwrite the viewport tag (see #6251)
  321.         if ($objLayout->viewport)
  322.         {
  323.             $this->Template->viewport '<meta name="viewport" content="' $objLayout->viewport '">' "\n";
  324.         }
  325.         $this->Template->mooScripts '';
  326.         // Make sure TL_JAVASCRIPT exists (see #4890)
  327.         if (isset($GLOBALS['TL_JAVASCRIPT']) && \is_array($GLOBALS['TL_JAVASCRIPT']))
  328.         {
  329.             $arrAppendJs $GLOBALS['TL_JAVASCRIPT'];
  330.             $GLOBALS['TL_JAVASCRIPT'] = array();
  331.         }
  332.         else
  333.         {
  334.             $arrAppendJs = array();
  335.             $GLOBALS['TL_JAVASCRIPT'] = array();
  336.         }
  337.         // jQuery scripts
  338.         if ($objLayout->addJQuery)
  339.         {
  340.             $GLOBALS['TL_JAVASCRIPT'][] = 'assets/jquery/js/jquery.min.js|static';
  341.         }
  342.         // MooTools scripts
  343.         if ($objLayout->addMooTools)
  344.         {
  345.             $GLOBALS['TL_JAVASCRIPT'][] = 'assets/mootools/js/mootools.min.js|static';
  346.         }
  347.         // Check whether TL_APPEND_JS exists (see #4890)
  348.         if (!empty($arrAppendJs))
  349.         {
  350.             $GLOBALS['TL_JAVASCRIPT'] = array_merge($GLOBALS['TL_JAVASCRIPT'], $arrAppendJs);
  351.         }
  352.         // Initialize the sections
  353.         $this->Template->header '';
  354.         $this->Template->left '';
  355.         $this->Template->main '';
  356.         $this->Template->right '';
  357.         $this->Template->footer '';
  358.         // Initialize the custom layout sections
  359.         $this->Template->sections = array();
  360.         $this->Template->positions = array();
  361.         if ($objLayout->sections)
  362.         {
  363.             $arrPositions = array();
  364.             $arrSections StringUtil::deserialize($objLayout->sections);
  365.             if (!empty($arrSections) && \is_array($arrSections))
  366.             {
  367.                 foreach ($arrSections as $v)
  368.                 {
  369.                     $arrPositions[$v['position']][$v['id']] = $v;
  370.                 }
  371.             }
  372.             $this->Template->positions $arrPositions;
  373.         }
  374.         // Add the check_cookies image and the request token script if needed
  375.         if ($objPage->alwaysLoadFromCache)
  376.         {
  377.             $GLOBALS['TL_BODY'][] = sprintf('<img src="%s" width="1" height="1" class="invisible" alt aria-hidden="true" onload="this.parentNode.removeChild(this)">'System::getContainer()->get('router')->generate('contao_frontend_check_cookies'));
  378.             $GLOBALS['TL_BODY'][] = sprintf('<script src="%s" async></script>'System::getContainer()->get('router')->generate('contao_frontend_request_token_script'));
  379.         }
  380.         // Default settings
  381.         $this->Template->layout $objLayout;
  382.         $this->Template->language $GLOBALS['TL_LANGUAGE'];
  383.         $this->Template->charset System::getContainer()->getParameter('kernel.charset');
  384.         $this->Template->base Environment::get('base');
  385.         $this->Template->isRTL false;
  386.     }
  387.     /**
  388.      * Create all header scripts
  389.      *
  390.      * @param PageModel   $objPage
  391.      * @param LayoutModel $objLayout
  392.      */
  393.     protected function createHeaderScripts($objPage$objLayout)
  394.     {
  395.         $strStyleSheets '';
  396.         $strCcStyleSheets '';
  397.         $arrStyleSheets StringUtil::deserialize($objLayout->stylesheet);
  398.         $arrFramework StringUtil::deserialize($objLayout->framework);
  399.         // Add the Contao CSS framework style sheets
  400.         if (\is_array($arrFramework))
  401.         {
  402.             foreach ($arrFramework as $strFile)
  403.             {
  404.                 if ($strFile != 'tinymce.css')
  405.                 {
  406.                     $GLOBALS['TL_FRAMEWORK_CSS'][] = 'assets/contao/css/' basename($strFile'.css') . '.min.css';
  407.                 }
  408.             }
  409.         }
  410.         // Make sure TL_USER_CSS is set
  411.         if (!isset($GLOBALS['TL_USER_CSS']) || !\is_array($GLOBALS['TL_USER_CSS']))
  412.         {
  413.             $GLOBALS['TL_USER_CSS'] = array();
  414.         }
  415.         // User style sheets
  416.         if (\is_array($arrStyleSheets) && isset($arrStyleSheets[0]))
  417.         {
  418.             $objStylesheets StyleSheetModel::findByIds($arrStyleSheets);
  419.             if ($objStylesheets !== null)
  420.             {
  421.                 while ($objStylesheets->next())
  422.                 {
  423.                     $media implode(','StringUtil::deserialize($objStylesheets->media));
  424.                     // Overwrite the media type with a custom media query
  425.                     if ($objStylesheets->mediaQuery)
  426.                     {
  427.                         $media $objStylesheets->mediaQuery;
  428.                     }
  429.                     // Style sheets with a CC or a combination of font-face and media-type != all cannot be aggregated (see #5216)
  430.                     if ($objStylesheets->cc || ($objStylesheets->hasFontFace && $media != 'all'))
  431.                     {
  432.                         $strStyleSheet '';
  433.                         // External style sheet
  434.                         if ($objStylesheets->type == 'external')
  435.                         {
  436.                             $objFile FilesModel::findByPk($objStylesheets->singleSRC);
  437.                             if ($objFile !== null)
  438.                             {
  439.                                 $strStyleSheet Template::generateStyleTag(Controller::addFilesUrlTo($objFile->path), $medianull);
  440.                             }
  441.                         }
  442.                         else
  443.                         {
  444.                             $strStyleSheet Template::generateStyleTag(Controller::addAssetsUrlTo('assets/css/' $objStylesheets->name '.css'), $mediamax($objStylesheets->tstamp$objStylesheets->tstamp2$objStylesheets->tstamp3));
  445.                         }
  446.                         if ($objStylesheets->cc)
  447.                         {
  448.                             $strStyleSheet '<!--[' $objStylesheets->cc ']>' $strStyleSheet '<![endif]-->';
  449.                         }
  450.                         $strCcStyleSheets .= $strStyleSheet "\n";
  451.                     }
  452.                     elseif ($objStylesheets->type == 'external')
  453.                     {
  454.                         $objFile FilesModel::findByPk($objStylesheets->singleSRC);
  455.                         if ($objFile !== null)
  456.                         {
  457.                             $GLOBALS['TL_USER_CSS'][] = $objFile->path '|' $media '|static';
  458.                         }
  459.                     }
  460.                     else
  461.                     {
  462.                         $GLOBALS['TL_USER_CSS'][] = 'assets/css/' $objStylesheets->name '.css|' $media '|static|' max($objStylesheets->tstamp$objStylesheets->tstamp2$objStylesheets->tstamp3);
  463.                     }
  464.                 }
  465.             }
  466.         }
  467.         $arrExternal StringUtil::deserialize($objLayout->external);
  468.         // External style sheets
  469.         if (!empty($arrExternal) && \is_array($arrExternal))
  470.         {
  471.             // Get the file entries from the database
  472.             $objFiles FilesModel::findMultipleByUuids($arrExternal);
  473.             $projectDir System::getContainer()->getParameter('kernel.project_dir');
  474.             if ($objFiles !== null)
  475.             {
  476.                 $arrFiles = array();
  477.                 while ($objFiles->next())
  478.                 {
  479.                     if (file_exists($projectDir '/' $objFiles->path))
  480.                     {
  481.                         $arrFiles[] = $objFiles->path '|static';
  482.                     }
  483.                 }
  484.                 // Inject the external style sheets before or after the internal ones (see #6937)
  485.                 if ($objLayout->loadingOrder == 'external_first')
  486.                 {
  487.                     array_splice($GLOBALS['TL_USER_CSS'], 00$arrFiles);
  488.                 }
  489.                 else
  490.                 {
  491.                     array_splice($GLOBALS['TL_USER_CSS'], \count($GLOBALS['TL_USER_CSS']), 0$arrFiles);
  492.                 }
  493.             }
  494.         }
  495.         // Add a placeholder for dynamic style sheets (see #4203)
  496.         $strStyleSheets .= '[[TL_CSS]]';
  497.         // Always add conditional style sheets at the end
  498.         $strStyleSheets .= $strCcStyleSheets;
  499.         // Add a placeholder for dynamic <head> tags (see #4203)
  500.         $strHeadTags '[[TL_HEAD]]';
  501.         // Add the analytics scripts
  502.         if ($objLayout->analytics)
  503.         {
  504.             $arrAnalytics StringUtil::deserialize($objLayout->analyticstrue);
  505.             foreach ($arrAnalytics as $strTemplate)
  506.             {
  507.                 if ($strTemplate)
  508.                 {
  509.                     $objTemplate = new FrontendTemplate($strTemplate);
  510.                     $strHeadTags .= $objTemplate->parse();
  511.                 }
  512.             }
  513.         }
  514.         // Add the user <head> tags
  515.         if ($strHead trim($objLayout->head ?? ''))
  516.         {
  517.             $strHeadTags .= $strHead "\n";
  518.         }
  519.         $this->Template->stylesheets $strStyleSheets;
  520.         $this->Template->head $strHeadTags;
  521.     }
  522.     /**
  523.      * Create all footer scripts
  524.      *
  525.      * @param LayoutModel $objLayout
  526.      * @param PageModel   $objPage
  527.      *
  528.      * @todo Change the method signature to ($objPage, $objLayout) in Contao 5.0
  529.      */
  530.     protected function createFooterScripts($objLayout$objPage null)
  531.     {
  532.         $strScripts '';
  533.         // jQuery
  534.         if ($objLayout->addJQuery)
  535.         {
  536.             $arrJquery StringUtil::deserialize($objLayout->jquerytrue);
  537.             foreach ($arrJquery as $strTemplate)
  538.             {
  539.                 if ($strTemplate)
  540.                 {
  541.                     $objTemplate = new FrontendTemplate($strTemplate);
  542.                     $strScripts .= $objTemplate->parse();
  543.                 }
  544.             }
  545.             // Add a placeholder for dynamic scripts (see #4203)
  546.             $strScripts .= '[[TL_JQUERY]]';
  547.         }
  548.         // MooTools
  549.         if ($objLayout->addMooTools)
  550.         {
  551.             $arrMootools StringUtil::deserialize($objLayout->mootoolstrue);
  552.             foreach ($arrMootools as $strTemplate)
  553.             {
  554.                 if ($strTemplate)
  555.                 {
  556.                     $objTemplate = new FrontendTemplate($strTemplate);
  557.                     $strScripts .= $objTemplate->parse();
  558.                 }
  559.             }
  560.             // Add a placeholder for dynamic scripts (see #4203)
  561.             $strScripts .= '[[TL_MOOTOOLS]]';
  562.         }
  563.         // Add the framework agnostic JavaScripts
  564.         if ($objLayout->scripts)
  565.         {
  566.             $arrScripts StringUtil::deserialize($objLayout->scriptstrue);
  567.             foreach ($arrScripts as $strTemplate)
  568.             {
  569.                 if ($strTemplate)
  570.                 {
  571.                     $objTemplate = new FrontendTemplate($strTemplate);
  572.                     $strScripts .= $objTemplate->parse();
  573.                 }
  574.             }
  575.         }
  576.         // Add a placeholder for dynamic scripts (see #4203, #5583)
  577.         $strScripts .= '[[TL_BODY]]';
  578.         // Add the external JavaScripts
  579.         $arrExternalJs StringUtil::deserialize($objLayout->externalJs);
  580.         // Get the file entries from the database
  581.         $objFiles FilesModel::findMultipleByUuids($arrExternalJs);
  582.         $projectDir System::getContainer()->getParameter('kernel.project_dir');
  583.         if ($objFiles !== null)
  584.         {
  585.             while ($objFiles->next())
  586.             {
  587.                 if (file_exists($projectDir '/' $objFiles->path))
  588.                 {
  589.                     $strScripts .= Template::generateScriptTag($objFiles->pathfalsenull);
  590.                 }
  591.             }
  592.         }
  593.         // Add the custom JavaScript
  594.         if ($objLayout->script)
  595.         {
  596.             $strScripts .= "\n" trim($objLayout->script) . "\n";
  597.         }
  598.         $this->Template->mootools $strScripts;
  599.         $this->Template->jsonLdScripts = function ()
  600.         {
  601.             if (!$this->responseContext->isInitialized(JsonLdManager::class))
  602.             {
  603.                 return '';
  604.             }
  605.             /** @var JsonLdManager $jsonLdManager */
  606.             $jsonLdManager $this->responseContext->get(JsonLdManager::class);
  607.             return $jsonLdManager->collectFinalScriptFromGraphs();
  608.         };
  609.     }
  610. }
  611. class_alias(PageRegular::class, 'PageRegular');