From a5d6a76cf46cfaf35b233357bfe4a46b27d74782 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sun, 22 Oct 2023 00:46:58 +0900 Subject: [PATCH] Add parent reference to Template instances --- common/framework/Template.php | 51 ++++++++++++++++--- .../parsers/template/TemplateParser_v2.php | 2 +- .../parsers/TemplateParserV2Test.php | 22 ++++---- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/common/framework/Template.php b/common/framework/Template.php index 9d743d069..0443918cf 100644 --- a/common/framework/Template.php +++ b/common/framework/Template.php @@ -13,9 +13,16 @@ class Template public $user; /** - * Properties for internal use + * Properties for configuration */ public $config; + public $source_type; + public $parent; + public $vars; + + /** + * Properties for path manipulation + */ public $absolute_dirname; public $relative_dirname; public $filename; @@ -23,17 +30,23 @@ class Template public $exists; public $absolute_path; public $relative_path; - public $cache_path; + + /** + * Properties for caching + */ public $cache_enabled = true; - public $source_type; - public $ob_level; - public $vars; + public $cache_path; + + /** + * Properties for state management during compilation/execution + */ + protected $_ob_level; protected $_fragments = []; protected static $_loopvars = []; protected static $_stacks = []; /** - * Static properties + * Properties for optimization */ protected static $_mtime; protected static $_delay_compile; @@ -191,6 +204,27 @@ class Template return $this->exists ? true : false; } + /** + * Get the parent template. + * + * @return ?self + */ + public function getParent(): ?self + { + return $this->parent; + } + + /** + * Set the parent template. + * + * @param ?self $parent + * @return void + */ + public function setParent(self $parent): void + { + $this->parent = $parent; + } + /** * Get vars. * @@ -395,7 +429,7 @@ class Template $__Context = $this->vars ?: \Context::getAll(); // Start the output buffer. - $this->ob_level = ob_get_level(); + $this->_ob_level = ob_get_level(); ob_start(); // Include the compiled template. @@ -403,7 +437,7 @@ class Template // Fetch the content of the output buffer until the buffer level is the same as before. $content = ''; - while (ob_get_level() > $this->ob_level) + while (ob_get_level() > $this->_ob_level) { $content .= ob_get_clean(); } @@ -571,6 +605,7 @@ class Template } // Set variables. + $template->setParent($this); if ($this->vars) { $template->setVars($this->vars); diff --git a/common/framework/parsers/template/TemplateParser_v2.php b/common/framework/parsers/template/TemplateParser_v2.php index e2d87b6ea..890fac53a 100644 --- a/common/framework/parsers/template/TemplateParser_v2.php +++ b/common/framework/parsers/template/TemplateParser_v2.php @@ -407,7 +407,7 @@ class TemplateParser_v2 // Generate the code to create a new Template object and compile it. $tpl = 'template->extension ?: 'auto') . '"); '; - $tpl .= 'if ($this->vars): $__tpl->setVars($this->vars); endif; '; + $tpl .= '$__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; '; $tpl .= !empty($attrs['vars']) ? '$__tpl->addVars(' . self::_convertVariableScope($attrs['vars']) . '); ' : ''; $tpl .= 'echo $__tpl->compile(); ?>'; diff --git a/tests/unit/framework/parsers/TemplateParserV2Test.php b/tests/unit/framework/parsers/TemplateParserV2Test.php index 987465352..80a58389b 100644 --- a/tests/unit/framework/parsers/TemplateParserV2Test.php +++ b/tests/unit/framework/parsers/TemplateParserV2Test.php @@ -50,42 +50,42 @@ class TemplateParserV2Test extends \Codeception\Test\Unit { // Basic usage $source = ''; - $target = 'relative_dirname, "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; + $target = 'relative_dirname, "foobar", "html"); $__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // Legacy 'target' attribute $source = ''; - $target = 'normalizePath($this->relative_dirname . "subdir"), "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; + $target = 'normalizePath($this->relative_dirname . "subdir"), "foobar", "html"); $__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // Conditional include $source = ''; - $target = 'normalizePath($this->relative_dirname . "../up"), "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; + $target = 'normalizePath($this->relative_dirname . "../up"), "foobar", "html"); $__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // Conditional include with legacy 'cond' attribute $source = ''; - $target = 'normalizePath($this->relative_dirname . "legacy"), "cond.statement.html", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; + $target = 'normalizePath($this->relative_dirname . "legacy"), "cond.statement.html", "html"); $__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // Path relative to Rhymix installation directory $source = ''; - $target = 'vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; + $target = 'setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // Unless $source = ''; - $target = 'vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; + $target = 'setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // With variables $source = ''; - $target = 'relative_dirname, "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; $__tpl->addVars($__Context->vars); echo $__tpl->compile(); ?>'; + $target = 'relative_dirname, "foobar", "html"); $__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; $__tpl->addVars($__Context->vars); echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // With array literal passed as variables $source = ''; - $target = 'relative_dirname, "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; $__tpl->addVars([\'foo\' => \'bar\']); echo $__tpl->compile(); ?>'; + $target = 'relative_dirname, "foobar", "html"); $__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif; $__tpl->addVars([\'foo\' => \'bar\']); echo $__tpl->compile(); ?>'; $this->assertEquals($target, $this->_parse($source)); // Blade-style @include @@ -1071,7 +1071,11 @@ class TemplateParserV2Test extends \Codeception\Test\Unit // cond is OK in includes $source = ''; - $target = 'relative_dirname, "foo.html", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>';; + $target = implode(' ', [ + 'relative_dirname, "foo.html", "html");', + '$__tpl->setParent($this); if ($this->vars): $__tpl->setVars($this->vars); endif;', + 'echo $__tpl->compile(); ?>', + ]); $this->assertEquals($target, $this->_parse($source)); // loop