Esempio n. 1
0
 /**
  * The compilation launcher. It executes the proper compilation steps
  * according to the inheritance rules etc.
  *
  * @param String $code The source code to be compiled.
  * @param String $filename The source template filename.
  * @param String $compiledFilename The output template filename.
  * @param Int $mode The compilation mode.
  */
 public function compile($code, $filename, $compiledFilename, $mode)
 {
     $manager = $this->getCdfManager();
     // Initialize the context.
     $this->_contextStack->push(new Opt_Compiler_Context($this, Opt_Compiler_Context::TEMPLATE_CTX, $filename));
     try {
         // First, we select a parser.
         if (!isset($this->_parsers[$mode])) {
             $this->_parsers[$mode] = new $mode();
             if (!$this->_parsers[$mode] instanceof Opt_Parser_Interface) {
                 throw new Opt_InvalidParser_Exception($mode);
             }
         }
         $parser = $this->_parsers[$mode];
         $parser->setCompiler($this);
         // We cannot compile two templates at the same time
         if (!is_null($this->_template)) {
             throw new Opt_CompilerLocked_Exception($filename, $this->_template);
         }
         // Detecting recursive inclusion
         if (is_null(self::$_recursionDetector)) {
             self::$_recursionDetector = array(0 => $filename);
             $weFree = true;
         } else {
             if (in_array($filename, self::$_recursionDetector)) {
                 $exception = new Opt_CompilerRecursion_Exception($filename);
                 $exception->setData(self::$_recursionDetector);
                 throw $exception;
             }
             self::$_recursionDetector[] = $filename;
             $weFree = false;
         }
         // Cleaning up the processors
         foreach ($this->_processors as $proc) {
             $proc->reset();
         }
         // Initializing the template launcher
         $this->set('template', $this->_template = $filename);
         $this->set('mode', $mode);
         $this->set('currentTemplate', $this->_template);
         array_push(self::$_templates, $filename);
         $this->_stack = new SplStack();
         $i = 0;
         $extend = $filename;
         $memory = 0;
         // The inheritance loop
         do {
             // Stage 1 - code compilation
             if ($this->_tpl->debugConsole) {
                 $initial = memory_get_usage();
                 $tree = $parser->parse($extend, $code);
                 // Migration stage - only if backwards compatibility is on
                 if ($this->_tpl->backwardCompatibility) {
                     $tree = $this->_migrate($tree);
                 }
                 // Stage 2 - PHP tree processing
                 $this->_stack = null;
                 $this->_stage2($tree);
                 $this->set('escape', NULL);
                 unset($this->_stack);
                 $memory += memory_get_usage() - $initial;
                 unset($code);
             } else {
                 $tree = $parser->parse($extend, $code);
                 unset($code);
                 // Migration stage - only if backward compatibility is on
                 if ($this->_tpl->backwardCompatibility) {
                     $this->_migrate($tree);
                 }
                 // Stage 2 - PHP tree processing
                 $this->_stack = array();
                 $this->_stage2($tree);
                 $this->set('escape', NULL);
                 unset($this->_stack);
             }
             // if the template extends something, load it and also process
             if (isset($extend) && $extend != $filename) {
                 $this->addDependantTemplate($extend);
             }
             if (!is_null($snippet = $tree->get('snippet'))) {
                 $tree->dispose();
                 unset($tree);
                 // Change the specified snippet into a root node.
                 $tree = new Opt_Xml_Root();
                 $attribute = new Opt_Xml_Attribute('opt:use', $snippet);
                 $this->processor('snippet')->processAttribute($tree, $attribute);
                 $this->processor('snippet')->postprocessAttribute($tree, $attribute);
                 $this->_stage2($tree, true);
                 break;
             }
             if (!is_null($extend = $tree->get('extend'))) {
                 $tree->dispose();
                 unset($tree);
                 $this->set('currentTemplate', $extend);
                 array_pop(self::$_templates);
                 array_push(self::$_templates, $extend);
                 $code = $this->_tpl->_getSource($extend);
             }
             $i++;
         } while (!is_null($extend));
         // There are some dependant templates. We must add a suitable PHP code
         // to the output.
         if (sizeof($this->_dependencies) > 0) {
             $this->_addDependencies($tree);
         }
         if ($this->_tpl->debugConsole) {
             Opt_Support::addCompiledTemplate($this->_template, $memory);
         }
         // Stage 3 - linking the last tree
         if (!is_null($compiledFilename)) {
             $this->_output = '';
             $this->_newQueue = null;
             $this->_dynamicBlocks = array();
             $this->_stage3($output, $tree);
             $tree->dispose();
             unset($tree);
             $this->_output = str_replace('?><' . '?php', '', $this->_output);
             // Build the directories, if needed.
             if (($pos = strrpos($compiledFilename, '/')) !== false) {
                 $path = $this->_tpl->compileDir . substr($compiledFilename, 0, $pos);
                 if (!is_dir($path)) {
                     mkdir($path, 0750, true);
                 }
             }
             // Save the file
             if (sizeof($this->_dynamicBlocks) > 0) {
                 file_put_contents($this->_tpl->compileDir . $compiledFilename . '.dyn', serialize($this->_dynamicBlocks));
             }
             file_put_contents($this->_tpl->compileDir . $compiledFilename, $this->_output);
             $this->_output = '';
             $this->_dynamicBlocks = null;
         } else {
             $tree->dispose();
         }
         array_pop(self::$_templates);
         $this->_inheritance = array();
         if ($weFree) {
             // Do the cleanup.
             $this->_dependencies = array();
             self::$_recursionDetector = NULL;
             foreach ($this->_processors as $processor) {
                 $processor->reset();
             }
         }
         $this->_template = NULL;
         $manager->clearLocals();
         // Free the context.
         while ($this->_contextStack->count() > 0) {
             $ctx = $this->_contextStack->pop();
             $ctx->dispose();
         }
         // Run the new garbage collector, if it is available.
         /*	if(version_compare(PHP_VERSION, '5.3.0', '>='))
         			{
         				gc_collect_cycles();
         			}*/
     } catch (Exception $e) {
         // Free the context
         while ($this->_contextStack->count() > 0) {
             $ctx = $this->_contextStack->pop();
             $ctx->dispose();
         }
         // Free the memory
         if (isset($tree)) {
             $tree->dispose();
         }
         // Clean the compiler state in case of exception
         $this->_template = NULL;
         $this->_dependencies = array();
         self::$_recursionDetector = NULL;
         foreach ($this->_processors as $processor) {
             $processor->reset();
         }
         $manager->clearLocals();
         // And throw it forward.
         throw $e;
     }
 }