* $t = new ezcTemplate(); * echo $t->process( "page.ezt" ); * * * The location for the source templates and compiled templates among other things * are specified in the ezcTemplateConfiguration configuration object. A default * configuration is always present and can be accessed via the $configuration * property. * * Usually one configuration object will be enough, since most of the templates * will use the same configuration settings. If for some reason, other configuration * settings are needed you can assign an ezcTemplateConfiguration object to the $configuration property. * * The following example shows how to change the template and compilation * directory by creating a new configuration object. * * $t = new ezcTemplate(); * $t->configuration = new ezcTemplateConfiguration( "design/templates", * "/tmp/compilation" ); * echo $t->process( "page.ezt" ); * * * Another approach is to pass the ezcTemplateConfiguration object to the process method. This * method will use the given configuration instead. * * $t = new ezcTemplate(); * $config = new ezcTemplateConfiguration( "design/templates", * "/tmp/compilation" ); * echo $t->process( "page.ezt", $config ); * * * The properties {@link ezcTemplate::send send} and * {@link ezcTemplate::receive receive} are available to set the variables that * are sent to and retrieved from the template. * * The next example demonstrates how a template variable is set and retrieved: * * * $t = new ezcTemplate(); * * $t->send->mySentence = "Hello world"; * echo $t->process( "calc_sentence_length.ezt" ); * * $number = $t->receive->length; * * * The template code: * * {use $mySentence = ""} * * {var $length = str_len( $mySentence )} * {return $length} * * * @property ezcTemplateVariableCollection $send * Contains the variables that are send to the template. * @property-read ezcTemplateVariableCollection $receive * Contains the variables that are returned by the template. * @property ezcTemplateConfiguration $configuration * Contains the template configuration. * @property-read string $output * The output of the last processed template. * @property-read string $compiledTemplatePath * The path of the compiled template. * @property-read ezcTemplateTstNode $tstTree * The generated tstTree (debug). * @property-read ezcTemplateAstNode $astTree * The generated astTree (debug). * @package Template * @version 1.2beta2 */ class ezcTemplate { /** * An array containing the properties of this object: * * @var array(string=>mixed) */ private $properties = array( 'configuration' => null, 'usedConfiguration' => null, 'send' => null, 'receive' => null, 'compiledTemplatePath' => null, 'tstTree' => false, 'astTree' => false, 'stream' => false, 'output' => "", ); /** * Returns the value of the property $name. * * @throws ezcBasePropertyNotFoundException if the property does not exist. * @param string $name * @return mixed * @ignore */ public function __get( $name ) { switch ( $name ) { case 'send': case 'receive': case 'tstTree': case 'astTree': case 'stream': case 'compiledTemplatePath': case 'usedConfiguration': case 'output': return $this->properties[$name]; case 'configuration': if ( $this->properties[$name] === null ) { $this->properties[$name] = ezcTemplateConfiguration::getInstance(); if ( get_class( $this->properties[$name] ) != 'ezcTemplateConfiguration' ) { throw new ezcTemplateInternalException( "Static method ezcTemplateConfiguration::getInstance() did not return an object of class ezcTemplateConfiguration" ); } } return $this->properties[$name]; default: throw new ezcBasePropertyNotFoundException( $name ); } } /** * Checks if the property $name is set and returns the result. * * @param string $name * @return bool * @ignore */ public function __isset( $name ) { switch ( $name ) { case 'configuration': case 'usedConfiguration': case 'compiledTemplatePath': case 'send': case 'receive': case 'tstTree': case 'astTree': case 'stream': case 'output': return isset( $this->properties[$name] ); default: return false; } } /** * Sets the property named $name to contain value of $value. * * @throws ezcBasePropertyNotFoundException if the property does not exist. * @param string $name * @param mixed $value * @return void * @ignore */ public function __set( $name, $value ) { switch ( $name ) { case 'send': if ( !$value instanceof ezcTemplateVariableCollection ) { throw new ezcBaseValueException( $name, $value, 'ezcTemplateVariableCollection' ); } $this->properties[$name] = $value; break; case 'configuration': if ( $value !== null and !( $value instanceof ezcTemplateConfiguration ) ) { throw new ezcBaseValueException( $name, $value, 'ezcTemplateConfiguration' ); } $this->properties[$name] = $value; break; case 'tstTree': case 'astTree': case 'compiledTemplatePath': case 'output': case 'stream': case 'receive': throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException::READ ); default: // case 'usedConfiguration': throw new ezcBasePropertyNotFoundException( $name ); } } /** * Intializes the ezcTemplate with a default configuration and empty * $send and $receive properties. * * Configuration of the object must now be done through the properties: * - {@link ezcTemplate::configuration configuration} * - {@link ezcTemplate::send send} * - {@link ezcTemplate::receive receive} */ public function __construct() { $this->properties["send"] = new ezcTemplateVariableCollection(); $this->properties["receive"] = new ezcTemplateVariableCollection(); } /** * Processes the specified template source and returns the output string. * * Note: The first time a template is accessed it needs to be compiled so the * execution time will be higher than subsequent calls. * * @param string $location The path to the template file to process, can be a PHP stream. * @param ezcTemplateConfiguration $config Optional configuration object which overrides * the default one defined in this object ($configuration). * @return string * * @throws ezcTemplateParserException * If the template could not be compiled. * @throws ezcTemplateFileNotWriteableException * If the directory could not be created. */ public function process( $location, ezcTemplateConfiguration $config = null ) { if ( $config === null ) { $config = $this->configuration; } $this->properties["usedConfiguration"] = $config; $this->properties["tstTree"] = false; $this->properties["astTree"] = false; $this->properties["stream"] = $location; if ( $location instanceof ezcTemplateLocationInterface) { $this->properties["file"] = $location; $this->properties["stream"] = $location->getPath(); } if ( strlen( $this->properties["stream"] ) > 0 && $this->properties["stream"][0] != "/" ) // Is it a relative path? { $this->properties["stream"] = $config->templatePath . DIRECTORY_SEPARATOR . $this->properties["stream"]; } // lookup compiled code here $compiled = ezcTemplateCompiledCode::findCompiled( $this->properties["stream"], $config->context, $this ); $this->properties["compiledTemplatePath"] = $compiled->path; $counter = 0; while ( true ) { ++$counter; if ( $counter > 3 ) { // @todo fix exception throw new ezcTemplateCompilationFailedException( "Failed to create and execute compiled code after " . ($counter - 1) . " tries." ); } if ( file_exists( $compiled->path ) && (!$config->checkModifiedTemplates || filemtime( $this->properties["stream"] ) <= filemtime( $compiled->path ) ) ) { try { // execute compiled code here $this->properties["output"] = $compiled->execute(); return $this->properties["output"]; } catch ( ezcTemplateOutdatedCompilationException $e ) { // The compiled file cannot be used so we need to recompile it } } $this->createDirectory( dirname( $compiled->path ) ); // get the compiled path. // use parser here $source = new ezcTemplateSourceCode( $this->properties["stream"], $this->properties["stream"] ); $source->load(); $parser = new ezcTemplateParser( $source, $this ); $this->properties["tstTree"] = $parser->parseIntoNodeTree(); if ($parser->hasCacheBlocks && !$config->disableCache ) { $fetchCacheInfo = new ezcTemplateFetchCacheInformation(); $this->properties["tstTree"]->accept( $fetchCacheInfo ); $tstToAst = new ezcTemplateTstToAstCachedTransformer ( $parser, $fetchCacheInfo->cacheTst); } else { $tstToAst = new ezcTemplateTstToAstTransformer ( $parser); } $this->properties["tstTree"]->accept( $tstToAst ); $this->properties["astTree"] = $tstToAst->programNode; $astToAst = new ezcTemplateAstToAstContextAppender( $config->context ); $tstToAst->programNode->accept( $astToAst ); // Extra optimization. $astToAst = new ezcTemplateAstToAstAssignmentOptimizer(); $tstToAst->programNode->accept( $astToAst ); $g = new ezcTemplateAstToPhpGenerator( $compiled->path, $config ); // Write to the file. $tstToAst->programNode->accept( $g ); // Add to the cache system. if ($config->cacheManager !== false ) { $config->cacheManager->includeTemplate( $this, $this->properties["stream"]); } } // execute compiled code here throw new ezcTemplateInternalException( "Compilation or execution failed" ); } /** * Creates the directory $path if it does not exist. * * If the directory $path could be created the function returns true, * otherwise the ezcTemplateFileNotWriteableException exception is thrown. * * @throws ezcTemplateFileNotWriteableException * If the directory could not be created * @param string $path * @return bool */ private function createDirectory( $path ) { if ( !is_dir( $path ) ) { $created = @mkdir( $path, 0700, true ); if ( !$created ) { throw new ezcTemplateFileNotWriteableException( $path ); } } return true; } /** * Generates a unique hash from the current options. * * For example the default values would return: * * "updqr0" * * * Note: This is mostly useful for the template component, * relying on the output of this function is not a good idea. * * @return string */ public function generateOptionHash() { return base_convert( crc32( 'ezcTemplate::options(' . false /*(bool)$this->outputDebugEnabled*/ . '-' . false /*(bool)$this->compiledDebugEnabled*/ . ')' ), 10, 36 ); } } ?>