Author: Raymond Bosman Date: 2007-02-07 15:16:25 +0100 (Wed, 07 Feb 2007) New Revision: 4629
Log: - Some tests. # needs code cleanup Added: trunk/Template/tests/cache_manager_test.php trunk/Template/tests/db_cache_manager.php trunk/Template/tests/templates/cache_manager_with_keys.tpl trunk/Template/tests/templates/cache_simple_include.tpl trunk/Template/tests/templates/hello_world.tpl trunk/Template/tests/templates/show_users.ezt trunk/Template/tests/templates/user_info.ezt Modified: trunk/Template/src/parsers/tst_to_ast/implementations/tst_to_ast_cached_transformer.php trunk/Template/src/template.php Modified: trunk/Template/src/parsers/tst_to_ast/implementations/tst_to_ast_cached_transformer.php =================================================================== --- trunk/Template/src/parsers/tst_to_ast/implementations/tst_to_ast_cached_transformer.php 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/src/parsers/tst_to_ast/implementations/tst_to_ast_cached_transformer.php 2007-02-07 14:16:25 UTC (rev 4629) @@ -217,7 +217,7 @@ if( $this->template->configuration->cacheManager !== false ) { // !$this->template->configuration->cacheManager->isValid( $cacheName ) || !file_exist() - $a = new ezcTemplateLogicalNegationOperatorAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->configuration->cacheManager->isValid", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" ), new ezcTemplateLiteralAstNode( $this->parser->template->stream ) ) ) ); + $a = new ezcTemplateLogicalNegationOperatorAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->configuration->cacheManager->isValid", array( new ezcTemplateVariableAstNode( "this->template"), new ezcTemplateLiteralAstNode( $this->parser->template->stream ), new ezcTemplateVariableAstNode( "_ezcTemplateCache" ) ) ) ); $b = new ezcTemplateLogicalNegationOperatorAstNode( new ezcTemplateFunctionCallAstNode( "file_exists", array( new ezcTemplateVariableAstNode( "_ezcTemplateCache" ) ) ) ); return new ezcTemplateLogicalOrOperatorAstNode( $a, $b ); @@ -244,11 +244,12 @@ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $cacheKeys = array(); - foreach ( $this->cacheInfo->keys as $key ) + foreach ( $this->cacheInfo->keys as $key => $value ) { // Translate the 'old' variableName to the new name. - $k = $key->accept($this); - $cacheKeys[] = $k->name; + $k = $value->accept($this); + + $cacheKeys[str_replace( "this->send->", "use:" , $k->name )] = $k->name; } //$this->cacheSystem->setCacheKeys( $cacheKeys ); @@ -299,9 +300,10 @@ /// startCaching(); + $cplen = strlen( $this->parser->template->configuration->compilePath ); if ($this->template->configuration->cacheManager !== false ) { - $cb->body->appendStatement( new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->configuration->cacheManager->startCaching", array( new ezcTemplateVariableAstNode("_ezcTemplateCache" ), new ezcTemplateLiteralAstNode( $this->parser->template->stream ) ) ) ) ); + $cb->body->appendStatement( new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->configuration->cacheManager->startCaching", array( new ezcTemplateVariableAstNode("this->template"), new ezcTemplateLiteralAstNode( $this->parser->template->stream ), new ezcTemplateVariableAstNode("_ezcTemplateCache" ), new ezcTemplateVariableAstNode("_ezcCacheKeys") ) ) ) ); } $cb->body->appendStatement( $this->_fopenCacheFileWriteMode() ); // $fp = fopen( $this->cache, "w" ); @@ -379,6 +381,7 @@ $this->programNode->appendStatement( $use ); } + $this->addCacheKeys( $this->programNode, $cacheKeys ); $ttlStatements = $this->checkTTL( $ttl, $cacheKeys ); foreach ( $ttlStatements as $s ) @@ -395,32 +398,45 @@ } } - protected function createCacheVariable( $cacheKeys ) + + protected function addCacheKeys( $programNode, $cacheKeys ) { - $code = '$_ezcTemplateCache = \'' . $this->getCacheBaseName() ."'"; + $hasCacheKey = false; + $programNode->appendStatement( new ezcTemplatePhpCodeAstNode( '$_ezcCacheKeys = array();' ."\n" ) ); - $st = ezcTemplateSymbolTable::getInstance(); - - foreach ( $cacheKeys as $key ) + foreach ( $cacheKeys as $key => $value ) { - // md5( var_export( is_object( $key ) && method_exists( $key, "cacheKey" ) ? $key->cacheKey() : $key ) ) + $programNode->appendStatement( new ezcTemplatePhpCodeAstNode( '$_ezcCacheKeys[\''.$key.'\'] = '. 'is_object( $'.$value.' ) && method_exists( $'.$value.', "cacheKey" ) ? $'.$value.'->cacheKey() : $'. $value . ";\n" ) ); - $code .= '.\'-\'. md5( var_export( is_object( $'.$key.' ) && method_exists( $'.$key.', "cacheKey" ) ? $'.$key.'->cacheKey() : $'. $key . ', true ) ) '; +// $programNode->appendStatement( new ezcTemplatePhpCodeAstNode( '$_ezcCacheKeys[\''.$value.'\'] = '. 'md5( var_export( is_object( $'.$value.' ) && method_exists( $'.$value.', "cacheKey" ) ? $'.$value.'->cacheKey() : $'. $value . ', true ) )' . ";\n" ) ); + + + $hasCacheKey = true; } - $code .= ";\n"; + if( $hasCacheKey ) + { + $code = '$_ezcTemplateCache = \'' . $this->getCacheBaseName() . "'" ; + foreach ( $cacheKeys as $key => $value ) + { + $code .= " . '-'". '. md5( var_export( $_ezcCacheKeys[\''.$key.'\'], true ))'; + } - return new ezcTemplatePhpCodeAstNode( $code ); + $programNode->appendStatement(new ezcTemplatePhpCodeAstNode( $code . ";\n" ) ); + } + else + { + $programNode->appendStatement(new ezcTemplatePhpCodeAstNode( '$_ezcTemplateCache = \'' . $this->getCacheBaseName() . "';\n" ) ); + } + + //$code = '$_ezcTemplateCache = \'' . $this->getCacheBaseName() . '-\' '. ( $hasCacheKey ? ' . implode("-", array_map("md5", array_map("var_export",$_ezcCacheKeys), array_fill(0, sizeof($_ezcCacheKeys), true ) ) )' : '' ) . ";\n"; + //$programNode->appendStatement(new ezcTemplatePhpCodeAstNode( $code ) ); } - protected function checkTTL( $ttl, $cacheKeys ) { $statements = array(); - $statements[] = $this->createCacheVariable( $cacheKeys ); - - if ( $ttl !== null ) { // Create the if statement that checks whether the cache file exists. @@ -602,23 +618,6 @@ return $cb; } } - - - /* - public function visitIncludeTstNode( ezcTemplateIncludeTstNode $type ) - { - $ast = parent::visitIncludeTstNode( $type ); - - if ($this->template->configuration->cacheManager !== false ) - { - $n = $type->file->accept( $this ); // Can go wrong, shouldn't be executed twice. TODO, XXX - $ast[] = new ezcTemplateGenericStatementAstNode( new ezcTemplateFunctionCallAstNode( "\$this->template->configuration->cacheManager->includeTemplate", array( new ezcTemplateLiteralAstNode( $n->value ) ) ) ); - } - - return $ast; - } - */ - } ?> Modified: trunk/Template/src/template.php =================================================================== --- trunk/Template/src/template.php 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/src/template.php 2007-02-07 14:16:25 UTC (rev 4629) @@ -339,7 +339,7 @@ // Add to the cache system. if ($this->configuration->cacheManager !== false ) { - $this->configuration->cacheManager->includeTemplate( $this->properties["stream"]); + $this->configuration->cacheManager->includeTemplate( $this, $this->properties["stream"]); } } Added: trunk/Template/tests/cache_manager_test.php =================================================================== --- trunk/Template/tests/cache_manager_test.php 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/tests/cache_manager_test.php 2007-02-07 14:16:25 UTC (rev 4629) @@ -0,0 +1,212 @@ +<?php +/** + * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + * @version //autogentag// + * @filesource + * @package Template + * @subpackage Tests + */ + +require "db_cache_manager.php"; +require "fetch.php"; + + +/** + * @package Template + * @subpackage Tests + */ +class ezcTemplateCacheTest extends ezcTestCase +{ + private $tempDir; + private $basePath; + private $templatePath; + + public static function suite() + { + return new PHPUnit_Framework_TestSuite( __CLASS__ ); + } + + protected function setUp() + { + $this->basePath = realpath( dirname( __FILE__ ) ) . '/'; + + $config = ezcTemplateConfiguration::getInstance(); + $this->tempDir = $config->compilePath = $this->createTempDir( "ezcTemplate_" ); + $config->templatePath = $this->basePath . 'templates/'; + + $config->cacheManager = new DbCacheManager(); + + // Create tables. + // + + $db = ezcDbInstance::get(); + + try + { + $db->exec( 'DROP TABLE user' ); + } + catch ( Exception $e ) {} // eat + + // insert some data + $db->exec( "CREATE TABLE user ( id int(10) unsigned NOT NULL auto_increment, + name varchar(50) NOT NULL, + nickname varchar(30) NOT NULL, + PRIMARY KEY (id) )" ); + + $db->exec ( "INSERT INTO `user` (`id`, `name`, `nickname`) VALUES + (1, 'Raymond', 'sunRay'), + (2, 'Derick', 'Tiger'), + (3, 'Jan', 'Amos')" ); + + } + + protected function tearDown() + { + // Remove tables. + $db = ezcDbInstance::get(); + $db->exec( 'DROP TABLE user' ); + } + + public function testRenewIncludedTemplates() + { + $t = new ezcTemplate(); + $t->configuration->templatePath = $this->tempDir; + + copy( $this->basePath."/templates/cache_simple_include.tpl", $this->tempDir . "/cache_simple_include.tpl" ); + copy( $this->basePath."/templates/hello_world.tpl", $this->tempDir . "/hello_world.tpl" ); + + $t->send->a = "Bernard"; + $r = $t->process( "cache_simple_include.tpl" ); + $this->assertEquals( "\nBernard\nHello world\n", $r ); + + // Old value expected. $a is not a cache key. + $t->send->a = "Bla"; + $r = $t->process( "cache_simple_include.tpl" ); + $this->assertEquals( "\nBernard\nHello world\n", $r ); + + // Simulate someone edits the template + sleep(1); // Otherwise the mtime is the same. + file_put_contents( $this->tempDir . "/hello_world.tpl", "Goodbye cruel world!"); + + $t->send->a = "Bla"; + $r = $t->process( "cache_simple_include.tpl" ); + $this->assertEquals( "\nBla\nGoodbye cruel world!", $r ); + } + + public function testRenewUserViaTemplateFetch() + { + $t = new ezcTemplate(); + $t->configuration->addExtension("Fetch"); + + $r = $t->process("show_users.ezt"); + $this->assertEquals( "\n\n\n\n1 Raymond sunRay\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + + // Update a single user. + $db = ezcDbInstance::get(); + $db->exec( 'UPDATE user SET nickname="bla" WHERE id=1' ); + + // Still cached. + $r = $t->process("show_users.ezt"); + $this->assertEquals( "\n\n\n\n1 Raymond sunRay\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + + // Send a update signal to the configuration manager. + ezcTemplateConfiguration::getInstance()->cacheManager->update("user", 1 ); + + $r = $t->process("show_users.ezt"); + $this->assertEquals( "\n\n\n\n1 Raymond bla\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + } + + public function testSignals() + { + $t = new ezcTemplate(); + $t->configuration->addExtension("Fetch"); + + $r = $t->process("show_users.ezt"); + $this->assertEquals( "\n\n\n\n1 Raymond sunRay\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + + + $r = $t->process("show_users.ezt"); + + +// $r = $t->process("show_users.ezt"); +// $this->assertEquals( "\n\n\n\n1 Raymond sunRay\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); +// +// // Update a single user. +// $db = ezcDbInstance::get(); +// $db->exec( 'UPDATE user SET nickname="bla" WHERE id=1' ); +// +// // Still cached. +// $r = $t->process("show_users.ezt"); +// $this->assertEquals( "\n\n\n\n1 Raymond sunRay\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); +// +// // Send a update signal to the configuration manager. +// ezcTemplateConfiguration::getInstance()->cacheManager->update("user", 1 ); +// +// $r = $t->process("show_users.ezt"); +// $this->assertEquals( "\n\n\n\n1 Raymond bla\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + } + + + public function testCacheKeys() + { + $t = new ezcTemplate(); + $t->configuration->addExtension("Fetch"); + + $t->send->id = 1; + $t->send->name = "aaa"; + $r = $t->process("cache_manager_with_keys.tpl"); + + + + + +/* + $this->assertEquals( "\n\n\n\n1 Raymond sunRay\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + + // Update a single user. + $db = ezcDbInstance::get(); + $db->exec( 'UPDATE user SET nickname="bla" WHERE id=1' ); + + // Still cached. + $r = $t->process("show_users.ezt"); + $this->assertEquals( "\n\n\n\n1 Raymond sunRay\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + + // Send a update signal to the configuration manager. + ezcTemplateConfiguration::getInstance()->cacheManager->update("user", 1 ); + + $r = $t->process("show_users.ezt"); + $this->assertEquals( "\n\n\n\n1 Raymond bla\n\n2 Derick Tiger\n\n3 Jan Amos\n", $r ); + */ + + } + + + +} + + +class TestUser +{ + public $firstName; + public $lastName; + public $name; + public $id; + + public function cacheKey() + { + return $this->id; + } + + public function __construct($firstName, $lastName, $id = 1 ) + { + $this->firstName = $firstName; + $this->lastName = $lastName; + $this->name = $firstName . " " . $lastName; + $this->id = $id; + } +} + + + +?> Property changes on: trunk/Template/tests/cache_manager_test.php ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/Template/tests/db_cache_manager.php =================================================================== --- trunk/Template/tests/db_cache_manager.php 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/tests/db_cache_manager.php 2007-02-07 14:16:25 UTC (rev 4629) @@ -0,0 +1,162 @@ +<?php + +class DbCacheManager +{ + protected $keys = array(); + protected $depth = -1; + + public function startCaching($template, $templatePath, $cachePath, $cacheKeys ) + { + + ezcSignalStaticConnections::getInstance()->connect( "UserBla", "ezcTemplateCacheRead", array( ezcTemplateConfiguration::getInstance()->cacheManager, "read" ) ); + + // INSERT NEW cache. + $db = ezcDbInstance::get(); + + $q = $db->prepare("SELECT id FROM cache_templates WHERE cache = :cache" ); + $q->bindValue( ":cache", $cachePath ); + $q->execute(); + + $r = $q->fetchAll(); + + if( sizeof( $r ) > 0 ) + { + foreach( $r as $x ) + { + $id = $x["id"]; + + // Reset the expired IDs. + $s = $db->prepare( "UPDATE cache_templates SET expired=0 WHERE id = :id" ); + $s->bindValue( ":id", $x["id"] ); + $s->execute(); + } + } + else + { + $q = $db->prepare("INSERT INTO cache_templates VALUES( '', :cache, '', 0)" ); + $q->bindValue( ":cache", $cachePath ); + $q->execute(); + $id = $db->lastInsertId(); + + + // Insert your own template in the value table. + $q = $db->prepare("REPLACE INTO cache_values VALUES(:id, :name, :value)" ); + $q->bindValue( ":id", $id ); + $q->bindValue( ":name", "include" ); + $q->bindValue( ":value", $templatePath ); + $q->execute(); + + } + + $this->depth++; + array_push( $this->keys, array( "cache_path" => $cachePath, "template_id" => $id)); + } + + public function stopCaching() + { + ezcSignalStaticConnections::getInstance()->disconnect( "UserBla", "ezcTemplateCacheRead", array( ezcTemplateConfiguration::getInstance()->cacheManager, "read" ) ); + + $this->depth--; + array_pop( $this->keys); + } + + public function isValid( $template, $templateName, $cacheName ) + { + $db = ezcDbInstance::get(); + $q = $db->prepare("SELECT expired FROM cache_templates WHERE cache LIKE :cache" ); + $q->bindValue( ":cache", $cacheName ); + $q->execute(); + + $rows = $q->fetchAll(); + + if( count( $rows) === 0 ) return false; + + // SLOW! + foreach( $rows as $r ) + { + if( $r["expired"] == 1 ) return false; + } + + $q = $db->prepare("SELECT id FROM cache_templates WHERE cache = :cache" ); + $q->bindValue( ":cache", $cacheName ); + $q->execute(); + $r = $q->fetchAll(); + + + $q = $db->prepare( "SELECT * FROM cache_values WHERE name = 'include' AND template_id = :id"); + $q->bindValue( ":id", $r[0]["id"] ); + $q->execute(); + + $rows = $q->fetchAll(); + foreach( $rows as $r ) + { + if( filemtime( $r["value"] ) > filemtime( $cacheName ) ) + { + return false; + } + } + + return true; + } + + public function isCached( $templateName ) + { + $db = ezcDbInstance::get(); + $q = $db->prepare("SELECT expired FROM cache_templates WHERE cache LIKE :cache" ); + $q->bindValue( ":cache", $cacheName ); + $q->execute(); + } + + + public function update($name, $value) + { + + $db = ezcDbInstance::get(); + $s = $db->prepare( "UPDATE cache_templates, cache_values SET cache_templates.expired=1 WHERE cache_templates.id = cache_values.template_id AND cache_values.name = :name AND cache_values.value = :value" ); + $s->bindValue( ":name", $name ); + $s->bindValue( ":value", $value ); + $s->execute(); + + + } + + public function read( $name, $value ) + { + + // We don't care about reading of non-cached files. + if( $this->depth < 0 ) return; + + + // From user_list, when cache is created. + + $db = ezcDbInstance::get(); + $s = $db->prepare( "REPLACE INTO cache_values VALUES ( :id, :name, :value )" ); + $s->bindValue( ":id", $this->keys[$this->depth]["template_id"] ); + $s->bindValue( ":name", $name ); + $s->bindValue( ":value", $value ); + $s->execute(); + + // Updated the values. If this value changes, the template should be renewed. + } + + + public function includeTemplate( $template, $template_path ) + { + if( $this->depth >= 0 ) + { + // echo ("DEPTH!"); + $db = ezcDbInstance::get(); + $id = $this->keys[ $this->depth ]["template_id"]; + + // Insert your parent template in the value table. + $q = $db->prepare("REPLACE INTO cache_values VALUES(:id, :name, :value)" ); + $q->bindValue( ":id", $id ); + $q->bindValue( ":name", "include" ); + $q->bindValue( ":value", $template_path ); + $q->execute(); + } + } + +} + +?> Property changes on: trunk/Template/tests/db_cache_manager.php ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/Template/tests/templates/cache_manager_with_keys.tpl =================================================================== --- trunk/Template/tests/templates/cache_manager_with_keys.tpl 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/tests/templates/cache_manager_with_keys.tpl 2007-02-07 14:16:25 UTC (rev 4629) @@ -0,0 +1,6 @@ +{use $id, $name} + +{cache_template keys $id} + +{$id} +{$name} Property changes on: trunk/Template/tests/templates/cache_manager_with_keys.tpl ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/Template/tests/templates/cache_simple_include.tpl =================================================================== --- trunk/Template/tests/templates/cache_simple_include.tpl 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/tests/templates/cache_simple_include.tpl 2007-02-07 14:16:25 UTC (rev 4629) @@ -0,0 +1,4 @@ +{use $a} +{cache_template} +{$a} +{include "hello_world.tpl"} Property changes on: trunk/Template/tests/templates/cache_simple_include.tpl ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/Template/tests/templates/hello_world.tpl =================================================================== --- trunk/Template/tests/templates/hello_world.tpl 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/tests/templates/hello_world.tpl 2007-02-07 14:16:25 UTC (rev 4629) @@ -0,0 +1 @@ +Hello world Property changes on: trunk/Template/tests/templates/hello_world.tpl ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/Template/tests/templates/show_users.ezt =================================================================== --- trunk/Template/tests/templates/show_users.ezt 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/tests/templates/show_users.ezt 2007-02-07 14:16:25 UTC (rev 4629) @@ -0,0 +1,8 @@ +{use $offset = 0, $limit = 4} +{cache_template keys $offset, $limit} + +{var $a = fetch_user_list($offset, $limit)} + +{foreach $a as $b} + {include "user_info.ezt" send $b} +{/foreach} Property changes on: trunk/Template/tests/templates/show_users.ezt ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/Template/tests/templates/user_info.ezt =================================================================== --- trunk/Template/tests/templates/user_info.ezt 2007-02-06 15:25:49 UTC (rev 4628) +++ trunk/Template/tests/templates/user_info.ezt 2007-02-07 14:16:25 UTC (rev 4629) @@ -0,0 +1,4 @@ +{use $b} +{cache_template keys $b} +{$b->id} {$b->name} {$b->nickname} + Property changes on: trunk/Template/tests/templates/user_info.ezt ___________________________________________________________________ Name: svn:eol-style + native -- svn-components mailing list svn-components@lists.ez.no http://lists.ez.no/mailman/listinfo/svn-components