* @param string $templateName
* @param string $sourceContent
* @param string $compiledFilename
+ * @param array $metaData
*/
- public function compile($templateName, $sourceContent, $compiledFilename) {
- // build fileheader
- $compiledHeader = "<?php\n/**\n* WoltLab Community Framework\n* Template: ".$templateName."\n* Compiled at: ".gmdate('r')."\n* \n* DO NOT EDIT THIS FILE\n*/\n\$this->v['tpl']['template'] = '".addcslashes($templateName, "'\\")."';\n?>\n";
+ public function compile($templateName, $sourceContent, $compiledFilename, $metaData) {
+ // build fileheader for template
+ $compiledHeader = "<?php\n/**\n * WoltLab Community Framework\n * Template: ".$templateName."\n * Compiled at: ".gmdate('r')."\n * \n * DO NOT EDIT THIS FILE\n */\n\$this->v['tpl']['template'] = '".addcslashes($templateName, "'\\")."';\n?>\n";
// include plug-ins
- $compiledContent = $this->compileString($templateName, $sourceContent);
+ $compiledContent = $this->compileString($templateName, $sourceContent, $metaData);
- // write compiled to file
+ // write compiled template to file
$file = new File($compiledFilename);
- $file->write($compiledHeader.$compiledContent);
+ $file->write($compiledHeader.$compiledContent['template']);
+ $file->close();
+
+ // write meta data to file
+ $file = new File($metaData['filename']);
+ $file->write("<?php exit; /* meta data for template: ".$templateName." (generated at ".gmdate('r').") DO NOT EDIT THIS FILE */ ?>\n");
+ $file->write(serialize($compiledContent['meta']));
$file->close();
}
$tplPackageID = $this->getPackageID($templateName, $packageID);
$compiledFilename = $this->getCompiledFilename($templateName, $packageID);
$sourceFilename = $this->getSourceFilename($templateName, $tplPackageID);
+ $metaDataFilename = $this->getMetaDataFilename($templateName, $packageID);
+ $metaData = $this->getMetaData($templateName, $metaDataFilename);
// check if compilation is necessary
- if (!$this->isCompiled($templateName, $sourceFilename, $compiledFilename)) {
+ if (!$this->isCompiled($templateName, $sourceFilename, $compiledFilename, $metaData)) {
// compile
- $this->compileTemplate($templateName, $sourceFilename, $compiledFilename);
+ $this->compileTemplate($templateName, $sourceFilename, $compiledFilename, array(
+ 'data' => $metaData,
+ 'filename' => $metaDataFilename,
+ 'packageID' => $packageID
+ ));
}
// assign current package id
* @param integer $packageID
* @return integer
*/
- protected function getPackageID($templateName, $packageID) {
+ public function getPackageID($templateName, $packageID) {
if ($packageID != 1 && isset($this->templatePaths[$packageID])) {
$path = $this->getPath($this->templatePaths[$packageID], $templateName);
* Returns the absolute filename of a compiled template.
*
* @param string $templateName
- * @return string $path
+ * @param integer $packageID
*/
public function getCompiledFilename($templateName, $packageID) {
return $this->compileDir.$packageID.'_'.$this->templateGroupID.'_'.$this->languageID.'_'.$templateName.'.php';
}
+ /**
+ * Returns the absolute filename for template's meta data.
+ *
+ * @param string $templateName
+ * @param integer $packageID
+ */
+ public function getMetaDataFilename($templateName, $packageID) {
+ return $this->compileDir.$packageID.'_'.$this->templateGroupID.'_'.$templateName.'.meta.php';
+ }
+
/**
* Checks wheater a template is already compiled or not.
*
* @param string $templateName
* @param string $sourceFilename
* @param string $compiledFilename
+ * @param array $metaData
* @return boolean $isCompiled
*/
- protected function isCompiled($templateName, $sourceFilename, $compiledFilename) {
- if ($this->forceCompile || !file_exists($compiledFilename)) {
+ protected function isCompiled($templateName, $sourceFilename, $compiledFilename, array $metaData) {
+ if ($this->forceCompile || !file_exists($compiledFilename) || !file_exists($metaDataFilename)) {
return false;
}
else {
return false;
}
else {
+ // check for meta data
+ if (!empty($metaData['include'])) {
+ foreach ($metaData['include'] as $template) {
+ $includedTemplateFilename = $this->getSourceFilename($template['templateName'], $packageID);
+ $includedMTime = @filemtime($includedTemplateFilename);
+
+ if ($includedMTime >= $compileMTime) {
+ return false;
+ }
+ }
+ }
+
// check for template listeners
if ($this->hasTemplateListeners($templateName)) {
$this->loadTemplateListenerCode($templateName);
* @param string $templateName
* @param string $sourceFilename
* @param string $compiledFilename
+ * @param array $metaData
*/
- protected function compileTemplate($templateName, $sourceFilename, $compiledFilename) {
+ protected function compileTemplate($templateName, $sourceFilename, $compiledFilename, array $metaData) {
// get compiler
if (!($this->compilerObj instanceof TemplateCompiler)) {
$this->compilerObj = $this->getCompiler();
$sourceContent = $this->getSourceContent($sourceFilename);
// compile template
- $this->compilerObj->compile($templateName, $sourceContent, $compiledFilename);
+ $this->compilerObj->compile($templateName, $sourceContent, $compiledFilename, $metaData);
}
/**
return '';
}
+
+ /**
+ * Reads meta data from file.
+ *
+ * @param string $templateName
+ * @param string $filename
+ * @return array
+ */
+ protected function getMetaData($templateName, $filename) {
+ if (!file_exists($filename) || !is_readable($filename)) {
+ return null;
+ }
+
+ // get file contents
+ $contents = file_get_contents($filename);
+
+ // find first newline
+ $position = strpos($contents, "\n");
+ if ($position === false) throw new SystemException("Unable to load meta data for template '".$templateName."'");
+
+ // cut contents
+ $contents = substr($contents, $position + 1);
+
+ // read serializes data
+ $data = @unserialize($contents);
+ if ($data === false || !is_array($data)) {
+ throw new SystemException("Invalid meta data for template '".$templateName."'");
+ }
+
+ return $data;
+ }
}
use wcf\system\exception\SystemException;
use wcf\system\template\plugin\ICompilerTemplatePlugin;
use wcf\system\template\plugin\IPrefilterTemplatePlugin;
+use wcf\system\WCF;
use wcf\util\StringStack;
use wcf\util\StringUtil;
*
* @param string $identifier
* @param string $sourceContent
+ * @param array $metaData
* @return string
*/
- public function compileString($identifier, $sourceContent) {
+ public function compileString($identifier, $sourceContent, array $metaData = array()) {
// reset vars
$this->autoloadPlugins = $this->tagStack = $this->stringStack = $this->literalStack = array();
$this->currentIdentifier = $identifier;
$compiledTags = array();
for ($i = 0, $j = count($templateTags); $i < $j; $i++) {
$this->currentLineNo += StringUtil::countSubstring($textBlocks[$i], "\n");
- $compiledTags[] = $this->compileTag($templateTags[$i]);
+ $compiledTags[] = $this->compileTag($templateTags[$i], $metaData);
$this->currentLineNo += StringUtil::countSubstring($templateTags[$i], "\n");
}
$compiledAutoloadPlugins = '';
if (count($this->autoloadPlugins) > 0) {
$compiledAutoloadPlugins = "<?php\n";
- foreach ($this->autoloadPlugins as $className/* => $fileName*/) {
+ foreach ($this->autoloadPlugins as $className) {
$compiledAutoloadPlugins .= "use ".$className.";\n";
$compiledAutoloadPlugins .= "if (!isset(\$this->pluginObjects['$className'])) {\n";
- /*
- if (WCF_DIR != '' && strpos($fileName, WCF_DIR) === 0) {
- $compiledAutoloadPlugins .= "require_once(WCF_DIR.'".StringUtil::replace(WCF_DIR, '', $fileName)."');\n";
- }
- else {
- $compiledAutoloadPlugins .= "require_once('".$fileName."');\n";
- }
- */
$compiledAutoloadPlugins .= "\$this->pluginObjects['$className'] = new $className;\n";
$compiledAutoloadPlugins .= "}\n";
}
* Compiles a template tag.
*
* @param string $tag
+ * @param array $metaData
*/
- protected function compileTag($tag) {
+ protected function compileTag($tag, array &$metaData) {
if (preg_match('~^'.$this->outputPattern.'~s', $tag)) {
// variable output
return $this->compileOutputTag($tag);
return '<?php } ?>';
case 'include':
- return $this->compileIncludeTag($tagArgs);
+ return $this->compileIncludeTag($tagArgs, $metaData);
case 'foreach':
$this->pushTag('foreach');
* Compiles an include tag.
*
* @param string $includeTag
- * @return string phpCode
+ * @param array $metaData
+ * @return string phpCode
*/
- protected function compileIncludeTag($includeTag) {
+ protected function compileIncludeTag($includeTag, array &$metaData) {
$args = $this->parseTagArgs($includeTag, 'include');
$append = false;
unset($args['once']);
}
+ // check for static includes
+ if ($sandbox === false && $assignVar === false && $once === false) {
+ $content = WCF::getTPL()->fetch($file, array(), false, $metaData['packageID']);
+ return $metaData;
+ }
+
// make argument string
$argString = $this->makeArgString($args);