/**
  Includes template's code into global namespace via I/O driver given in DSN.
  I/O system checks @c recompilationMode (which you may override per-template using @c $mode parameter) and
  acts accordingly, recompiling only when it's required either by this setting or template change.
  Also recursively handles inclusion of template parent.
  
  @param[in] $template %Template name
  @param[in] $mode Per-template recompilation mode override (optional)
  @param[in] $returnMeta If @c true, then returns metadata instead of including the code
  @return Template's class name, as string; or metadata, as array
 */
 public function include_($template, $mode = null, $returnMeta = false)
 {
     if (!$mode) {
         $mode = $this->settings['recompilationMode'];
     }
     list($io, $template) = TemplateUtils::parseIODSN($this->settings, $template);
     if (!$io->upToDate($this->settings, $template, $mode)) {
         $this->compile($io, $template);
     }
     $metadata = $io->loadMetadata($this->settings, $template);
     if ($returnMeta) {
         return $metadata;
     }
     if (is_array($metadata) && isset($metadata['parentTemplate'])) {
         $this->include_($metadata['parentTemplate'], $mode);
     }
     return $io->includeCode($this->settings, $template);
 }
 /**
  Compiles given template into output package.
  
  @param[in] $io Used I/O driver
  @param[in] $template %Template name
 */
 public function compile(ITemplateIODriver $io, $template)
 {
     $this->reset();
     if (($tpl = $io->loadTemplate($this->settings, $template)) === false) {
         throw new TemplateError('Could not load template "' . $in . '"', TemplateError::E_IO_LOAD_FAILURE);
     }
     $this->className = $io->className($this->settings, $template);
     $this->parserCurrentFile = $template;
     $this->metadata['usedIO'] = $io->driverID;
     $genAST = $this->createAST($tpl);
     $genCode = $this->generateCode($genAST);
     // determine template's parent class
     $classCode = '<?php class ' . $this->className . ' extends ';
     if (isset($this->metadata['parentTemplate'])) {
         list($parentIO, $parent) = TemplateUtils::parseIODSN($this->settings, $this->metadata['parentTemplate']);
         $classCode .= $parentIO->className($this->settings, $parent);
         // main content is ignored, when template extends another
         unset($genCode['main']);
     } else {
         $classCode .= 'Template';
     }
     $classCode .= '{';
     foreach ($genCode as $blockName => &$blockCode) {
         $classCode .= 'function _' . TemplateUtils::sanitize($blockName) . '($e){';
         // TODO: is constructor support really needed?
         if ($blockName == '_constructor') {
             $classCode .= 'parent::__constructor();';
         }
         $classCode .= $blockCode . '}';
     }
     $classCode .= '}';
     if ($io->saveMetadata($this->settings, $template, $this->metadata) === false) {
         throw new TemplateError('Could not save template metadata (compiled from "' . $template . '")', TemplateError::E_IO_SAVE_FAILURE);
     }
     if ($io->saveTemplate($this->settings, $template, $classCode) === false) {
         throw new TemplateError('Could not save template code (compiled from "' . $template . '").', TemplateError::E_IO_SAVE_FAILURE);
     }
 }
 /**
  Tests the behaviour of @ref TemplateUtils::parseDSN.
 */
 public function testUtilsParseDSN()
 {
     $settings =& $this->environ->settings;
     list($io, $id) = TemplateUtils::parseIODSN($settings, 'string://foo');
     $this->assertTrue($io instanceof TemplateStringIO);
     $this->assertEquals('foo', $id);
     list($io, $id) = TemplateUtils::parseIODSN($settings, 'foo');
     $this->assertTrue($io instanceof TemplateFileIO);
     $this->assertEquals('foo', $id);
 }