From c19d71847fa59340d61fe68a7a2e4d3dffc4d9a6 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Wed, 18 Oct 2023 02:23:18 +0900 Subject: [PATCH] Implement template v2 feature of pushing to stack --- common/framework/Template.php | 19 ++++++++++ .../parsers/template/TemplateParser_v2.php | 37 +++++++++++++++---- .../_data/template/v2pushstack.executed.html | 7 ++++ tests/_data/template/v2pushstack.html | 27 ++++++++++++++ .../parsers/TemplateParserV2Test.php | 13 +++++++ 5 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 tests/_data/template/v2pushstack.executed.html create mode 100644 tests/_data/template/v2pushstack.html diff --git a/common/framework/Template.php b/common/framework/Template.php index ba92a4957..bf9582449 100644 --- a/common/framework/Template.php +++ b/common/framework/Template.php @@ -30,6 +30,7 @@ class Template public $vars; protected $_fragments = []; protected static $_loopvars = []; + protected static $_stacks = []; /** * Static properties @@ -411,6 +412,24 @@ class Template } } + /** + * Get the contents of a stack. + * + * @param string $name + * @return ?array + */ + public function getStack(string $name): ?array + { + if (isset(self::$_stacks[$name])) + { + return self::$_stacks[$name]; + } + else + { + return null; + } + } + /** * Check if a path should be treated as relative to the path of the current template. * diff --git a/common/framework/parsers/template/TemplateParser_v2.php b/common/framework/parsers/template/TemplateParser_v2.php index 48a4c5fcb..70a360581 100644 --- a/common/framework/parsers/template/TemplateParser_v2.php +++ b/common/framework/parsers/template/TemplateParser_v2.php @@ -60,12 +60,28 @@ class TemplateParser_v2 ], 'fragment' => [ 'ob_start(); $__last_fragment_name = %s;', - "\$this->_fragments[\$__last_fragment_name] = ob_get_flush();", + '$this->_fragments[$__last_fragment_name] = ob_get_flush();', ], 'error' => [ 'if ($this->_v2_errorExists(%s)):', 'endif;', ], + 'push' => [ + 'ob_start(); if (!isset(self::$_stacks[%s])): self::$_stacks[%s] = []; endif;', + 'array_push(self::$_stacks[%s], trim(ob_get_clean()));', + ], + 'pushif' => [ + 'list($__stack_cond, $__stack_name) = [%s]; if ($__stack_cond): ob_start(); if (!isset(self::$_stacks[$__stack_name])): self::$_stacks[$__stack_name] = []; endif;', + 'array_push(self::$_stacks[$__stack_name], trim(ob_get_clean())); endif;', + ], + 'prepend' => [ + 'ob_start(); if (!isset(self::$_stacks[%s])): self::$_stacks[%s] = []; endif;', + 'array_unshift(self::$_stacks[%s], trim(ob_get_clean()));', + ], + 'prependif' => [ + 'list($__stack_cond, $__stack_name) = [%s]; if ($__stack_cond): ob_start(); if (!isset(self::$_stacks[$__stack_name])): self::$_stacks[$__stack_name] = []; endif;', + 'array_unshift(self::$_stacks[$__stack_name], trim(ob_get_clean())); endif;', + ], 'isset' => ['if (isset(%s)):', 'endif;'], 'unset' => ['if (!isset(%s)):', 'endif;'], 'empty' => ['if (empty(%s)):', 'endif;'], @@ -474,10 +490,11 @@ class TemplateParser_v2 // Generate the list of directives to match. foreach (self::$_loopdef as $directive => $def) { + $directive = preg_replace('#(.+)if$#', '$1[iI]f', $directive); $directives[] = $directive; if (count($def) > 1) { - $directives[] = 'end' . $directive; + $directives[] = 'end[' . substr($directive, 0, 1) . strtoupper(substr($directive, 0, 1)) . ']' . substr($directive, 1); } } usort($directives, function($a, $b) { return strlen($b) - strlen($a); }); @@ -489,7 +506,7 @@ class TemplateParser_v2 $content = preg_replace_callback($regexp, function($match) { // Collect the necessary information. - $directive = $match[1]; + $directive = strtolower($match[1]); $args = isset($match[2]) ? self::_convertVariableScope(substr($match[2], 1, strlen($match[2]) - 2)) : ''; $stack = null; $code = null; @@ -539,10 +556,10 @@ class TemplateParser_v2 } } $code = self::$_loopdef[$directive][0]; - $code = strtr($code, ['%uniq' => $uniq, '%array' => $array, '%remainder' => $remainder]); - $code = str_contains($code, '%s') ? sprintf($code, $args) : $code; + $code = strtr($code, ['%s' => $args, '%uniq' => $uniq, '%array' => $array, '%remainder' => $remainder]); $this->_stack[] = [ 'directive' => $directive, + 'args' => $args, 'uniq' => $uniq, 'array' => $array, 'remainder' => $remainder, @@ -553,8 +570,7 @@ class TemplateParser_v2 else { $code = end(self::$_loopdef[$directive]); - $code = strtr($code, ['%uniq' => $stack['uniq'], '%array' => $stack['array'], '%remainder' => $stack['remainder']]); - $code = str_contains($code, '%s') ? sprintf($code, $args) : $code; + $code = strtr($code, ['%s' => $stack['args'], '%uniq' => $stack['uniq'], '%array' => $stack['array'], '%remainder' => $stack['remainder']]); } } else @@ -621,6 +637,7 @@ class TemplateParser_v2 * @csrf * @json($var) * @lang('foo.bar') + * @stack('name') * * @param string $content * @return string @@ -634,7 +651,7 @@ class TemplateParser_v2 // Insert JSON, lang codes, and dumps. $parentheses = self::_getRegexpForParentheses(2); - $content = preg_replace_callback('#(?', $args); } + elseif ($match[1] === 'stack') + { + return sprintf('', $args); + } else { return $match[0]; diff --git a/tests/_data/template/v2pushstack.executed.html b/tests/_data/template/v2pushstack.executed.html new file mode 100644 index 000000000..a5fa010f4 --- /dev/null +++ b/tests/_data/template/v2pushstack.executed.html @@ -0,0 +1,7 @@ + + diff --git a/tests/_data/template/v2pushstack.html b/tests/_data/template/v2pushstack.html new file mode 100644 index 000000000..0557f078c --- /dev/null +++ b/tests/_data/template/v2pushstack.html @@ -0,0 +1,27 @@ +@version(2) + + + +@push('cms') +
  • XE
  • +@endpush + +@push('cms') +
  • WordPress
  • +@end + +@pushIf($foo, 'cms') +
  • Drupal
  • +@endPushIf + +@prepend('cms') +
  • Rhymix
  • +@endprepend + +@prependIf(!$foo, 'cms') +
  • Joomla
  • +@end + + diff --git a/tests/unit/framework/parsers/TemplateParserV2Test.php b/tests/unit/framework/parsers/TemplateParserV2Test.php index 223229e87..f5b517633 100644 --- a/tests/unit/framework/parsers/TemplateParserV2Test.php +++ b/tests/unit/framework/parsers/TemplateParserV2Test.php @@ -1038,6 +1038,19 @@ class TemplateParserV2Test extends \Codeception\Test\Unit $this->_normalizeWhitespace($executed_output) ); + // Push stack + $tmpl = new \Rhymix\Framework\Template('./tests/_data/template', 'v2pushstack.html'); + $tmpl->disableCache(); + + $executed_output = $tmpl->compile(); + //Rhymix\Framework\Storage::write(\RX_BASEDIR . 'tests/_data/template/v2pushstack.executed.html', $executed_output); + $expected = file_get_contents(\RX_BASEDIR . 'tests/_data/template/v2pushstack.executed.html'); + $this->assertEquals( + $this->_normalizeWhitespace($expected), + $this->_normalizeWhitespace($executed_output) + ); + $this->assertEquals(4, count($tmpl->getStack('cms'))); + // Validation error check $tmpl = new \Rhymix\Framework\Template('./tests/_data/template', 'v2validation.html'); $tmpl->disableCache();