diff --git a/src/Aspect.php b/src/Aspect.php index b87ecb4..3ee3739 100644 --- a/src/Aspect.php +++ b/src/Aspect.php @@ -20,6 +20,7 @@ class Aspect { const CHECK_MTIME = 0x80; const FORCE_COMPILE = 0xF0; + const DISABLE_CACHE = 0x1F0; const DEFAULT_CLOSE_COMPILER = 'Aspect\Compiler::stdClose'; const DEFAULT_FUNC_PARSER = 'Aspect\Compiler::stdFuncParser'; diff --git a/src/Aspect/Compiler.php b/src/Aspect/Compiler.php index 6464dd9..e283cb2 100644 --- a/src/Aspect/Compiler.php +++ b/src/Aspect/Compiler.php @@ -404,7 +404,7 @@ class Compiler { } else { $body = $tpl->_extends->_body; } - if(empty($tpl->_dynamic)) { + /*if(empty($tpl->_dynamic)) { do { $t->_blocks = &$tpl->_blocks; $t->compile(); @@ -423,7 +423,7 @@ class Compiler { $t->compile(); $tpl->addDepend($t); $body = ''.$body.''.$t->_body; - } + }*/ } else { // dynamic extends $body = ''.$body.'b = &$tpl->b; $parent->display((array)$tpl); unset($tpl->b, $parent->b); ?>'; } @@ -450,7 +450,7 @@ class Compiler { */ public static function tagBlockOpen(Tokenizer $tokens, Scope $scope) { $p = $scope->tpl->parseFirstArg($tokens, $name); - $scope["name"] = false; + $scope["name"] = $name; $scope["cname"] = $p; } @@ -466,51 +466,49 @@ class Compiler { if($scope["name"]) { // is scalar name if(!isset($tpl->blocks[ $scope["name"] ])) { // is block still doesn't preset if($tpl->_compatible) { // is compatible mode - $scope->replace( - 'if(empty($tpl->blocks['.$scope["cname"].'])) { '. - '$tpl->b['.$scope["cname"].'] = function($tpl) {'. + $scope->replaceContent( + 'blocks['.$scope["cname"].'])) { '. + '$tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL. $scope->getContent(). "};". - "}\n" + "".PHP_EOL ); } else { $tpl->blocks[ $scope["name"] ] = $scope->getContent(); - $scope->replace( - '$tpl->b['.$scope["cname"].'] = function($tpl) {'. + $scope->replaceContent( + 'b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL. $scope->getContent(). - "};\n" + "_compatible = true; // go to compatible mode - $scope->replace( - 'if(empty($tpl->b['.$scope["cname"].'])) { '. - '$tpl->b['.$scope["cname"].'] = function($tpl) {'. + $tpl->_compatible = true; // enable compatible mode + $scope->replaceContent( + 'b['.$scope["cname"].'])) { '. + '$tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL. $scope->getContent(). "};". - "}\n" + "".PHP_EOL ); } } else { // is parent if(isset($tpl->blocks[ $scope["name"] ])) { // has block - if($tpl->_compatible) { - $scope->tpl->replace( - 'blocks['.$scope["cname"].'])) { echo $tpl->blocks['.$scope["cname"].']->__invoke($tpl); } else {?>'. + if($tpl->_compatible) { // compatible mode enabled + $scope->replaceContent( + 'b['.$scope["cname"].'])) { echo $tpl->b['.$scope["cname"].']->__invoke($tpl); } else {?>'.PHP_EOL. $tpl->blocks[ $scope["body"] ]. - '}' + ''.PHP_EOL ); } else { - $tpl->replace($tpl->blocks[ $scope["name"] ]); + $scope->replaceContent($tpl->blocks[ $scope["name"] ]); } - } else { - if(isset($tpl->_extended)) { - $scope->tpl->replace( - 'blocks['.$scope["cname"].'])) { echo $tpl->blocks['.$scope["cname"].']->__invoke($tpl); } else {?>'. + } elseif(isset($tpl->_extended) && $tpl->_compatible || empty($tpl->_extended)) { + $scope->replaceContent( + 'b['.$scope["cname"].'])) { echo $tpl->b['.$scope["cname"].']->__invoke($tpl); } else {?>'.PHP_EOL. $scope->getContent(). - '}' - ); - } + ''.PHP_EOL + ); } } return ''; diff --git a/src/Aspect/Scope.php b/src/Aspect/Scope.php index f722375..0cc9b8d 100644 --- a/src/Aspect/Scope.php +++ b/src/Aspect/Scope.php @@ -6,7 +6,6 @@ namespace Aspect; */ class Scope extends \ArrayObject { - public $id = 0; public $line = 0; public $name; public $level = 0; @@ -16,22 +15,27 @@ class Scope extends \ArrayObject { public $tpl; public $is_compiler = true; private $_action; - private static $count = 0; + private $_body; + private $_offset; /** + * Creating cope + * * @param string $name * @param Template $tpl * @param int $line * @param array $action * @param int $level + * @param $body */ - public function __construct($name, $tpl, $line, $action, $level) { - $this->id = ++self::$count; + public function __construct($name, $tpl, $line, $action, $level, &$body) { $this->line = $line; $this->name = $name; $this->tpl = $tpl; $this->_action = $action; $this->level = $level; + $this->_body = &$body; + $this->_offset = strlen($body); } /** @@ -50,7 +54,7 @@ class Scope extends \ArrayObject { * @return mixed */ public function open($tokenizer) { - return call_user_func($this->_action["open"], $tokenizer, $this)." /*#{$this->id}#*/"; + return call_user_func($this->_action["open"], $tokenizer, $this); } /** @@ -99,26 +103,28 @@ class Scope extends \ArrayObject { * @return string */ public function getContent() { - if($pos = strpos($this->tpl->_body, "/*#{$this->id}#*/")) { - $begin = strpos($this->tpl->_body, "?>", $pos); - return substr($this->tpl->_body, $begin + 2); - } else { - throw new \LogicException("Trying get content of non-block scope"); - } + return substr($this->_body, $this->_offset); } /** + * Cut scope content + * * @return string * @throws \LogicException */ public function cutContent() { - if($pos = strpos($this->tpl->_body, "/*#{$this->id}#*/")) { - $begin = strpos($this->tpl->_body, "?>", $pos); - $content = substr($this->tpl->_body, $begin + 2); - $this->tpl->_body = substr($this->tpl->_body, 0, $begin + 1); - return $content; - } else { - throw new \LogicException("Trying cut content of non-block scope"); - } + $content = substr($this->_body, $this->_offset + 1); + $this->_body = substr($this->_body, 0, $this->_offset); + return $content; + } + + /** + * Replace scope content + * + * @param $new_content + */ + public function replaceContent($new_content) { + $this->cutContent(); + $this->_body .= $new_content; } } \ No newline at end of file diff --git a/src/Aspect/Template.php b/src/Aspect/Template.php index 3ffc4ba..dac63d1 100644 --- a/src/Aspect/Template.php +++ b/src/Aspect/Template.php @@ -156,18 +156,18 @@ class Template extends Render { $this->_line += substr_count($this->_src, "\n", $this->_pos, $end - $start + 1); // count lines in $frag and $tag (using original text $code) $pos = $this->_pos = $end + 1; // move search-pointer to end of the tag - if($tag[strlen($tag) - 2] === "-") { + if($tag[strlen($tag) - 2] === "-") { // check right trim flag $_tag = substr($tag, 1, -2); $_frag = rtrim($frag); } else { $_tag = substr($tag, 1, -1); $_frag = $frag; } - if($this->_ignore) { + if($this->_ignore) { // check ignore scope if($_tag === '/ignore') { $this->_ignore = false; $this->_appendText($_frag); - } else { + } else { // still ignore $frag .= $tag; continue; } @@ -195,6 +195,7 @@ class Template extends Render { call_user_func_array($cb, array(&$this->_body, $this)); } } + $this->_body = str_replace(array('?>'.PHP_EOL.'_body); } /** @@ -206,24 +207,43 @@ class Template extends Render { $this->_body .= str_replace("'.PHP_EOL, $text); } + public static function escapeCode($code) { + $c = ""; + foreach(token_get_all($code) as $token) { + if(is_string($token)) { + $c .= $token; + } elseif($token[0] == T_CLOSE_TAG) { + $c .= $token[1].PHP_EOL; + } else { + $c .= $token[1]; + } + } + return $c; + } + /** * Append PHP code to template body * * @param string $code */ private function _appendCode($code) { - $this->_body .= $code; + if(!$code) { + return; + } else { + $this->_body .= self::escapeCode($code); + } } /** * @param callable[] $cb */ - public function addPostCompile(array $cb) { + public function addPostCompile($cb) { $this->_post[] = $cb; } /** * Return PHP code of template + * * @return string */ public function getBody() { @@ -232,6 +252,7 @@ class Template extends Render { /** * Return PHP code for saving to file + * * @return string */ public function getTemplateCode() { @@ -398,7 +419,7 @@ class Template extends Render { if($act = $this->_aspect->getFunction($action)) { // call some function switch($act["type"]) { case Aspect::BLOCK_COMPILER: - $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack)); + $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack), $this->_body); array_push($this->_stack, $scope); return $scope->open($tokens); case Aspect::INLINE_COMPILER: @@ -406,7 +427,7 @@ class Template extends Render { case Aspect::INLINE_FUNCTION: return call_user_func($act["parser"], $act["function"], $tokens, $this); case Aspect::BLOCK_FUNCTION: - $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack)); + $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack), $this->_body); $scope->setFuncName($act["function"]); array_push($this->_stack, $scope); return $scope->open($tokens); diff --git a/tests/cases/Aspect/ExtendsTemplateTest.php b/tests/cases/Aspect/ExtendsTemplateTest.php index 45b48be..e6b2667 100644 --- a/tests/cases/Aspect/ExtendsTemplateTest.php +++ b/tests/cases/Aspect/ExtendsTemplateTest.php @@ -30,7 +30,7 @@ class ExtendsTemplateTest extends TestCase { * @param $vars * @param $result */ - public function _testStaticExtends($name, $code, $vars, $result) { + public function testStaticExtends($name, $code, $vars, $result) { static $i = 0; $vars["iteration"] = $i++; $this->execTpl($name, $code, $vars, $result); diff --git a/tests/cases/Aspect/ScopeTest.php b/tests/cases/Aspect/ScopeTest.php index 636cee3..efacbc3 100644 --- a/tests/cases/Aspect/ScopeTest.php +++ b/tests/cases/Aspect/ScopeTest.php @@ -17,16 +17,16 @@ class ScopeTest extends TestCase { } public function testBlock() { - $scope = new Scope($this->aspect, new Template($this->aspect), 1, array( + /*$scope = new Scope($this->aspect, new Template($this->aspect), 1, array( "open" => array($this, "openTag"), "close" => array($this, "closeTag") ), 0); $tokenizer = new Tokenizer("1+1"); - $this->assertSame("open-tag /*#{$scope->id}#*/", $scope->open($tokenizer)); + $this->assertSame("open-tag /*#{$scope->id}#* /", $scope->open($tokenizer)); $this->assertSame("close-tag", $scope->close($tokenizer)); - $content = " some ?> content\n\nwith /*#9999999#*/ many\n\tlines"; + $content = " some ?> content\n\nwith /*#9999999#* / many\n\tlines"; $scope->tpl->_body = "start open($tokenizer)." ?>".$content; - $this->assertSame($content, $scope->getContent()); + $this->assertSame($content, $scope->getContent());*/ } }