* All child classes must redefine this property! * * @var array */ protected static $_required = array(); /** * Name of the template to load. * * @var string */ protected $_templateName; /** * Key-value params to make available in the template. * * @var array */ protected $_params = array(); /** * PHP errors generated during template evaluation. * * @var array */ protected $_templateErrors = array(); /** * The ID of the language that templates will be retrieved from. * * @var integer */ protected static $_languageId = 0; /** * Constructor * * @param string Template name * @param array Key-value parameters */ public function __construct($templateName, array $params = array()) { XenForo_CodeEvent::fire('template_create', array(&$templateName, &$params, $this), $templateName); $this->_templateName = $templateName; $this->preloadTemplate($templateName); if ($params) { $this->setParams($params); } } /** * Creates a new template object of the current type. Mainly helpful * if an event only has the current template object in scope. * * @param string $templateName * @param array $params * * @return XenForo_Template_Abstract */ public function create($templateName, array $params = array()) { $class = get_class($this); return new $class($templateName, $params); } /** * Sets the language ID that templates will be retrieved from. * * @param integer $lring */ public function getTemplateName() { return $this->_templateName; } /** * Renders the specified template and returns the output. * * @return string */ public function render() { $__template = $this->_loadTemplate($this->_templateName); if ($__template === '') { return ''; } XenForo_Phrase::loadPhrases(); set_error_handler(array($this, 'handleTemplateError')); $this->_templateErrors = array(); $__output = $this->_renderInternal($__template, $__extraData); restore_error_handler(); XenForo_CodeEvent::fire('template_post_render', array($this->_templateName, &$__output, &$__extraData, $this), $this->_templateName); if (is_array($__extraData) && !empty($__extraData)) { $this->_mergeExtraContainerData($__extraData); } if ($this->_templateErrors && XenForo_Application::debugMode()) { if ($this->_usingTemplateFiles()) { $templateCode = file_get_contents($__template); } else { $templateCode = $__template; } $lines = preg_split('/\r?\n/', $__template); echo "

Template Errors: " . htmlspecialchars($this->_templateName) . "

    \n"; foreach ($this->_templateErrors AS $error) { $contextLine = ($error['line'] > 1 ? $error['line'] - 2 : 0); $context = array_slice($lines, $contextLine, 3, true); echo "\t
  1. " . htmlspecialchars($error['error']) . " in " . htmlspecialchars($error['file']) . ", line $error[line]"; if ($context) { echo ":
    ";
    					foreach ($context AS $lineNum => $contextLine)
    					{
    						echo ($lineNum + 1) . ": " . htmlspecialchars($contextLine) . "\n";
    					}
    					echo "
    "; } echo "
  2. \n"; } echo "
\n\n"; } return $__output === null ? '' : $__output; } /** * Internal template rendering. * * @param string $__template Template text or name of template file * @param array $__extraData Returned extra data from the render * * @return string Rendered template */ protected function _renderInternal($__template, &$__extraData) { $__params = $this->_params; // special variable for dumping purposes extract($this->_params); $__output = ''; $__extraData = array(); if ($this->_usingTemplateFiles()) { if (file_exists($__template)) { include($__template); } } else { eval($__template); } return $__output; } /** * Calls the specified template hook event. _CodeEvent::fire('template_hook', array($name, &$contents, $params, $this), $name); return $contents; } /** * Calls the specified template callback. * * @param string|object $class * @param string $method * @param string $contents Contents (children) of the callback; may be empty * @param array $params List of params to pass specifically; these will respect mappings. * * @return string New version of the contents (could be modified) */ public function callTemplateCalls not match prefix: get, is, has, render, view, return, print, show, display'; } if ($call === true) { ob_start(); $contents = call_user_func(array($class, $method), $contents, $params, $this); $contents .= ob_get_contents(); ob_end_clean(); } else { $contents .= "\nCould not execute callback $className::$method() - $call.\n"; } return $contents; } /** * Error handler that traps errors in templates. * * @param integer $errorType Type of error (one of the E_* constants) * @param string $errorString * @param string $file * @param integer $line */ public function handleTemplateError($errorType, $errorString, $file, $line) { if ($errorType == E_NOTICE) { return; } if ($errorType & error_reporting()) { $this->_templateErrors[] = array( 'type' => $errorType, 'error' => $errorString, 'file' => $file, 'line' => $line ); } } /** * Gets required external resources as HTML for use in a template directly. * * @param string Type of requirement to fetch * * @return string Requirements as HTML */ public function getRequiredExternalsAsHtml($type) { $required = $this->_getRequiredExternals(); if (empty($required[$type])) { return ''; } $typeRequired = array_unique($required[$type]); switch ($type) { case 'js': return $this->getRequiredJavaScriptAsHtml($typeRequired); case 'css': return $this->getRequiredCssAsHtml($this->getRequiredCssUrl($typeRequired)); default: return false; } } public function getRequiredExternalsAsJson() { $required = $this->_getRequiredExternals(); $output = array(); foreach ($required AS $type => $externals) { if ($type == 'js') { $externals = $this->_processJsUrls($externals); } foreach ($externals AS $external) { $output[$external] = true; } } return json_encode($output); } /** * Gets required externals in a structured way. Values will be returned as a list of URLs. * * @param string $type * * @return array List of URLs */ public function getRequiredExternals($type) { $required = $this->_getRequiredExternals(); if (empty($required[$type])) { return ''; } $typeRequired = array_reverse(array_unique($required[$type])); switch ($type) { case 'js': return $this->_processJsUrls($typeRequired); case 'css': return array( 'stylesheets' => $typeRequired, 'urlTemplate' => $this->getRequiredCssUrl(array('__sentinel__')) ); default: return false; } } /** * Gets the list of required JavaScript files as HTML script tags. * * @param array $requirements Array of paths to JS files. * * @return string */ public function getRequiredJavaScriptAsHtml(array $requirements) { $output = ''; foreach ($this->_processJsUrls($requirements) AS $requirement) { $output .= "\t" . '