Example #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;
     }
 }
Example #2
0
 /**
  * Uses the specified variable within the context.
  *
  * @param string $variable The variable name.
  * @param boolean $isGlobal Is the variable global or local?
  * @param string $contextFormat The format enforced by the occurence context.
  * @return array
  */
 public function useVariable($variable, $type, $isGlobal, $contextFormat = null)
 {
     if (!isset($this->_variables[$type . $variable])) {
         // In this case the variable has not been used yet. We must check
         // if the user have not selected any format for it, calculate the
         // default format and modify the context format.
         $manager = $this->_compiler->getCdfManager();
         try {
             // In case of template variables, we should not check the data formats
             // because we would run into several problems. We immediately jump to the
             // format resolution algorithm.
             if ($type == '@') {
                 throw new Exception();
             }
             // OK, look for a variable
             $this->_variables[$type . $variable] = $manager->getFormat('variable', $variable, $this);
             return array('format' => $this->_variables[$type . $variable], 'replacement' => null, 'cast' => null);
         } catch (Exception $exception) {
             if ($contextFormat === null) {
                 // This is very strange. It seems that someone has used
                 // an uninitialized variable, so we can set it to null and
                 // report it as an unused variable.
                 Opt_Support::warning('Uninitialized variable ' . $variable . ' - casting to NULL');
                 return array('format' => null, 'replacement' => 'null');
             } else {
                 $manager->addFormat('variable', $variable, $contextFormat, $this->getElementLocation('variable', $variable));
                 $this->_variables[$type . $variable] = $manager->getFormat('variable', $variable, $this);
                 return array('format' => $this->_variables[$type . $variable], 'replacement' => null, 'cast' => null);
             }
         }
     } else {
         // The variable has already been used. We must match the
         // previously selected format.
         if ($contextFormat !== null) {
             return array('format' => $this->_variables[$type . $variable], 'replacement' => null, 'cast' => $this->_variables[$type . $variable]->getName());
         } else {
             return array('format' => $this->_variables[$type . $variable], 'replacement' => null);
         }
     }
 }
Example #3
0
 /**
  * Parses the XML prolog and returns its attributes as an array. The parsing
  * algorith is the same, as in _compileAttributes().
  *
  * @internal
  * @param String $prolog The prolog string.
  * @return Array
  */
 protected function _compileProlog($prolog)
 {
     // Tokenize the list
     preg_match_all($this->_rPrologTokens, $prolog, $match, PREG_SET_ORDER);
     $size = sizeof($match);
     $result = array();
     for ($i = 0; $i < $size; $i++) {
         if (!ctype_space($match[$i][0])) {
             // Traverse through a single attribute
             if (!preg_match($this->_rNameExpression, $match[$i][0])) {
                 throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
             }
             $vret = false;
             $name = $match[$i][0];
             $value = null;
             for ($i++; $i < $size && ctype_space($match[$i][0]); $i++) {
             }
             if ($i >= $size || $match[$i][0] != '=') {
                 throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
             }
             for ($i++; ctype_space($match[$i][0]) && $i < $size; $i++) {
             }
             if ($match[$i][0] != '"' && $match[$i][0] != '\'') {
                 throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
             }
             $opening = $match[$i][0];
             $value = '';
             for ($i++; $i < $size; $i++) {
                 if ($match[$i][0] == $opening) {
                     break;
                 }
                 $value .= $match[$i][0];
             }
             if (!isset($match[$i][0]) || $match[$i][0] != $opening) {
                 throw new Opt_XmlInvalidProlog_Exception('invalid attribute format');
             }
             // If we are here, the attribute is correct. No shit on the way detected.
             $result[$name] = $value;
         }
     }
     $returnedResult = $result;
     // Check, whether the arguments are correct.
     if (isset($result['version'])) {
         // There is no other version so far, so report a warning. For 99,9% this is a mistake.
         if ($result['version'] != '1.0') {
             $this->_tpl->debugConsole and Opt_Support::warning('OPT', 'XML prolog warning: strange XML version: ' . $result['version']);
         }
         unset($result['version']);
     }
     if (isset($result['encoding'])) {
         if (!preg_match($this->_rEncodingName, $result['encoding'])) {
             throw new Opt_XmlInvalidProlog_Exception('invalid encoding name format');
         }
         // The encoding should match the value we mentioned in the OPT configuration and sent to the browser.
         $result['encoding'] = strtolower($result['encoding']);
         $charset = is_null($this->_tpl->charset) ? null : strtolower($this->_tpl->charset);
         if ($result['encoding'] != $charset && !is_null($charset)) {
             $this->_tpl->debugConsole and Opt_Support::warning('OPT', 'XML prolog warning: the declared encoding: "' . $result['encoding'] . '" differs from setContentType() setting: "' . $charset . '"');
         }
         unset($result['encoding']);
     } else {
         $this->_tpl->debugConsole and Opt_Support::warning('XML prolog warning: no encoding information. Remember your content must be pure UTF-8 or UTF-16 then.');
     }
     if (isset($result['standalone'])) {
         if ($result['standalone'] != 'yes' && $result['standalone'] != 'no') {
             throw new Opt_XmlInvalidProlog_Exception('invalid value for "standalone" attribute: "' . $result['standalone'] . '"; expected: "yes", "no".');
         }
         unset($result['standalone']);
     }
     if (sizeof($result) > 0) {
         throw new Opt_XmlInvalidProlog_Exception('invalid attributes in prolog.');
     }
     return $returnedResult;
 }
Example #4
0
 /**
  * Starts the section by putting its record on a section stack.
  *
  * @param Array $section The section record.
  */
 protected function _sectionStart(array &$section)
 {
     self::_addSection($section);
     if (!is_null($section['node']->get('call:use'))) {
         $this->_compiler->setConversion('##simplevar_' . $section['node']->get('call:use'), $section['name']);
     }
     // Populate the debug console.
     if ($this->_tpl->debugConsole) {
         if (isset($section['datasource'])) {
             $parent = '<em>Datasource</em>';
         } elseif (!is_null($section['parent'])) {
             $parent = $section['parent'];
         } else {
             $parent = '-';
         }
         Opt_Support::addSection($section['name'], $parent, (string) $section['format'], $section['node']->getXmlName());
     }
 }
Example #5
0
 /**
  * Executes, and optionally compiles the template represented by the view.
  * Returns true, if the template was found and successfully executed.
  *
  * @param Opt_Output_Interface $output The output interface.
  * @param Boolean $exception Should the exceptions be thrown if the template does not exist?
  * @return Boolean
  */
 public function _parse(Opt_Output_Interface $output, $exception = true)
 {
     if ($this->_tpl->debugConsole) {
         $time = microtime(true);
     }
     $cached = false;
     if ($this->_cache !== null) {
         $result = $this->_cache->templateCacheStart($this);
         if ($result !== false) {
             // For dynamic cache...
             if (is_string($result)) {
                 include $result;
             }
             return true;
         }
         $cached = true;
     }
     $this->_tf = $this->_tpl->getTranslationInterface();
     if ($this->_tpl->compileMode != Opt_Class::CM_PERFORMANCE) {
         list($compileName, $compileTime) = $this->_preprocess($exception);
         if ($compileName === null) {
             return false;
         }
     } else {
         $compileName = $this->_convert($this->_template);
         $compileTime = null;
         if (!$exception && !file_exists($compileName)) {
             return false;
         }
     }
     $old = error_reporting($this->_tpl->errorReporting);
     require $this->_tpl->compileDir . $compileName;
     error_reporting($old);
     // The counter stops, if the time counting has been enabled for the debug console purposes
     if ($this->_cache !== null) {
         $this->_cache->templateCacheStop($this);
     }
     if (isset($time)) {
         Opt_Support::addView($this->_template, $output->getName(), $this->_processingTime = microtime(true) - $time, $cached);
     }
     return true;
 }