blob: fa0f69f4448609c9c36fd5cbe662c468786188a5 [file] [log] [blame]
<?php
/**
* File containing the ezcTemplateTstToAstCachedTransformer class
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package Template
* @version //autogen//
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @access private
*/
/**
* Use this transformer when caching is enabled.
*
* @package Template
* @version //autogen//
* @access private
*/
class ezcTemplateTstToAstCachedTransformer extends ezcTemplateTstToAstTransformer
{
/**
* Contains the {cache_template} information.
*/
protected $cacheTemplate = null;
private $template = null;
private $cacheName = null;
private $cacheSystem = null;
private $isInDynamicBlock = false;
/**
* True when in {cache_template} or inside a {cache_block}.
*/
private $isInCacheBlock = false;
private $cacheLevel = 0;
private $cacheBaseName = null;
protected $cacheBlockCounter = 0;
public function __construct( $parser, $cacheTemplate )
{
parent::__construct( $parser );
$this->cacheTemplate = $cacheTemplate;
// XXX
$this->template = $parser->template;
}
public function __destruct()
{
}
/**
* Removes the old cache file
*/
protected function removeOldCache( $cachePath )
{
if ( file_exists( $cachePath ) )
{
unlink( $cachePath );
}
}
protected function getFp()
{
return $this->createVariableNode( "fp" . $this->cacheLevel );
}
/**
* Returns the ast tree: include( $_ezcTemplateCache );
*/
protected function _includeCache()
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "include", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" . $this->cacheLevel ) ) ) );
}
/**
* Returns the ast tree: $fp = fopen( $_ezcTemplateCache, "w");
*/
protected function _fopenCacheFileWriteMode()
{
// return new ezcTemplateGenericStatementAstNode( new ezcTemplateAssignmentOperatorAstNode( $this->getFp(), new ezcTemplateFunctionCallAstNode( "fopen", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" ), new ezcTemplateLiteralAstNode( "w") )) ) );
return new ezcTemplateGenericStatementAstNode( new ezcTemplateAssignmentOperatorAstNode( $this->getFp(), new ezcTemplateLiteralAstNode("")));
}
/**
* Returns the ast tree: fwrite( $fp, "<" . "?php\n" );
*/
protected function _fwritePhpOpen()
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateConcatAssignmentOperatorAstNode( $this->getFp(), new ezcTemplateConcatOperatorAstNode( new ezcTemplateLiteralAstNode('<'), new ezcTemplateLiteralAstNode("?php\n" ) ) ) );
// return new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "fwrite", array( $this->getFp(), new ezcTemplateConcatOperatorAstNode( new ezcTemplateLiteralAstNode('<'), new ezcTemplateLiteralAstNode("?php\n" ) ) ) ) );
}
/**
* Returns the ast tree: <variable> = "";
*/
protected function _assignEmptyString( $variable )
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateAssignmentOperatorAstNode( $this->createVariableNode( $variable ), new ezcTemplateLiteralAstNode( "") ) );
}
/**
* Returns the ast tree: <variableDst> .= <variableSrc>;
*/
protected function _concatAssignVariable( $variableSrc, $variableDst )
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateConcatAssignmentOperatorAstNode( $this->createVariableNode( $variableDst ), $this->createVariableNode( $variableSrc ) ) );
}
/**
* Returns the ast tree: <variableDst> = <variableSrc>;
*/
protected function _assignVariable( $variableSrc, $variableDst )
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateAssignmentOperatorAstNode( $this->createVariableNode( $variableDst ), $this->createVariableNode( $variableSrc ) ) );
}
/**
* Returns the ast tree: fwriteLiteral( $fp, <literal_value> );
*/
protected function _fwriteLiteral( $literalValue )
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateConcatAssignmentOperatorAstNode( $this->getFp(), new ezcTemplateLiteralAstNode( $literalValue ) ) );
// return new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "fwrite", array( $this->getFp(), new ezcTemplateLiteralAstNode( $literalValue ) ) ) );
}
/**
* Returns the ast tree: fwriteVariable( $fp, $<variableName> );
*/
protected function _fwriteVariable( $variableName )
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateConcatAssignmentOperatorAstNode( $this->getFp(), $this->createVariableNode( $variableName ) ) );
// return new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "fwrite", array( $this->getFp(), $this->createVariableNode( $variableName ) ) ) );
}
/**
* Returns the ast tree: return $<variableName>;
*/
protected function _returnVariable( $variableName )
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateReturnAstNode ( $this->createVariableNode( $variableName ) ) );
}
/**
* Returns one of the following ast trees, depending on the variables $concat and $fwritePhpClose:
*
* fwrite( $fp, "\\\<variableName> = " . var_export( <variableName>, true) . "; ?>" );
* fwrite( $fp, "\\\<variableName> .= " . var_export( <variableName>, true) . ";" );
* fwrite( $fp, "\\\<variableName> = " . var_export( <variableName>, true) . "; ?>" );
* fwrite( $fp, "\\\<variableName> .= " . var_export( <variableName>, true) . ";" );
*/
protected function _fwriteVarExportVariable( $variableName, $concat, $fwritePhpClose = false )
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateConcatAssignmentOperatorAstNode( $this->getFp(), new ezcTemplateConcatOperatorAstNode( new ezcTemplateLiteralAstNode("\$".$variableName." ". ($concat ? ".=" : "=") ." "), new ezcTemplateConcatOperatorAstNode( new ezcTemplateFunctionCallAstNode( "var_export", array( $this->createVariableNode("$variableName"), new ezcTemplateLiteralAstNode(true) ) ), new ezcTemplateLiteralAstNode(";\n" . ($fwritePhpClose ? " ?>" : "" )) ) ) ) );
/* return new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "fwrite", array($this->getFp(), new ezcTemplateConcatOperatorAstNode( new ezcTemplateLiteralAstNode("\$".$variableName." ". ($concat ? ".=" : "=") ." "), new ezcTemplateConcatOperatorAstNode( new ezcTemplateFunctionCallAstNode( "var_export", array( $this->createVariableNode("$variableName"), new ezcTemplateLiteralAstNode(true) ) ), new ezcTemplateLiteralAstNode(";\n" . ($fwritePhpClose ? " ?>" : "" )) ) ) ) ) );
*/
}
/**
* Returns the ast tree that inserts comments.
*/
protected function _comment( $str )
{
return new ezcTemplatePhpCodeAstNode( "// ". str_replace( "\n", "\n// ", $str ) . "\n" );
}
/**
* Returns the ast tree: fclose( $fp);
*/
protected function _fclose()
{
return new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "file_put_contents", array( new ezcTemplateVariableAstNode("_ezcTemplateCache" . $this->cacheLevel ), $this->getFp() ) ) ) ;
// return new ezcTemplateGenericStatementAstNode( new ezcTemplateAssignmentOperatorAstNode( $this->getFp(), new ezcTemplateFunctionCallAstNode( "fopen", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" ), new ezcTemplateLiteralAstNode( "w") )) ) );
//
// return new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "fclose", array( $this->getFp() ) ) ) ;
}
protected function getCacheBaseName()
{
if ( $this->cacheBaseName === null )
{
$rpTemplate = realpath( $this->template->usedConfiguration->templatePath );
$rpStream = realpath( $this->parser->template->stream );
if ( strncmp( $rpTemplate, $rpStream, strlen( $rpTemplate ) ) == 0 )
{
$fileName = substr( $rpStream, strlen( $rpTemplate ) );
}
else
{
$fileName = $rpStream;
}
$this->cacheBaseName = $this->template->usedConfiguration->compilePath . DIRECTORY_SEPARATOR . $this->template->usedConfiguration->cachedTemplatesPath . DIRECTORY_SEPARATOR . str_replace( DIRECTORY_SEPARATOR, "-", $fileName );
}
return $this->cacheBaseName;
}
protected function deleteOldCache()
{
$bn = $this->getCacheBaseName();
$base = basename( $bn );
$dir = dirname( $bn);
if ( is_dir( $dir ) )
{
$dp = opendir( $dir );
while ( false !== ( $file = readdir( $dp ) ) )
{
if ( strncmp( $base, $file, strlen($base ) ) == 0 )
{
unlink( $dir . DIRECTORY_SEPARATOR . $file );
}
}
closedir( $dp );
}
}
/**
* Returns the ast tree: !file_exists( [ $_ezcTemplateCache ] )
*/
protected function notFileExistsCache()
{
if ( $this->template->usedConfiguration->cacheManager )
{
// !file_exists() || !$this->template->usedConfiguration->cacheManager->isValid( $cacheName )
$a = new ezcTemplateLogicalNegationOperatorAstNode( new ezcTemplateFunctionCallAstNode( "file_exists", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" . $this->cacheLevel ) ) ) );
$b = new ezcTemplateLogicalNegationOperatorAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->usedConfiguration->cacheManager->isValid", array( new ezcTemplateVariableAstNode( "this->template"), new ezcTemplateLiteralAstNode( $this->parser->template->stream ), new ezcTemplateVariableAstNode( "_ezcTemplateCache" . $this->cacheLevel ) ) ) );
return new ezcTemplateLogicalOrOperatorAstNode( $a, $b );
}
else
{
return new ezcTemplateLogicalNegationOperatorAstNode( new ezcTemplateFunctionCallAstNode( "file_exists", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" . $this->cacheLevel ) ) ) );
}
}
protected function translateCacheKeys($tstKeys)
{
$cacheKeys = array();
$i = 0;
foreach ( $tstKeys as $key => $value )
{
// Translate the 'old' variableName to the new name.
$k = $value->accept($this);
// If the cachekey is an expression, assign it to a variable.
if (!$k instanceof ezcTemplateVariableAstNode )
{
$var = $this->createVariableNode( self::INTERNAL_PREFIX . "cachekey" . $i );
$createVar = new ezcTemplateGenericStatementAstNode( new ezcTemplateAssignmentOperatorAstNode( $var, $k ) );
$this->programNode->appendStatement( $createVar );
$k = $var;
}
$type = $this->parser->symbolTable->retrieve($k->name);
if ( substr( $k->name, 0, 12) == "this->send->")
{
$cacheKeys[str_replace( "this->send->", "use:" , $k->name )] = $k->name;
}
elseif (substr( $k->name, 0, 2) == "t_" )
{
$cacheKeys[ "var:" . substr($k->name, 2)] = $k->name;
}
else
{
$cacheKeys[$k->name] = $k->name;
}
$i++;
}
return $cacheKeys;
}
protected function translateTTL($tstTTL)
{
$ttl = null;
if ( $tstTTL !== null )
{
$ttl = $tstTTL->accept($this);
}
return $ttl;
}
protected function createCacheDir()
{
$dir = $this->template->usedConfiguration->compilePath . DIRECTORY_SEPARATOR . $this->template->usedConfiguration->cachedTemplatesPath;
if ( !file_exists( $dir ) )
{
mkdir( $dir );
}
}
protected function startCaching( $cb )
{
// / startCaching();
$cplen = strlen( $this->parser->template->usedConfiguration->compilePath );
if ($this->template->usedConfiguration->cacheManager )
{
$cb->appendStatement( new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->usedConfiguration->cacheManager->startCaching", array( new ezcTemplateVariableAstNode("this->template"), new ezcTemplateLiteralAstNode( $this->parser->template->stream ), new ezcTemplateVariableAstNode("_ezcTemplateCache" . $this->cacheLevel ), new ezcTemplateVariableAstNode("_ezcCacheKeys") ) ) ) );
}
$cb->appendStatement( $this->_fopenCacheFileWriteMode() ); // $fp = fopen( $this->cache, "w" );
$cb->appendStatement( $this->_fwritePhpOpen() ); // fwrite( $fp, "<" . "?php\n" );
$cb->appendStatement( $this->_assignVariable(self::INTERNAL_PREFIX . "output", "total".$this->cacheLevel) );
$cb->appendStatement( $this->_assignEmptyString( self::INTERNAL_PREFIX. "output") );
}
protected function insertInCache( $cb, $type )
{
foreach ( $type->children as $element )
{
$astNode = $element->accept( $this );
if ( !is_array( $astNode ) )
{
$astNode = array($astNode);
}
foreach ( $astNode as $ast )
{
if ( $ast instanceof ezcTemplateStatementAstNode )
{
$cb->statements[] = $ast;
}
else
{
throw new ezcTemplateInternalException ("Expected an ezcTemplateStatementAstNode: ". __FILE__ . ":" . __LINE__ );
}
}
}
}
protected function stopCaching($cb, $addReturn = true)
{
$cb->appendStatement( $this->_fwriteVarExportVariable( self::INTERNAL_PREFIX . "output", true, true) );
// $total .= $_ezcTemplate_output;
$cb->appendStatement( $this->_concatAssignVariable( self::INTERNAL_PREFIX . "output", "total".$this->cacheLevel) );
// fclose($fp);
$cb->appendStatement( $this->_fclose() );
// $_ezcTemplate_output = $total;
$cb->appendStatement( $this->_assignVariable( "total".$this->cacheLevel, self::INTERNAL_PREFIX . "output" ) );
if ($addReturn)
{
$cb->appendStatement( new ezcTemplateReturnAstNode( $this->outputVariable->getAst()) );
}
}
public function visitProgramTstNode( ezcTemplateProgramTstNode $type )
{
// Is the whole template cached?
if ($this->cacheTemplate == null)
{
// Call the parent instead.
return parent::visitProgramTstNode($type);
}
// Cache the template.
$this->cacheLevel++;
$this->prepareProgram(); // Program operations, nothing to do with caching.
// Start inserting nodes, until the CacheTstNode is found.
$elemLen = sizeof( $type->children);
for( $i = 0; $i < $elemLen; $i++)
{
$element = $type->children[$i];
if ( $element instanceof ezcTemplateCacheTstNode )
{
break;
}
$astNode = $element->accept( $this );
if ( !is_array( $astNode ) )
{
$astNode = array($astNode);
}
foreach ( $astNode as $ast )
{
if ( $ast instanceof ezcTemplateStatementAstNode )
{
$this->programNode->appendStatement($ast);
}
else
{
throw new ezcTemplateInternalException ("Expected an ezcTemplateStatementAstNode: ". __FILE__ . ":" . __LINE__ );
}
}
}
// Remove the nodes already added.
$newType = array();
for ($k = $i; $k < $elemLen; $k++)
{
$newType[] = $type->children[$k];
}
$type->children = $newType;
$cacheKeys = $this->translateCacheKeys($this->cacheTemplate->keys);
$this->addCacheKeys( $this->programNode, $cacheKeys );
$ttl = $this->translateTTL($this->cacheTemplate->ttl);
$ttlStatements = $this->checkTTL( $ttl );
foreach ( $ttlStatements as $s )
{
$this->programNode->appendStatement( $s );
}
$this->createCacheDir();
$this->deleteOldCache();
// Create the if statement that checks whether the cache file exists.
$if = new ezcTemplateIfAstNode();
$if->conditions[] = $cb = new ezcTemplateConditionBodyAstNode();
$cb->condition = $this->notFileExistsCache();
$cb->body = new ezcTemplateBodyAstNode();
$this->startCaching($cb->body);
$this->insertInCache( $cb->body, $type );
// Create the 'else' part. The else should 'include' (and execute) the cached file.
$if->conditions[] = $else = new ezcTemplateConditionBodyAstNode();
$else->body = new ezcTemplateBodyAstNode();
$else->body->statements = array();
$else->body->statements[] = $this->_includeCache();
if ($this->template->usedConfiguration->cacheManager )
{
$cb->body->appendStatement( new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->usedConfiguration->cacheManager->stopCaching", array() )));
}
$this->stopCaching($cb->body);
// Outside.
$this->programNode->appendStatement( $if );
// RETURN STATEMENT outside..
$this->programNode->appendStatement( new ezcTemplateReturnAstNode( $this->outputVariable->getAst()) );
}
protected function addCacheKeys( $programNode, $cacheKeys, $cacheBlock = false )
{
$hasCacheKey = false;
$programNode->appendStatement( new ezcTemplatePhpCodeAstNode( '$_ezcCacheKeys = array();' ."\n" ) );
$cacheBlock = $cacheBlock === false ? "" : "[cb".$cacheBlock . "]";
// add the normal cache keys
foreach ( $cacheKeys as $key => $value )
{
$programNode->appendStatement( new ezcTemplatePhpCodeAstNode( '$_ezcCacheKeys[\''.$key.'\'] = '. 'is_object( $'.$value.' ) && method_exists( $'.$value.', "cacheKey" ) ? $'.$value.'->cacheKey() : $'. $value . ";\n" ) );
$hasCacheKey = true;
}
// in case we are using translations, we need to add the current locale as cache key
if ( $this->template->usedConfiguration->translation !== null )
{
$programNode->appendStatement( new ezcTemplatePhpCodeAstNode( '$_ezcCacheKeys[\'languageLocale\'] = $this->template->usedConfiguration->translation->locale;' . "\n" ) );
$cacheKeys['languageLocale'] = 'dummy';
$hasCacheKey = true;
}
if ( $hasCacheKey )
{
$code = '$_ezcTemplateCache'.$this->cacheLevel.' = \'' . $this->getCacheBaseName() . $cacheBlock ."'" ;
foreach ( $cacheKeys as $key => $value )
{
$code .= " . '-'". '. md5( var_export( $_ezcCacheKeys[\''.$key.'\'], true ))';
}
$programNode->appendStatement(new ezcTemplatePhpCodeAstNode( $code . ";\n" ) );
}
else
{
$programNode->appendStatement(new ezcTemplatePhpCodeAstNode( '$_ezcTemplateCache'.$this->cacheLevel.' = \'' . $this->getCacheBaseName() . $cacheBlock . "';\n" ) );
}
}
protected function checkTTL( $ttl )
{
$statements = array();
if ( $ttl !== null )
{
// Create the if statement that checks whether the cache file exists.
$if = new ezcTemplateIfAstNode();
$if->conditions[] = $cb = new ezcTemplateConditionBodyAstNode();
$time = new ezcTemplateFunctionCallAstNode( "time", array() );
$time->checkAndSetTypeHint();
$cb->condition = new ezcTemplateLogicalAndOperatorAstNode( new ezcTemplateFunctionCallAstNode( "file_exists", array(new ezcTemplateVariableAstNode( "_ezcTemplateCache" . $this->cacheLevel ) ) ), new ezcTemplateLessThanOperatorAstNode( new ezcTemplateAdditionOperatorAstNode( new ezcTemplateFunctionCallAstNode( "filemtime", array(new ezcTemplateVariableAstNode( "_ezcTemplateCache" . $this->cacheLevel ) )), new ezcTemplateParenthesisAstNode( $ttl ) ) , $time ) );
$cb->body = new ezcTemplateBodyAstNode();
$cb->body->statements = array();
$cb->body->statements[] = new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "unlink", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" . $this->cacheLevel ) ) ) );
$statements[] = $if;
}
return $statements;
}
public function visitReturnTstNode( ezcTemplateReturnTstNode $node )
{
if ( $this->isInDynamicBlock )
{
// Do not add additional cache stuff, because that is written by the dynamic block.
return parent::visitReturnTstNode( $node );
}
$astNodes = array();
foreach ( $node->variables as $var => $expr )
{
$assign = new ezcTemplateAssignmentOperatorAstNode();
$assign->appendParameter( $this->createVariableNode( "this->receive->" . $var ) );
if ( $expr === null )
{
if ( $this->parser->symbolTable->retrieve( $var ) == ezcTemplateSymbolTable::IMPORT )
{
$assign->appendParameter( $this->createVariableNode( "this->send->" . $var ) );
}
else
{
$assign->appendParameter( $this->createVariableNode( $var ) );
}
}
else
{
$assign->appendParameter( $expr->accept( $this ) );
}
$astNodes[] = new ezcTemplateGenericStatementAstNode( $assign );
// Add the cache .
$astNodes[] = $this->_fwriteVarExportVariable( "this->receive->" . $var , false, false );
}
// Some extra stuff.
$astNodes[] = $this->_fwriteVarExportVariable( self::INTERNAL_PREFIX . "output", true, true);
// $total .= $_ezcTemplate_output;
$astNodes[] = $this->_concatAssignVariable( self::INTERNAL_PREFIX . "output", "total".$this->cacheLevel);
// fclose($fp);
$astNodes[] = $this->_fclose();
// $_ezcTemplate_output = $total;
$astNodes[] = $this->_assignVariable( "total".$this->cacheLevel, self::INTERNAL_PREFIX . "output" );
$astNodes[] = new ezcTemplateReturnAstNode( $this->outputVariable->getAst() );
return $astNodes;
}
public function visitDynamicBlockTstNode( ezcTemplateDynamicBlockTstNode $node )
{
// Write the variables introduced in the static part to the cache.
$symbolTable = ezcTemplateSymbolTable::getInstance();
$symbols = $symbolTable->retrieveSymbolsWithType( array( ezcTemplateSymbolTable::VARIABLE, ezcTemplateSymbolTable::CYCLE ) );
$newStatement = array();
foreach ( $symbols as $s )
{
if (array_key_exists( $s, $this->declaredVariables ) )
{
$newStatement[] = $this->_fwriteVarExportVariable( "t_".$s, false, false );
}
}
$newStatement[] = $this->_comment(" ---> start {dynamic}");
// $total .= $_ezcTemplate_output
$newStatement[] = $this->_concatAssignVariable( self::INTERNAL_PREFIX . "output", "total".$this->cacheLevel);
// fwrite( $fp, "\\\<variableName> .= " . var_export( <variableName>, true) . ";" );
$newStatement[] = $this->_fwriteVarExportVariable( self::INTERNAL_PREFIX . "output", true, false);
// $_ezcTemplate_output = "";
$newStatement[] = $this->_assignEmptyString( self::INTERNAL_PREFIX . "output" );
// $output .= $_ezcTemplate_output;
$newStatement[] = $this->_concatAssignVariable( self::INTERNAL_PREFIX . "output", "total".$this->cacheLevel);
// Place everything in the code block.
$newStatement[] = new ezcTemplatePhpCodeAstNode( "\$code = '" );
$this->isInDynamicBlock = true;
$tmp = new ezcTemplateDynamicBlockAstNode( $this->createBody( $node->children ) );
$tmp->escapeSingleQuote = true;
$newStatement[] = $tmp;
$this->isInDynamicBlock = false;
// $newStatement = array();
$newStatement[] = new ezcTemplatePhpCodeAstNode( "';\n" );
// fwrite( $fp, $code );
$newStatement[] = $this->_fwriteVariable( "code" );
// eval( $code );
$retTypeVariable = $this->createVariableNode( self::INTERNAL_PREFIX ."retType" );
$newStatement[] = new ezcTemplateGenericStatementAstNode(
new ezcTemplateAssignmentOperatorAstNode( $retTypeVariable, new ezcTemplateFunctionCallAstNode( "eval", array( $this->createVariableNode( "code" ) ) ) ) );
// $total .= _ezcTemplate_output
$newStatement[] = $this->_concatAssignVariable( self::INTERNAL_PREFIX . "output", "total".$this->cacheLevel );
// $ezcTemplate_output = "";
$newStatement[] = $this->_assignEmptyString( self::INTERNAL_PREFIX . "output" );
$retTypeIf = new ezcTemplateIfAstNode();
$retTypeIf->conditions[] = $cb = new ezcTemplateConditionBodyAstNode();
$cb->condition = new ezcTemplateNotIdenticalOperatorAstNode( $retTypeVariable, new ezcTemplateLiteralAstNode(null) );
$cb->body = new ezcTemplateBodyAstNode();
$cb->body->statements = array();
$cb->body->statements[] = $this->_fclose();
$cb->body->statements[] = new ezcTemplateReturnAstNode( new ezcTemplateVariableAstNode( "total".$this->cacheLevel) );
$newStatement[] = $retTypeIf;
$newStatement[] = $this->_comment(" <--- stop {/dynamic}");
return $newStatement;
}
public function visitCacheTstNode( ezcTemplateCacheTstNode $type )
{
// This <cache_template> tst node is handled by visitProgramTstNode
return new ezcTemplateNopAstNode();
}
public function visitCacheBlockTstNode( ezcTemplateCacheBlockTstNode $type )
{
if ( $this->isInDynamicBlock )
{
throw new ezcTemplateParserException( $type->source, $type->endCursor, $type->endCursor, ezcTemplateSourceToTstErrorMessages::MSG_CACHE_BLOCK_IN_DYNAMIC_BLOCK );
}
$this->cacheLevel++;
$statements = new ezcTemplateBodyAstNode();
$cacheKeys = $this->translateCacheKeys($type->keys);
$this->addCacheKeys( $statements, $cacheKeys, $this->cacheBlockCounter++ );
$ttl = $this->translateTTL($type->ttl);
$ttlStatements = $this->checkTTL( $ttl);
foreach ( $ttlStatements as $s )
{
$statements->appendStatement( $s );
}
$this->createCacheDir();
$this->deleteOldCache();
// Create the if statement that checks whether the cache file exists.
$if = new ezcTemplateIfAstNode();
$if->conditions[] = $cb = new ezcTemplateConditionBodyAstNode();
$cb->condition = $this->notFileExistsCache();
$cb->body = new ezcTemplateBodyAstNode();
$this->startCaching($cb->body);
$this->insertInCache( $cb->body, $type );
// Create the 'else' part. The else should 'include' (and execute) the cached file.
$if->conditions[] = $else = new ezcTemplateConditionBodyAstNode();
$else->body = new ezcTemplateBodyAstNode();
$else->body->statements = array();
$else->body->statements[] = $this->_includeCache();
if ($this->template->usedConfiguration->cacheManager )
{
$cb->body->appendStatement( new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->usedConfiguration->cacheManager->stopCaching", array() )));
}
$this->stopCaching($cb->body, false);
// Outside.
$statements->appendStatement( $if );
$this->cacheLevel--;
return $statements->statements;
}
/**
* visitTranslationTstNode
*
* @param ezcTemplateTranslationTstNode $node
* @return ezcTemplateNopAstNode
*/
public function visitTranslationTstNode( ezcTemplateTranslationTstNode $node )
{
// if we're not in a cache block, call the normal (non-cached) TST->AST convertor
if ( !$this->cacheLevel )
{
return parent::visitTranslationTstNode( $node );
}
// convert arguments
$string = $node->string->accept( $this );
// check for the translation context. If we have one, we use it. If we
// don't have one, we check whether there is one set through a
// tr_context block. If not, we default to an empty string.
if ( $node->context !== null )
{
$context = $node->context->accept( $this );
}
else
{
if ( $this->programNode->translationContext !== null )
{
$context = new ezcTemplateLiteralAstNode( $this->programNode->translationContext->value );
}
else
{
$context = new ezcTemplateLiteralAstNode( '' );
}
}
// the array of parameters we need to do something special with, so we
// retrieve it and clone so that we can mangle it as much as we want.
$compileArray = new ezcTemplateLiteralArrayAstNode();
if ( $node->variables !== null )
{
$array = $node->variables->accept( $this );
$compileArray = clone $array;
foreach ( $compileArray->value as $key => $value )
{
$g = new ezcTemplateAstToPhpStringGenerator( $this->template->usedConfiguration );
$value->accept( $g );
$newValue = new ezcTemplateLiteralAstNode( $g->getString() );
$compileArray->value[$key] = $newValue;
// Make the numerical indexes 1 based
if ( !isset( $compileArray->keys[$key] ) )
{
$compileArray->keys[$key] = new ezcTemplateLiteralAstNode( $index );
$index++;
}
if ( is_numeric( $compileArray->keys[$key]->value ))
{
$index = ( (int) $compileArray->keys[$key]->value ) + 1;
$compileArray->keys[$key]->value = (int) $compileArray->keys[$key]->value;
}
}
}
// return all the generated nodes
return array(
new ezcTemplateEolCommentAstNode( " ---> start {tr}" ),
// we reset the output and total vars here
$this->_fwriteVarExportVariable( self::INTERNAL_PREFIX . "output", true, false),
$this->_concatAssignVariable( self::INTERNAL_PREFIX . "output", "total" . $this->cacheLevel ),
$this->_assignEmptyString( self::INTERNAL_PREFIX . "output" ),
// the code that ends up in the cache block
new ezcTemplateGenericStatementAstNode(
new ezcTemplateConcatOperatorAstNode(
new ezcTemplateConcatOperatorAstNode(
new ezcTemplateConcatAssignmentOperatorAstNode(
$this->getFp(), new ezcTemplateLiteralAstNode( "\$" . self::INTERNAL_PREFIX . 'output' . " .= " )
),
new ezcTemplateFunctionCallAstNode( 'ezcTemplateTranslationProvider::compile', array( $string, $context, $compileArray ) )
),
new ezcTemplateLiteralAstNode( ";\n" )
)
),
// the code that is executed during template compilation
new ezcTemplateGenericStatementAstNode(
new ezcTemplateConcatAssignmentOperatorAstNode(
$this->createVariableNode( 'total' . $this->cacheLevel ),
new ezcTemplateFunctionCallAstNode( 'ezcTemplateTranslationProvider::translate', array( $string, $context, $array ) )
)
),
new ezcTemplateEolCommentAstNode( " <--- stop {tr}" ),
);
}
}
?>