/** 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); }