vendor/contao/core-bundle/src/Resources/contao/library/Contao/Template.php line 150

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\Image\Studio\FigureRenderer;
  11. use Contao\CoreBundle\Routing\ResponseContext\JsonLd\JsonLdManager;
  12. use Contao\CoreBundle\Routing\ResponseContext\ResponseContext;
  13. use Contao\CoreBundle\Routing\ResponseContext\ResponseContextAccessor;
  14. use Contao\Image\ImageInterface;
  15. use Contao\Image\PictureConfiguration;
  16. use MatthiasMullie\Minify\CSS;
  17. use MatthiasMullie\Minify\JS;
  18. use Spatie\SchemaOrg\Graph;
  19. use Symfony\Component\HttpFoundation\Response;
  20. use Symfony\Component\VarDumper\VarDumper;
  21. /**
  22.  * Parses and outputs template files
  23.  *
  24.  * The class supports loading template files, adding variables to them and then
  25.  * printing them to the screen. It functions as abstract parent class for the
  26.  * two core classes "BackendTemplate" and "FrontendTemplate".
  27.  *
  28.  * Usage:
  29.  *
  30.  *     $template = new BackendTemplate();
  31.  *     $template->name = 'Leo Feyer';
  32.  *     $template->output();
  33.  *
  34.  * @property string       $style
  35.  * @property array|string $cssID
  36.  * @property string       $class
  37.  * @property string       $inColumn
  38.  * @property string       $headline
  39.  * @property array        $hl
  40.  * @property string       $content
  41.  * @property string       $action
  42.  * @property string       $enforceTwoFactor
  43.  * @property string       $targetPath
  44.  * @property string       $message
  45.  * @property string       $href
  46.  * @property string       $twoFactor
  47.  * @property string       $explain
  48.  * @property string       $active
  49.  * @property string       $enableButton
  50.  * @property string       $disableButton
  51.  * @property boolean      $enable
  52.  * @property boolean      $isEnabled
  53.  * @property string       $secret
  54.  * @property string       $textCode
  55.  * @property string       $qrCode
  56.  * @property string       $scan
  57.  * @property string       $verify
  58.  * @property string       $verifyHelp
  59.  * @property boolean      $showBackupCodes
  60.  * @property array        $backupCodes
  61.  * @property boolean      $trustedDevicesEnabled
  62.  * @property array        $trustedDevices
  63.  * @property string       $currentDevice
  64.  *
  65.  * @author Leo Feyer <https://github.com/leofeyer>
  66.  */
  67. abstract class Template extends Controller
  68. {
  69.     use TemplateInheritance;
  70.     /**
  71.      * Output buffer
  72.      * @var string
  73.      */
  74.     protected $strBuffer;
  75.     /**
  76.      * Content type
  77.      * @var string
  78.      */
  79.     protected $strContentType;
  80.     /**
  81.      * Template data
  82.      * @var array
  83.      */
  84.     protected $arrData = array();
  85.     /**
  86.      * Valid JavaScipt types
  87.      * @var array
  88.      * @see http://www.w3.org/TR/html5/scripting-1.html#scriptingLanguages
  89.      */
  90.     protected static $validJavaScriptTypes = array
  91.     (
  92.         'application/ecmascript',
  93.         'application/javascript',
  94.         'application/x-ecmascript',
  95.         'application/x-javascript',
  96.         'text/ecmascript',
  97.         'text/javascript',
  98.         'text/javascript1.0',
  99.         'text/javascript1.1',
  100.         'text/javascript1.2',
  101.         'text/javascript1.3',
  102.         'text/javascript1.4',
  103.         'text/javascript1.5',
  104.         'text/jscript',
  105.         'text/livescript',
  106.         'text/x-ecmascript',
  107.         'text/x-javascript',
  108.     );
  109.     /**
  110.      * Create a new template object
  111.      *
  112.      * @param string $strTemplate    The template name
  113.      * @param string $strContentType The content type (defaults to "text/html")
  114.      */
  115.     public function __construct($strTemplate=''$strContentType='text/html')
  116.     {
  117.         parent::__construct();
  118.         $this->strTemplate $strTemplate;
  119.         $this->strContentType $strContentType;
  120.     }
  121.     /**
  122.      * Set an object property
  123.      *
  124.      * @param string $strKey   The property name
  125.      * @param mixed  $varValue The property value
  126.      */
  127.     public function __set($strKey$varValue)
  128.     {
  129.         $this->arrData[$strKey] = $varValue;
  130.     }
  131.     /**
  132.      * Return an object property
  133.      *
  134.      * @param string $strKey The property name
  135.      *
  136.      * @return mixed The property value
  137.      */
  138.     public function __get($strKey)
  139.     {
  140.         if (isset($this->arrData[$strKey]))
  141.         {
  142.             if (\is_object($this->arrData[$strKey]) && \is_callable($this->arrData[$strKey]))
  143.             {
  144.                 return $this->arrData[$strKey]();
  145.             }
  146.             return $this->arrData[$strKey];
  147.         }
  148.         return parent::__get($strKey);
  149.     }
  150.     /**
  151.      * Execute a callable and return the result
  152.      *
  153.      * @param string $strKey    The name of the key
  154.      * @param array  $arrParams The parameters array
  155.      *
  156.      * @return mixed The callable return value
  157.      *
  158.      * @throws \InvalidArgumentException If the callable does not exist
  159.      */
  160.     public function __call($strKey$arrParams)
  161.     {
  162.         if (!isset($this->arrData[$strKey]) || !\is_callable($this->arrData[$strKey]))
  163.         {
  164.             throw new \InvalidArgumentException("$strKey is not set or not a callable");
  165.         }
  166.         return \call_user_func_array($this->arrData[$strKey], $arrParams);
  167.     }
  168.     /**
  169.      * Check whether a property is set
  170.      *
  171.      * @param string $strKey The property name
  172.      *
  173.      * @return boolean True if the property is set
  174.      */
  175.     public function __isset($strKey)
  176.     {
  177.         return isset($this->arrData[$strKey]);
  178.     }
  179.     /**
  180.      * Set the template data from an array
  181.      *
  182.      * @param array $arrData The data array
  183.      */
  184.     public function setData($arrData)
  185.     {
  186.         $this->arrData $arrData;
  187.     }
  188.     /**
  189.      * Return the template data as array
  190.      *
  191.      * @return array The data array
  192.      */
  193.     public function getData()
  194.     {
  195.         return $this->arrData;
  196.     }
  197.     /**
  198.      * Set the template name
  199.      *
  200.      * @param string $strTemplate The template name
  201.      */
  202.     public function setName($strTemplate)
  203.     {
  204.         $this->strTemplate $strTemplate;
  205.     }
  206.     /**
  207.      * Return the template name
  208.      *
  209.      * @return string The template name
  210.      */
  211.     public function getName()
  212.     {
  213.         return $this->strTemplate;
  214.     }
  215.     /**
  216.      * Set the output format
  217.      *
  218.      * @param string $strFormat The output format
  219.      */
  220.     public function setFormat($strFormat)
  221.     {
  222.         $this->strFormat $strFormat;
  223.     }
  224.     /**
  225.      * Return the output format
  226.      *
  227.      * @return string The output format
  228.      */
  229.     public function getFormat()
  230.     {
  231.         return $this->strFormat;
  232.     }
  233.     /**
  234.      * Print all template variables to the screen using print_r
  235.      *
  236.      * @deprecated Deprecated since Contao 4.3, to be removed in Contao 5.
  237.      *             Use Template::dumpTemplateVars() instead.
  238.      */
  239.     public function showTemplateVars()
  240.     {
  241.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\Template::showTemplateVars()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Template::dumpTemplateVars()" instead.');
  242.         $this->dumpTemplateVars();
  243.     }
  244.     /**
  245.      * Print all template variables to the screen using the Symfony VarDumper component
  246.      */
  247.     public function dumpTemplateVars()
  248.     {
  249.         VarDumper::dump($this->arrData);
  250.     }
  251.     /**
  252.      * Parse the template file and return it as string
  253.      *
  254.      * @return string The template markup
  255.      */
  256.     public function parse()
  257.     {
  258.         if (!$this->strTemplate)
  259.         {
  260.             return '';
  261.         }
  262.         // HOOK: add custom parse filters
  263.         if (isset($GLOBALS['TL_HOOKS']['parseTemplate']) && \is_array($GLOBALS['TL_HOOKS']['parseTemplate']))
  264.         {
  265.             foreach ($GLOBALS['TL_HOOKS']['parseTemplate'] as $callback)
  266.             {
  267.                 $this->import($callback[0]);
  268.                 $this->{$callback[0]}->{$callback[1]}($this);
  269.             }
  270.         }
  271.         return $this->inherit();
  272.     }
  273.     /**
  274.      * Parse the template file and print it to the screen
  275.      *
  276.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  277.      *             Use Template::getResponse() instead.
  278.      */
  279.     public function output()
  280.     {
  281.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\Template::output()" has been deprecated and will no longer work in Contao 5.0. Use "Contao\Template::getResponse()" instead.');
  282.         $this->compile();
  283.         header('Content-Type: ' $this->strContentType '; charset=' System::getContainer()->getParameter('kernel.charset'));
  284.         echo $this->strBuffer;
  285.     }
  286.     /**
  287.      * Return a response object
  288.      *
  289.      * @return Response The response object
  290.      */
  291.     public function getResponse()
  292.     {
  293.         $this->compile();
  294.         $response = new Response($this->strBuffer);
  295.         $response->headers->set('Content-Type'$this->strContentType);
  296.         $response->setCharset(System::getContainer()->getParameter('kernel.charset'));
  297.         return $response;
  298.     }
  299.     /**
  300.      * Return a route relative to the base URL
  301.      *
  302.      * @param string $strName   The route name
  303.      * @param array  $arrParams The route parameters
  304.      *
  305.      * @return string The route
  306.      */
  307.     public function route($strName$arrParams=array())
  308.     {
  309.         $strUrl System::getContainer()->get('router')->generate($strName$arrParams);
  310.         $strUrl substr($strUrl, \strlen(Environment::get('path')) + 1);
  311.         return StringUtil::ampersand($strUrl);
  312.     }
  313.     /**
  314.      * Return the preview route
  315.      *
  316.      * @param string $strName   The route name
  317.      * @param array  $arrParams The route parameters
  318.      *
  319.      * @return string The route
  320.      */
  321.     public function previewRoute($strName$arrParams=array())
  322.     {
  323.         $container System::getContainer();
  324.         if (!$previewScript $container->getParameter('contao.preview_script'))
  325.         {
  326.             return $this->route($strName$arrParams);
  327.         }
  328.         $router $container->get('router');
  329.         $context $router->getContext();
  330.         $context->setBaseUrl($previewScript);
  331.         $strUrl $router->generate($strName$arrParams);
  332.         $strUrl substr($strUrl, \strlen(Environment::get('path')) + 1);
  333.         $context->setBaseUrl('');
  334.         return StringUtil::ampersand($strUrl);
  335.     }
  336.     /**
  337.      * Returns a translated message
  338.      *
  339.      * @param string $strId
  340.      * @param array  $arrParams
  341.      * @param string $strDomain
  342.      *
  343.      * @return string
  344.      */
  345.     public function trans($strId, array $arrParams=array(), $strDomain='contao_default')
  346.     {
  347.         return System::getContainer()->get('translator')->trans($strId$arrParams$strDomain);
  348.     }
  349.     /**
  350.      * Helper method to allow quick access in the Contao templates for safe raw (unencoded) output.
  351.      * It replaces (or optionally removes) Contao insert tags and removes all HTML.
  352.      *
  353.      * Be careful when using this. It must NOT be used within regular HTML when $value
  354.      * is uncontrolled user input. It's useful to ensure raw values within e.g. <code> examples
  355.      * or JSON-LD arrays.
  356.      */
  357.     public function rawPlainText(string $valuebool $removeInsertTags false): string
  358.     {
  359.         return StringUtil::inputEncodedToPlainText($value$removeInsertTags);
  360.     }
  361.     /**
  362.      * Helper method to allow quick access in the Contao templates for safe raw (unencoded) output.
  363.      *
  364.      * Compared to $this->rawPlainText() it adds new lines before and after block level HTML elements
  365.      * and only then removes the rest of the HTML tags.
  366.      *
  367.      * Be careful when using this. It must NOT be used within regular HTML when $value
  368.      * is uncontrolled user input. It's useful to ensure raw values within e.g. <code> examples
  369.      * or JSON-LD arrays.
  370.      */
  371.     public function rawHtmlToPlainText(string $valuebool $removeInsertTags false): string
  372.     {
  373.         return StringUtil::htmlToPlainText($value$removeInsertTags);
  374.     }
  375.     /**
  376.      * Adds schema.org JSON-LD data to the current response context
  377.      */
  378.     public function addSchemaOrg(array $jsonLd): void
  379.     {
  380.         /** @var ResponseContext $responseContext */
  381.         $responseContext System::getContainer()->get(ResponseContextAccessor::class)->getResponseContext();
  382.         if (!$responseContext || !$responseContext->has(JsonLdManager::class))
  383.         {
  384.             return;
  385.         }
  386.         /** @var JsonLdManager $jsonLdManager */
  387.         $jsonLdManager $responseContext->get(JsonLdManager::class);
  388.         $type $jsonLdManager->createSchemaOrgTypeFromArray($jsonLd);
  389.         $jsonLdManager
  390.             ->getGraphForSchema(JsonLdManager::SCHEMA_ORG)
  391.             ->set($type$jsonLd['identifier'] ?? Graph::IDENTIFIER_DEFAULT)
  392.         ;
  393.     }
  394.     /**
  395.      * Render a figure
  396.      *
  397.      * The provided configuration array is used to configure a FigureBuilder.
  398.      * If not explicitly set, the default template "image.html5" will be used
  399.      * to render the results. To use the core's default Twig template, pass
  400.      * "@ContaoCore/Image/Studio/figure.html.twig" as $template argument.
  401.      *
  402.      * @param int|string|FilesModel|ImageInterface       $from          Can be a FilesModel, an ImageInterface, a tl_files UUID/ID/path or a file system path
  403.      * @param int|string|array|PictureConfiguration|null $size          A picture size configuration or reference
  404.      * @param array<string, mixed>                       $configuration Configuration for the FigureBuilder
  405.      * @param string                                     $template      A Contao or Twig template
  406.      *
  407.      * @return string|null Returns null if the resource is invalid
  408.      */
  409.     public function figure($from$size$configuration = array(), $template 'image')
  410.     {
  411.         return System::getContainer()->get(FigureRenderer::class)->render($from$size$configuration$template);
  412.     }
  413.     /**
  414.      * Returns an asset path
  415.      *
  416.      * @param string      $path
  417.      * @param string|null $packageName
  418.      *
  419.      * @return string
  420.      */
  421.     public function asset($path$packageName null)
  422.     {
  423.         $url System::getContainer()->get('assets.packages')->getUrl($path$packageName);
  424.         $basePath '/';
  425.         $request System::getContainer()->get('request_stack')->getMasterRequest();
  426.         if ($request !== null)
  427.         {
  428.             $basePath $request->getBasePath() . '/';
  429.         }
  430.         if (=== strncmp($url$basePath, \strlen($basePath)))
  431.         {
  432.             return substr($url, \strlen($basePath));
  433.         }
  434.         // Contao paths are relative to the <base> tag, so remove leading slashes
  435.         return $url;
  436.     }
  437.     /**
  438.      * Returns a container parameter
  439.      *
  440.      * @param string $strKey
  441.      *
  442.      * @return mixed
  443.      */
  444.     public function param($strKey)
  445.     {
  446.         return System::getContainer()->getParameter($strKey);
  447.     }
  448.     /**
  449.      * Compile the template
  450.      *
  451.      * @internal Do not call this method in your code. It will be made private in Contao 5.0.
  452.      */
  453.     protected function compile()
  454.     {
  455.         if (!$this->strBuffer)
  456.         {
  457.             $this->strBuffer $this->parse();
  458.         }
  459.     }
  460.     /**
  461.      * Return the debug bar string
  462.      *
  463.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  464.      */
  465.     protected function getDebugBar()
  466.     {
  467.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\Template::getDebugBar()" has been deprecated and will no longer work in Contao 5.0.');
  468.     }
  469.     /**
  470.      * Minify the HTML markup preserving pre, script, style and textarea tags
  471.      *
  472.      * @param string $strHtml The HTML markup
  473.      *
  474.      * @return string The minified HTML markup
  475.      */
  476.     public function minifyHtml($strHtml)
  477.     {
  478.         if (System::getContainer()->getParameter('kernel.debug'))
  479.         {
  480.             return $strHtml;
  481.         }
  482.         // Split the markup based on the tags that shall be preserved
  483.         $arrChunks preg_split('@(</?pre[^>]*>)|(</?script[^>]*>)|(</?style[^>]*>)|( ?</?textarea[^>]*>)@i'$strHtml, -1PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
  484.         $strHtml '';
  485.         $blnPreserveNext false;
  486.         $blnOptimizeNext false;
  487.         $strType null;
  488.         // Check for valid JavaScript types (see #7927)
  489.         $isJavaScript = static function ($strChunk)
  490.         {
  491.             $typeMatch = array();
  492.             if (preg_match('/\stype\s*=\s*(?:(?J)(["\'])\s*(?<type>.*?)\s*\1|(?<type>[^\s>]+))/i'$strChunk$typeMatch) && !\in_array(strtolower($typeMatch['type']), static::$validJavaScriptTypes))
  493.             {
  494.                 return false;
  495.             }
  496.             if (preg_match('/\slanguage\s*=\s*(?:(?J)(["\'])\s*(?<type>.*?)\s*\1|(?<type>[^\s>]+))/i'$strChunk$typeMatch) && !\in_array('text/' strtolower($typeMatch['type']), static::$validJavaScriptTypes))
  497.             {
  498.                 return false;
  499.             }
  500.             return true;
  501.         };
  502.         // Recombine the markup
  503.         foreach ($arrChunks as $strChunk)
  504.         {
  505.             if (strncasecmp($strChunk'<pre'4) === || strncasecmp(ltrim($strChunk), '<textarea'9) === 0)
  506.             {
  507.                 $blnPreserveNext true;
  508.             }
  509.             elseif (strncasecmp($strChunk'<script'7) === 0)
  510.             {
  511.                 if ($isJavaScript($strChunk))
  512.                 {
  513.                     $blnOptimizeNext true;
  514.                     $strType 'js';
  515.                 }
  516.                 else
  517.                 {
  518.                     $blnPreserveNext true;
  519.                 }
  520.             }
  521.             elseif (strncasecmp($strChunk'<style'6) === 0)
  522.             {
  523.                 $blnOptimizeNext true;
  524.                 $strType 'css';
  525.             }
  526.             elseif ($blnPreserveNext)
  527.             {
  528.                 $blnPreserveNext false;
  529.             }
  530.             elseif ($blnOptimizeNext)
  531.             {
  532.                 $blnOptimizeNext false;
  533.                 // Minify inline scripts
  534.                 if ($strType == 'js')
  535.                 {
  536.                     $objMinify = new JS();
  537.                     $objMinify->add($strChunk);
  538.                     $strChunk $objMinify->minify();
  539.                 }
  540.                 elseif ($strType == 'css')
  541.                 {
  542.                     $objMinify = new CSS();
  543.                     $objMinify->add($strChunk);
  544.                     $strChunk $objMinify->minify();
  545.                 }
  546.             }
  547.             else
  548.             {
  549.                 // Remove line indentations and trailing spaces
  550.                 $strChunk str_replace("\r"''$strChunk);
  551.                 $strChunk preg_replace(array('/^[\t ]+/m''/[\t ]+$/m''/\n\n+/'), array(''''"\n"), $strChunk);
  552.             }
  553.             $strHtml .= $strChunk;
  554.         }
  555.         return trim($strHtml);
  556.     }
  557.     /**
  558.      * Generate the markup for a style sheet tag
  559.      *
  560.      * @param string $href  The script path
  561.      * @param string $media The media type string
  562.      * @param mixed  $mtime The file mtime
  563.      *
  564.      * @return string The markup string
  565.      */
  566.     public static function generateStyleTag($href$media=null$mtime=false)
  567.     {
  568.         // Add the filemtime if not given and not an external file
  569.         if ($mtime === null && !preg_match('@^https?://@'$href))
  570.         {
  571.             $container System::getContainer();
  572.             $projectDir $container->getParameter('kernel.project_dir');
  573.             if (file_exists($projectDir '/' $href))
  574.             {
  575.                 $mtime filemtime($projectDir '/' $href);
  576.             }
  577.             else
  578.             {
  579.                 $webDir StringUtil::stripRootDir($container->getParameter('contao.web_dir'));
  580.                 // Handle public bundle resources in the contao.web_dir folder
  581.                 if (file_exists($projectDir '/' $webDir '/' $href))
  582.                 {
  583.                     $mtime filemtime($projectDir '/' $webDir '/' $href);
  584.                 }
  585.             }
  586.         }
  587.         if ($mtime)
  588.         {
  589.             $href .= '?v=' substr(md5($mtime), 08);
  590.         }
  591.         return '<link rel="stylesheet" href="' $href '"' . (($media && $media != 'all') ? ' media="' $media '"' '') . '>';
  592.     }
  593.     /**
  594.      * Generate the markup for inline CSS code
  595.      *
  596.      * @param string $script The CSS code
  597.      *
  598.      * @return string The markup string
  599.      */
  600.     public static function generateInlineStyle($script)
  601.     {
  602.         return '<style>' $script '</style>';
  603.     }
  604.     /**
  605.      * Generate the markup for a JavaScript tag
  606.      *
  607.      * @param string      $src            The script path
  608.      * @param boolean     $async          True to add the async attribute
  609.      * @param mixed       $mtime          The file mtime
  610.      * @param string|null $hash           An optional integrity hash
  611.      * @param string|null $crossorigin    An optional crossorigin attribute
  612.      * @param string|null $referrerpolicy An optional referrerpolicy attribute
  613.      *
  614.      * @return string The markup string
  615.      */
  616.     public static function generateScriptTag($src$async=false$mtime=false$hash=null$crossorigin=null$referrerpolicy=null)
  617.     {
  618.         // Add the filemtime if not given and not an external file
  619.         if ($mtime === null && !preg_match('@^https?://@'$src))
  620.         {
  621.             $container System::getContainer();
  622.             $projectDir $container->getParameter('kernel.project_dir');
  623.             if (file_exists($projectDir '/' $src))
  624.             {
  625.                 $mtime filemtime($projectDir '/' $src);
  626.             }
  627.             else
  628.             {
  629.                 $webDir StringUtil::stripRootDir($container->getParameter('contao.web_dir'));
  630.                 // Handle public bundle resources in the contao.web_dir folder
  631.                 if (file_exists($projectDir '/' $webDir '/' $src))
  632.                 {
  633.                     $mtime filemtime($projectDir '/' $webDir '/' $src);
  634.                 }
  635.             }
  636.         }
  637.         if ($mtime)
  638.         {
  639.             $src .= '?v=' substr(md5($mtime), 08);
  640.         }
  641.         return '<script src="' $src '"' . ($async ' async' '') . ($hash ' integrity="' $hash '"' '') . ($crossorigin ' crossorigin="' $crossorigin '"' '') . ($referrerpolicy ' referrerpolicy="' $referrerpolicy '"' '') . '></script>';
  642.     }
  643.     /**
  644.      * Generate the markup for an inline JavaScript
  645.      *
  646.      * @param string $script The JavaScript code
  647.      *
  648.      * @return string The markup string
  649.      */
  650.     public static function generateInlineScript($script)
  651.     {
  652.         return '<script>' $script '</script>';
  653.     }
  654.     /**
  655.      * Generate the markup for an RSS feed tag
  656.      *
  657.      * @param string $href   The script path
  658.      * @param string $format The feed format
  659.      * @param string $title  The feed title
  660.      *
  661.      * @return string The markup string
  662.      */
  663.     public static function generateFeedTag($href$format$title)
  664.     {
  665.         return '<link type="application/' $format '+xml" rel="alternate" href="' $href '" title="' StringUtil::specialchars($title) . '">';
  666.     }
  667.     /**
  668.      * Flush the output buffers
  669.      *
  670.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  671.      */
  672.     public function flushAllData()
  673.     {
  674.         trigger_deprecation('contao/core-bundle''4.0''Using "Contao\Template::flushAllData()" has been deprecated and will no longer work in Contao 5.0.');
  675.         if (\function_exists('fastcgi_finish_request'))
  676.         {
  677.             fastcgi_finish_request();
  678.         }
  679.         elseif (\PHP_SAPI !== 'cli')
  680.         {
  681.             $status ob_get_status(true);
  682.             $level = \count($status);
  683.             while ($level-- > && (!empty($status[$level]['del']) || (isset($status[$level]['flags']) && ($status[$level]['flags'] & PHP_OUTPUT_HANDLER_REMOVABLE) && ($status[$level]['flags'] & PHP_OUTPUT_HANDLER_FLUSHABLE))))
  684.             {
  685.                 ob_end_flush();
  686.             }
  687.             flush();
  688.         }
  689.     }
  690. }
  691. class_alias(Template::class, 'Template');