Вход Регистрация
Файл: contao-3.5.8/system/modules/core/library/Contao/Template.php
Строк: 459
<?php

/**
 * Contao Open Source CMS
 *
 * Copyright (c) 2005-2016 Leo Feyer
 *
 * @license LGPL-3.0+
 */

namespace Contao;

use 
MatthiasMullieMinify;


/**
 * Parses and outputs template files
 *
 * The class supports loading template files, adding variables to them and then
 * printing them to the screen. It functions as abstract parent class for the
 * two core classes "BackendTemplate" and "FrontendTemplate".
 *
 * Usage:
 *
 *     $template = new BackendTemplate();
 *     $template->name = 'Leo Feyer';
 *     $template->output();
 *
 * @property string $style
 * @property array  $cssID
 * @property string $class
 * @property string $inColumn
 * @property string $headline
 * @property array  $hl
 *
 * @author Leo Feyer <https://github.com/leofeyer>
 */
abstract class Template extends BaseTemplate
{

    
/**
     * Output buffer
     * @var string
     */
    
protected $strBuffer;

    
/**
     * Content type
     * @var string
     */
    
protected $strContentType;

    
/**
     * Template data
     * @var array
     */
    
protected $arrData = array();

    
/**
     * Valid JavaScipt types
     * @var array
     * @see http://www.w3.org/TR/html5/scripting-1.html#scriptingLanguages
     */
    
protected static $validJavaScriptTypes = array
    (
        
'application/ecmascript',
        
'application/javascript',
        
'application/x-ecmascript',
        
'application/x-javascript',
        
'text/ecmascript',
        
'text/javascript',
        
'text/javascript1.0',
        
'text/javascript1.1',
        
'text/javascript1.2',
        
'text/javascript1.3',
        
'text/javascript1.4',
        
'text/javascript1.5',
        
'text/jscript',
        
'text/livescript',
        
'text/x-ecmascript',
        
'text/x-javascript',
    );


    
/**
     * Create a new template object
     *
     * @param string $strTemplate    The template name
     * @param string $strContentType The content type (defaults to "text/html")
     */
    
public function __construct($strTemplate=''$strContentType='text/html')
    {
        
parent::__construct();

        
$this->strTemplate $strTemplate;
        
$this->strContentType $strContentType;
    }


    
/**
     * Set an object property
     *
     * @param string $strKey   The property name
     * @param mixed  $varValue The property value
     */
    
public function __set($strKey$varValue)
    {
        
$this->arrData[$strKey] = $varValue;
    }


    
/**
     * Return an object property
     *
     * @param string $strKey The property name
     *
     * @return mixed The property value
     */
    
public function __get($strKey)
    {
        if (isset(
$this->arrData[$strKey]))
        {
            if (
is_object($this->arrData[$strKey]) && is_callable($this->arrData[$strKey]))
            {
                return 
$this->arrData[$strKey]();
            }

            return 
$this->arrData[$strKey];
        }

        return 
parent::__get($strKey);
    }


    
/**
     * Execute a callable and return the result
     *
     * @param string $strKey    The name of the key
     * @param array  $arrParams The parameters array
     *
     * @return mixed The callable return value
     *
     * @throws InvalidArgumentException If the callable does not exist
     */
    
public function __call($strKey$arrParams)
    {
        if (!isset(
$this->arrData[$strKey]) || !is_callable($this->arrData[$strKey]))
        {
            throw new 
InvalidArgumentException("$strKey is not set or not a callable");
        }

        return 
call_user_func_array($this->arrData[$strKey], $arrParams);
    }


    
/**
     * Check whether a property is set
     *
     * @param string $strKey The property name
     *
     * @return boolean True if the property is set
     */
    
public function __isset($strKey)
    {
        return isset(
$this->arrData[$strKey]);
    }


    
/**
     * Set the template data from an array
     *
     * @param array $arrData The data array
     */
    
public function setData($arrData)
    {
        
$this->arrData $arrData;
    }


    
/**
     * Return the template data as array
     *
     * @return array The data array
     */
    
public function getData()
    {
        return 
$this->arrData;
    }


    
/**
     * Set the template name
     *
     * @param string $strTemplate The template name
     */
    
public function setName($strTemplate)
    {
        
$this->strTemplate $strTemplate;
    }


    
/**
     * Return the template name
     *
     * @return string The template name
     */
    
public function getName()
    {
        return 
$this->strTemplate;
    }


    
/**
     * Set the output format
     *
     * @param string $strFormat The output format
     */
    
public function setFormat($strFormat)
    {
        
$this->strFormat $strFormat;
    }


    
/**
     * Return the output format
     *
     * @return string The output format
     */
    
public function getFormat()
    {
        return 
$this->strFormat;
    }


    
/**
     * Print all template variables to the screen using print_r
     */
    
public function showTemplateVars()
    {
        echo 
"<pre>n";
        
print_r($this->arrData);
        echo 
"</pre>n";
    }


    
/**
     * Print all template variables to the screen using var_dump
     */
    
public function dumpTemplateVars()
    {
        
dump($this->arrData);
    }


    
/**
     * Parse the template file and return it as string
     *
     * @return string The template markup
     */
    
public function parse()
    {
        if (
$this->strTemplate == '')
        {
            return 
'';
        }

        
// HOOK: add custom parse filters
        
if (isset($GLOBALS['TL_HOOKS']['parseTemplate']) && is_array($GLOBALS['TL_HOOKS']['parseTemplate']))
        {
            foreach (
$GLOBALS['TL_HOOKS']['parseTemplate'] as $callback)
            {
                
$this->import($callback[0]);
                
$this->{$callback[0]}->{$callback[1]}($this);
            }
        }

        return 
parent::parse();
    }


    
/**
     * Parse the template file and print it to the screen
     */
    
public function output()
    {
        if (!
$this->strBuffer)
        {
            
$this->strBuffer $this->parse();
        }

        
// Minify the markup
        
$this->strBuffer $this->minifyHtml($this->strBuffer);

        
header('Vary: User-Agent'false);
        
header('Content-Type: ' $this->strContentType '; charset=' Config::get('characterSet'));

        
// Add the debug bar
        
if (Config::get('debugMode') && !Config::get('hideDebugBar') && !isset($_GET['popup']))
        {
            
$this->strBuffer str_replace('</body>'$this->getDebugBar() . '</body>'$this->strBuffer);
        }

        echo 
$this->strBuffer;

        
// Flush the output buffers (see #6962)
        
$this->flushAllData();

        
// HOOK: add custom logic
        
if (isset($GLOBALS['TL_HOOKS']['postFlushData']) && is_array($GLOBALS['TL_HOOKS']['postFlushData']))
        {
            foreach (
$GLOBALS['TL_HOOKS']['postFlushData'] as $callback)
            {
                
$this->import($callback[0]);
                
$this->{$callback[0]}->{$callback[1]}($this->strBuffer$this);
            }
        }
    }


    
/**
     * Return the debug bar string
     *
     * @return string The debug bar markup
     */
    
protected function getDebugBar()
    {
        
$intReturned 0;
        
$intAffected 0;

        
// Count the totals (see #3884)
        
if (is_array($GLOBALS['TL_DEBUG']['database_queries']))
        {
            foreach (
$GLOBALS['TL_DEBUG']['database_queries'] as $k=>$v)
            {
                
$intReturned += $v['return_count'];
                
$intAffected += $v['affected_count'];
                unset(
$GLOBALS['TL_DEBUG']['database_queries'][$k]['return_count']);
                unset(
$GLOBALS['TL_DEBUG']['database_queries'][$k]['affected_count']);
            }
        }

        
$intElapsed = (microtime(true) - TL_START);

        
$strDebug sprintf(
            
"<!-- indexer::stop -->n"
            
'<div id="contao-debug">'
            
'<p>'
                
'<span class="debug-time">Execution time: %s ms</span>'
                
'<span class="debug-memory">Memory usage: %s</span>'
                
'<span class="debug-db">Database queries: %d</span>'
                
'<span class="debug-rows">Rows: %d returned, %s affected</span>'
                
'<span class="debug-models">Registered models: %d</span>'
                
'<span id="debug-tog">&nbsp;</span>'
            
'</p>'
            
'<div><pre>',
            
$this->getFormattedNumber(($intElapsed 1000), 0),
            
$this->getReadableSize(memory_get_peak_usage()),
            
count($GLOBALS['TL_DEBUG']['database_queries']),
            
$intReturned,
            
$intAffected,
            
ModelRegistry::getInstance()->count()
        );

        
ksort($GLOBALS['TL_DEBUG']);

        
ob_start();
        
print_r($GLOBALS['TL_DEBUG']);
        
$strDebug .= ob_get_contents();
        
ob_end_clean();

        unset(
$GLOBALS['TL_DEBUG']);

        
$strDebug .= '</pre></div></div>'
            
$this->generateInlineScript(
                
"(function($) {"
                    
"$(document.body).addClass('debug-enabled " Input::cookie('CONTAO_CONSOLE') . "');"
                    
"$('debug-tog').addEvent('click',function(e) {"
                        
"$(document.body).toggleClass('debug-closed');"
                        
"Cookie.write('CONTAO_CONSOLE',$(document.body).hasClass('debug-closed')?'debug-closed':'',{path:'" . (TL_PATH ?: '/') . "'});"
                    
"});"
                
"})(document.id);",
                (
$this->strFormat == 'xhtml')
            )
            . 
"n<!-- indexer::continue -->nn"
        
;

        return 
$strDebug;
    }


    
/**
     * Minify the HTML markup preserving pre, script, style and textarea tags
     *
     * @param string $strHtml The HTML markup
     *
     * @return string The minified HTML markup
     */
    
public function minifyHtml($strHtml)
    {
        
// The feature has been disabled
        
if (!Config::get('minifyMarkup') || Config::get('debugMode'))
        {
            return 
$strHtml;
        }

        
// Split the markup based on the tags that shall be preserved
        
$arrChunks preg_split('@(</?pre[^>]*>)|(</?script[^>]*>)|(</?style[^>]*>)|( ?</?textarea[^>]*>)@i'$strHtml, -1PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);

        
$strHtml '';
        
$blnPreserveNext false;
        
$blnOptimizeNext false;
        
$strType null;

        
// Check for valid JavaScript types (see #7927)
        
$isJavaScript = function ($strChunk)
        {
            
$typeMatch = array();

            if (
preg_match('/stypes*=s*(?:(?J)(["'])s*(?<type>.*?)s*1|(?<type>[^s>]+))/i', $strChunk, $typeMatch) && !in_array(strtolower($typeMatch['type']), static::$validJavaScriptTypes))
            {
                return false;
            }

            if (preg_match('
/slanguages*=s*(?:(?J)(["'])s*(?<type>.*?)s*1|(?<type>[^s>]+))/i', $strChunk$typeMatch) && !in_array('text/' . strtolower($typeMatch['type']), static::$validJavaScriptTypes))
            {
                return false;
            }

            return true;
        };

        // Recombine the markup
        foreach (
$arrChunks as $strChunk)
        {
            if (strncasecmp(
$strChunk, '<pre', 4) === 0 || strncasecmp(ltrim($strChunk), '<textarea', 9) === 0)
            {
                
$blnPreserveNext = true;
            }
            elseif (strncasecmp(
$strChunk, '<script', 7) === 0)
            {
                if (
$isJavaScript($strChunk))
                {
                    
$blnOptimizeNext = true;
                    
$strType = 'js';
                }
                else
                {
                    
$blnPreserveNext = true;
                }
            }
            elseif (strncasecmp(
$strChunk, '<style', 6) === 0)
            {
                
$blnOptimizeNext = true;
                
$strType = 'css';
            }
            elseif (
$blnPreserveNext)
            {
                
$blnPreserveNext = false;
            }
            elseif (
$blnOptimizeNext)
            {
                
$blnOptimizeNext = false;

                // Minify inline scripts
                if (
$strType == 'js')
                {
                    
$objMinify = new MinifyJS();
                    
$objMinify->add($strChunk);
                    
$strChunk = $objMinify->minify();
                }
                elseif (
$strType == 'css')
                {
                    
$objMinify = new MinifyCSS();
                    
$objMinify->add($strChunk);
                    
$strChunk = $objMinify->minify();
                }
            }
            else
            {
                // Remove line indentations and trailing spaces
                
$strChunk = str_replace("r", '', $strChunk);
                
$strChunk = preg_replace(array('/^[t ]+/m', '/[t ]+$/m', '/nn+/'), array('', '', "n"), $strChunk);
            }

            
$strHtml .= $strChunk;
        }

        return trim(
$strHtml);
    }


    /**
     * Generate the markup for a style sheet tag
     *
     * @param string  
$href  The script path
     * @param string  
$media The media type string
     * @param boolean 
$xhtml True if the output shall be XHTML compliant
     *
     * @return string The markup string
     */
    public static function generateStyleTag(
$href$media=null, $xhtml=false)
    {
        return '<link' . (
$xhtml ? ' type="text/css"' : '') . ' rel="stylesheet" href="' . $href . '"' . (($media && $media != 'all') ? ' media="' . $media . '"' : '') . ($xhtml ? ' />' : '>');
    }


    /**
     * Generate the markup for inline CSS code
     *
     * @param string  
$script The CSS code
     * @param boolean 
$xhtml  True if the output shall be XHTML compliant
     *
     * @return string The markup string
     */
    public static function generateInlineStyle(
$script$xhtml=false)
    {
        if (
$xhtml)
        {
            return '<style type="
text/css">' . "n/* <![CDATA[ */n" . $script . "n/* ]]> */n" . '</style>';
        }
        else
        {
            return '<style>' . 
$script . '</style>';
        }
    }


    /**
     * Generate the markup for a JavaScript tag
     *
     * @param string  
$src   The script path
     * @param boolean 
$xhtml True if the output shall be XHTML compliant
     * @param boolean 
$async True to add the async attribute
     *
     * @return string The markup string
     */
    public static function generateScriptTag(
$src$xhtml=false, $async=false)
    {
        return '<script' . (
$xhtml ? ' type="text/javascript"' : '') . ' src="' . $src . '"' . ($async && !$xhtml ? ' async' : '') . '></script>';
    }


    /**
     * Generate the markup for an inline JavaScript
     *
     * @param string  
$script The JavaScript code
     * @param boolean 
$xhtml  True if the output shall be XHTML compliant
     *
     * @return string The markup string
     */
    public static function generateInlineScript(
$script$xhtml=false)
    {
        if (
$xhtml)
        {
            return '<script type="
text/javascript">' . "n/* <![CDATA[ */n" . $script . "n/* ]]> */n" . '</script>';
        }
        else
        {
            return '<script>' . 
$script . '</script>';
        }
    }


    /**
     * Generate the markup for an RSS feed tag
     *
     * @param string  
$href   The script path
     * @param string  
$format The feed format
     * @param string  
$title  The feed title
     * @param boolean 
$xhtml  True if the output shall be XHTML compliant
     *
     * @return string The markup string
     */
    public static function generateFeedTag(
$href$format$title$xhtml=false)
    {
        return '<link type="
application/' . $format . '+xml" rel="alternate" href="' . $href . '" title="' . specialchars($title) . '"' . ($xhtml ? ' />' : '>');
    }


    /**
     * Flush the output buffers
     *
     * @see SymfonyComponentHttpFoundationResponse
     */
    public function flushAllData()
    {
        if (function_exists('fastcgi_finish_request'))
        {
            fastcgi_finish_request();
        }
        elseif (PHP_SAPI !== 'cli')
        {
            
$status = ob_get_status(true);
            
$level = count($status);

            while (
$level-- > 0 && (!empty($status[$level]['del']) || (isset($status[$level]['flags']) && ($status[$level]['flags'] & PHP_OUTPUT_HANDLER_REMOVABLE) && ($status[$level]['flags'] & PHP_OUTPUT_HANDLER_FLUSHABLE))))
            {
                ob_end_flush();
            }

            flush();
        }
    }


    /**
     * Print the IE6 warning
     *
     * @return string The warning message
     *
     * @deprecated The IE6 warning is now in the templates (e.g. be_install)
     */
    public function showIE6warning()
    {
        return ''; // Backwards compatibility
    }
}
Онлайн: 0
Реклама