Prototype for static includes
authorAlexander Ebert <ebert@woltlab.com>
Wed, 8 Feb 2012 14:33:37 +0000 (15:33 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 8 Feb 2012 14:33:37 +0000 (15:33 +0100)
EXPERIMENTAL/crash-for-sure

wcfsetup/install/files/lib/system/template/TemplateCompiler.class.php
wcfsetup/install/files/lib/system/template/TemplateEngine.class.php
wcfsetup/install/files/lib/system/template/TemplateScriptingCompiler.class.php

index 20e52a08cddaaa46e310ee062f91bb66110b7ddf..568e9ec31d67c457289bf999618f02b9a8fe72fd 100644 (file)
@@ -19,17 +19,24 @@ class TemplateCompiler extends TemplateScriptingCompiler {
         * @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();
        }
        
index 441e6b201d6eff4abc0f19c8c8022b5e540426f6..01436f577429399bf3643c048c266163d41c6f71 100644 (file)
@@ -300,11 +300,17 @@ class TemplateEngine extends SingletonFactory {
                $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
@@ -325,7 +331,7 @@ class TemplateEngine extends SingletonFactory {
         * @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);
                        
@@ -389,22 +395,33 @@ class TemplateEngine extends SingletonFactory {
         * 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 {
@@ -415,6 +432,18 @@ class TemplateEngine extends SingletonFactory {
                                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);
@@ -436,8 +465,9 @@ class TemplateEngine extends SingletonFactory {
         * @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();
@@ -447,7 +477,7 @@ class TemplateEngine extends SingletonFactory {
                $sourceContent = $this->getSourceContent($sourceFilename);
                
                // compile template
-               $this->compilerObj->compile($templateName, $sourceContent, $compiledFilename);
+               $this->compilerObj->compile($templateName, $sourceContent, $compiledFilename, $metaData);
        }
        
        /**
@@ -761,4 +791,35 @@ class TemplateEngine extends SingletonFactory {
                
                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;
+       }
 }
index a2ac07cc77aa47afb3c156aa83d843d9bd6604fb..d71a8aa7e093c3e0067392d56440c3b6533651d5 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\system\template;
 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;
 
@@ -187,9 +188,10 @@ class TemplateScriptingCompiler {
         * 
         * @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;
@@ -219,7 +221,7 @@ class TemplateScriptingCompiler {
                $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");
                }
                
@@ -252,17 +254,9 @@ class TemplateScriptingCompiler {
                $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";
                        }
@@ -276,8 +270,9 @@ class TemplateScriptingCompiler {
         * 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);
@@ -324,7 +319,7 @@ class TemplateScriptingCompiler {
                                        return '<?php } ?>';
                                
                                case 'include':
-                                       return $this->compileIncludeTag($tagArgs);
+                                       return $this->compileIncludeTag($tagArgs, $metaData);
                                        
                                case 'foreach':
                                        $this->pushTag('foreach');
@@ -681,9 +676,10 @@ class TemplateScriptingCompiler {
         * 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;
                
@@ -721,6 +717,12 @@ class TemplateScriptingCompiler {
                        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);