From 98a3460b2a039526139b2550696d0e37af542cae Mon Sep 17 00:00:00 2001 From: Inhere Date: Mon, 8 Nov 2021 13:37:44 +0800 Subject: [PATCH] refactor: refacting the template file load logic --- app/Lib/Template/AbstractTemplate.php | 123 ++++++++++++++++++ app/Lib/Template/Compiler/PregCompiler.php | 19 ++- .../Template/Contract/CompilerInterface.php | 10 +- app/Lib/Template/EasyTemplate.php | 40 +++--- app/Lib/Template/HtmlTemplate.php | 104 +-------------- app/Lib/Template/TextTemplate.php | 20 --- test/testdata/full-demo.tpl.php | 8 +- test/testdata/use_all_token.tpl | 13 +- .../Lib/Template/EasyTemplateTest.php | 57 ++++---- .../Lib/Template/PregCompilerTest.php | 25 +++- 10 files changed, 236 insertions(+), 183 deletions(-) diff --git a/app/Lib/Template/AbstractTemplate.php b/app/Lib/Template/AbstractTemplate.php index f6172ba..d69fe13 100644 --- a/app/Lib/Template/AbstractTemplate.php +++ b/app/Lib/Template/AbstractTemplate.php @@ -3,7 +3,11 @@ namespace Inhere\Kite\Lib\Template; use Inhere\Kite\Lib\Template\Contract\TemplateInterface; +use InvalidArgumentException; +use Toolkit\FsUtil\File; use Toolkit\Stdlib\Obj; +use function is_file; +use function strpos; /** * Class AbstractTemplate @@ -18,6 +22,25 @@ abstract class AbstractTemplate implements TemplateInterface */ protected array $globalVars = []; + /** + * allow template file ext list. should start with '.' + * + * @var string[] + */ + protected array $allowExt = ['.php', '.tpl']; + + /** + * @var string + */ + protected string $tplDir = ''; + + /** + * manual set view files + * + * @var array + */ + protected array $tplFiles = []; + /** * @return static */ @@ -36,6 +59,106 @@ public function __construct(array $config = []) Obj::init($this, $config); } + /** + * @param string $tplName + * + * @return string + */ + protected function findTplFile(string $tplName): string + { + if (is_file($tplName)) { + return $tplName; + } + + if (isset($this->tplFiles[$tplName])) { + return $this->tplFiles[$tplName]; + } + + if (!$this->tplDir) { + throw new InvalidArgumentException("no such template file: $tplName"); + } + + $suffix = ''; + $tplFile = $this->tplDir . '/' . $tplName; + + if (strpos($tplName, '.') > 0) { + $suffix = File::getExtension($tplName); + } + + // is an exists file + if ($suffix) { + if (is_file($tplFile)) { + return $tplFile; + } + } else { + foreach ($this->allowExt as $ext) { + $filename = $tplFile . $ext; + if (is_file($filename)) { + return $filename; + } + } + } + + throw new InvalidArgumentException("no such template file: $tplName"); + } + + /** + * @param string $tplName + * @param string $filePath + */ + public function addTplFile(string $tplName, string $filePath): void + { + $this->tplFiles[$tplName] = $filePath; + } + + /** + * @return array + */ + public function getTplFiles(): array + { + return $this->tplFiles; + } + + /** + * @param array $tplFiles + */ + public function setTplFiles(array $tplFiles): void + { + $this->tplFiles = $tplFiles; + } + + /** + * @return string + */ + public function getTplDir(): string + { + return $this->tplDir; + } + + /** + * @param string $tplDir + */ + public function setTplDir(string $tplDir): void + { + $this->tplDir = $tplDir; + } + + /** + * @return string[] + */ + public function getAllowExt(): array + { + return $this->allowExt; + } + + /** + * @param string[] $allowExt + */ + public function setAllowExt(array $allowExt): void + { + $this->allowExt = $allowExt; + } + /** * @return array */ diff --git a/app/Lib/Template/Compiler/PregCompiler.php b/app/Lib/Template/Compiler/PregCompiler.php index cd7b58d..e7b821f 100644 --- a/app/Lib/Template/Compiler/PregCompiler.php +++ b/app/Lib/Template/Compiler/PregCompiler.php @@ -2,6 +2,7 @@ namespace Inhere\Kite\Lib\Template\Compiler; +use Toolkit\FsUtil\File; use function addslashes; use function array_keys; use function explode; @@ -48,6 +49,18 @@ public function setOpenCloseTag(string $open, string $close): self return $this; } + /** + * @param string $tplFile + * + * @return string + */ + public function compileFile(string $tplFile): string + { + $tplCode = File::readAll($tplFile); + + return $this->compile($tplCode); + } + /** * @param string $tplCode * @@ -117,10 +130,12 @@ public function parseCodeBlock(string $block): string $open = self::PHP_TAG_OPEN . ($isInline ? ' ' : "\n"); $close = ($isInline ? ' ' : "\n") . self::PHP_TAG_CLOSE; + // echo statement if ($trimmed[0] === '=') { $type = Token::T_ECHO; $open = self::PHP_TAG_ECHO; - } elseif (str_starts_with($trimmed, 'echo ')) { // echo statement + } elseif (str_starts_with($trimmed, 'echo ')) { + // echo statement $type = Token::T_ECHO; $open = self::PHP_TAG_OPEN . ' '; } elseif ($isInline && ($tryType = Token::tryAloneToken($trimmed))) { @@ -142,7 +157,7 @@ public function parseCodeBlock(string $block): string $endChar = $trimmed[strlen($trimmed) - 1]; // not in raw php code AND end char != : - if ($endChar !== '}' && $endChar !== '{' && $endChar !== ':') { + if ($endChar !== '}' && $endChar !== '{' && $endChar !== ';' && $endChar !== ':') { $close = ': ' . self::PHP_TAG_CLOSE; } } diff --git a/app/Lib/Template/Contract/CompilerInterface.php b/app/Lib/Template/Contract/CompilerInterface.php index 6689633..ae0cd53 100644 --- a/app/Lib/Template/Contract/CompilerInterface.php +++ b/app/Lib/Template/Contract/CompilerInterface.php @@ -9,7 +9,6 @@ */ interface CompilerInterface { - /** * @param string $open * @param string $close @@ -26,4 +25,13 @@ public function setOpenCloseTag(string $open, string $close): self; * @return string */ public function compile(string $tplCode): string; + + /** + * compile template file contents to raw PHP template codes + * + * @param string $tplFile + * + * @return string + */ + public function compileFile(string $tplFile): string; } diff --git a/app/Lib/Template/EasyTemplate.php b/app/Lib/Template/EasyTemplate.php index e25e001..bce17f2 100644 --- a/app/Lib/Template/EasyTemplate.php +++ b/app/Lib/Template/EasyTemplate.php @@ -5,9 +5,6 @@ use Inhere\Kite\Lib\Template\Compiler\PregCompiler; use Inhere\Kite\Lib\Template\Contract\CompilerInterface; use Inhere\Kite\Lib\Template\Contract\EasyTemplateInterface; -use InvalidArgumentException; -use Toolkit\FsUtil\File; -use function file_exists; /** * Class EasyTemplate @@ -16,11 +13,6 @@ */ class EasyTemplate extends TextTemplate implements EasyTemplateInterface { - /** - * @var string[] - */ - protected array $allowExt = ['.php', '.tpl']; - /** * @var CompilerInterface */ @@ -39,11 +31,24 @@ public function __construct(array $config = []) $this->compiler->addDirective( 'include', function (string $body, string $name) { - return 'echo $this->' . $name . $body; + return '$this->' . $name . $body; } ); } + /** + * @param string $tplFile + * @param array $tplVars + * + * @return string + */ + public function renderFile(string $tplFile, array $tplVars): string + { + $phpFile = $this->compileFile($tplFile); + + return $this->doRenderFile($phpFile, $tplVars); + } + /** * @param string $tplCode * @param array $tplVars @@ -52,7 +57,7 @@ function (string $body, string $name) { */ public function renderString(string $tplCode, array $tplVars): string { - $tplCode = $this->compileCode($tplCode); + $tplCode = $this->compiler->compile($tplCode); return parent::renderString($tplCode, $tplVars); } @@ -60,14 +65,12 @@ public function renderString(string $tplCode, array $tplVars): string /** * @param string $tplFile * @param array $tplVars - * - * @return string */ - public function renderFile(string $tplFile, array $tplVars): string + protected function include(string $tplFile, array $tplVars): void { $phpFile = $this->compileFile($tplFile); - return $this->doRenderFile($phpFile, $tplVars); + echo $this->doRenderFile($phpFile, $tplVars); } /** @@ -76,7 +79,7 @@ public function renderFile(string $tplFile, array $tplVars): string * * @return string */ - protected function include(string $tplFile, array $tplVars): string + protected function renderInclude(string $tplFile, array $tplVars): string { $phpFile = $this->compileFile($tplFile); @@ -90,13 +93,10 @@ protected function include(string $tplFile, array $tplVars): string */ public function compileFile(string $tplFile): string { - if (!file_exists($tplFile)) { - throw new InvalidArgumentException('no such template file:' . $tplFile); - } + $tplFile = $this->findTplFile($tplFile); - $tplCode = File::readAll($tplFile); // compile contents - $tplCode = $this->compileCode($tplCode); + $tplCode = $this->compiler->compileFile($tplFile); // generate temp php file return $this->genTempPhpFile($tplCode); diff --git a/app/Lib/Template/HtmlTemplate.php b/app/Lib/Template/HtmlTemplate.php index 8b930da..0e28eb5 100644 --- a/app/Lib/Template/HtmlTemplate.php +++ b/app/Lib/Template/HtmlTemplate.php @@ -2,11 +2,6 @@ namespace Inhere\Kite\Lib\Template; -use InvalidArgumentException; -use Toolkit\FsUtil\File; -use function is_file; -use function strpos; - /** * Class HtmlTemplate * @@ -19,118 +14,27 @@ class HtmlTemplate extends TextTemplate */ protected array $allowExt = ['.html', '.phtml', '.php']; - /** - * @var string - */ - protected string $viewsDir = ''; - - /** - * manual set view files - * - * @var array - */ - protected array $viewsFiles = []; - /** * @param string $viewPath - * @param array $vars + * @param array $vars * * @return string */ public function render(string $viewPath, array $vars = []): string { - $viewFile = $this->findViewFile($viewPath); + $viewFile = $this->findTplFile($viewPath); return $this->renderFile($viewFile, $vars); } /** * @param string $viewPath - * @param array $vars + * @param array $vars */ public function renderOutput(string $viewPath, array $vars = []): void { - $viewFile = $this->findViewFile($viewPath); + $viewFile = $this->findTplFile($viewPath); echo $this->renderFile($viewFile, $vars); } - - /** - * @param string $viewName - * - * @return string - */ - protected function findViewFile(string $viewName): string - { - if (isset($this->viewsFiles[$viewName])) { - return $this->viewsFiles[$viewName]; - } - - $suffix = ''; - if (strpos($viewName, '.') > 0) { - $suffix = File::getExtension($viewName); - } - - $viewFile = $this->viewsDir . '/' . $viewName; - - // is an exists file - if ($suffix) { - if (is_file($viewFile)) { - return $viewFile; - } - - throw new InvalidArgumentException("no such view file: $viewName"); - } - - foreach ($this->allowExt as $ext) { - $filename = $viewFile . $ext; - if (is_file($filename)) { - return $filename; - } - } - - throw new InvalidArgumentException("no such view file: $viewName"); - } - - /** - * @param string $viewName - * @param string $filePath - */ - public function addViewFile(string $viewName, string $filePath): void - { - $this->viewsFiles[$viewName] = $filePath; - } - - /** - * @return array - */ - public function getViewsFiles(): array - { - return $this->viewsFiles; - } - - /** - * @param array $viewsFiles - */ - public function setViewsFiles(array $viewsFiles): void - { - $this->viewsFiles = $viewsFiles; - } - - /** - * @return string - */ - public function getViewsDir(): string - { - return $this->viewsDir; - } - - /** - * @param string $viewsDir - */ - public function setViewsDir(string $viewsDir): void - { - $this->viewsDir = $viewsDir; - } - } diff --git a/app/Lib/Template/TextTemplate.php b/app/Lib/Template/TextTemplate.php index 6f4dff1..b239bc2 100644 --- a/app/Lib/Template/TextTemplate.php +++ b/app/Lib/Template/TextTemplate.php @@ -28,10 +28,6 @@ */ class TextTemplate extends AbstractTemplate { - /** - * @var string[] - */ - protected array $allowExt = ['.php']; /** * The dir for auto generated temp php file @@ -125,22 +121,6 @@ protected function genTempPhpFile(string $tplCode): string return $tmpFile; } - /** - * @return string[] - */ - public function getAllowExt(): array - { - return $this->allowExt; - } - - /** - * @param string[] $allowExt - */ - public function setAllowExt(array $allowExt): void - { - $this->allowExt = $allowExt; - } - /** * @return string */ diff --git a/test/testdata/full-demo.tpl.php b/test/testdata/full-demo.tpl.php index 8ecf64a..c00e4ed 100644 --- a/test/testdata/full-demo.tpl.php +++ b/test/testdata/full-demo.tpl.php @@ -2,19 +2,19 @@ /** * comments * - * @var array $arr + * @var array $map * @var object $obj */ ?> echo vars: - - + + foreach example: - $val) : ?> + $val) : ?> KEY: => VALUE: $val) : }} +{{ foreach ($map as $key => $val) : }} + in foreach KEY:{{= $key}} => VALUE:{{ $typ = gettype($val); echo ucfirst($typ === 'array' ? 'arrayValue' : $typ) -}} - in foreach +}} {{ $val }}; {{ endforeach }} {{ diff --git a/test/unittest/Lib/Template/EasyTemplateTest.php b/test/unittest/Lib/Template/EasyTemplateTest.php index f1598b6..28ce6a1 100644 --- a/test/unittest/Lib/Template/EasyTemplateTest.php +++ b/test/unittest/Lib/Template/EasyTemplateTest.php @@ -3,13 +3,10 @@ namespace Inhere\KiteTest\Lib\Template; use Inhere\Kite\Kite; -use Inhere\Kite\Lib\Template\Compiler\Token; use Inhere\Kite\Lib\Template\EasyTemplate; use Inhere\KiteTest\BaseKiteTestCase; use PhpToken; use Toolkit\FsUtil\File; -use function preg_match; -use function random_int; use function vdump; /** @@ -17,7 +14,20 @@ */ class EasyTemplateTest extends BaseKiteTestCase { - public function testV2Render_use_echo_foreach():void + private $tplVars = [ + 'int' => 23, + 'str' => 'a string', + 'arr' => [ + 'inhere', + 20, + ], + 'map' => [ + 'name' => 'inhere', + 'age' => 20, + ], + ]; + + public function testV2RenderFile_use_echo_foreach(): void { $t = new EasyTemplate(); @@ -30,7 +40,7 @@ public function testV2Render_use_echo_foreach():void vdump($result); } - public function testCompileFile_use_echo_foreach():void + public function testCompileFile_use_echo_foreach(): void { $t = new EasyTemplate(); @@ -48,7 +58,7 @@ public function testCompileFile_use_echo_foreach():void // vdump($genCode); } - public function testCompileFile_use_all_token():void + public function testCompileFile_use_all_token(): void { $t = new EasyTemplate(); @@ -66,7 +76,19 @@ public function testCompileFile_use_all_token():void $this->assertStringNotContainsString('}}', $genCode); } - public function testCompileCode_check():void + public function testV2RenderFile_use_all_token(): void + { + $t = new EasyTemplate(); + + $tplFile = Kite::resolve('@testdata/use_all_token.tpl'); + $result = $t->renderFile($tplFile, $this->tplVars); + + $this->assertNotEmpty($result); + + vdump($result); + } + + public function testCompileCode_check(): void { $t2 = new EasyTemplate(); @@ -77,20 +99,7 @@ public function testCompileCode_check():void $this->assertEquals('no tpl tags', $compiled); } - private $tplVars = [ - 'int' => 23, - 'str' => 'a string', - 'arr' => [ - 'hello', - 'world', - ], - 'map' => [ - 'key0' => 'map-val0', - 'key1' => 'map-val1', - ], - ]; - - public function testV2Render_vars():void + public function testV2Render_vars(): void { // inline $code = ' @@ -104,14 +113,14 @@ public function testV2Render_vars():void vdump($tokens2); $tplVars = ['vars' => ['Info', 'Error', 'Warn']]; - $t = new EasyTemplate(); + $t = new EasyTemplate(); $result = $t->renderString($code, $tplVars); vdump($result); } - public function testV2Render_ifElse():void + public function testV2Render_ifElse(): void { $t = new EasyTemplate(); @@ -124,7 +133,7 @@ public function testV2Render_ifElse():void vdump($result); } - public function testV2Render_foreach():void + public function testV2Render_foreach(): void { $t = new EasyTemplate(); diff --git a/test/unittest/Lib/Template/PregCompilerTest.php b/test/unittest/Lib/Template/PregCompilerTest.php index cd9eed6..fdfcbba 100644 --- a/test/unittest/Lib/Template/PregCompilerTest.php +++ b/test/unittest/Lib/Template/PregCompilerTest.php @@ -113,15 +113,15 @@ public function testCompile_customDirective():void { $p = new PregCompiler(); $p->addDirective('include', function (string $body, string $name) { - return 'echo $this->' . $name . $body; + return '$this->' . $name . $body; }); $tests = [ - ['{{ include("header.tpl") }}', 'include("header.tpl") ?>'], + ['{{ include("header.tpl") }}', 'include("header.tpl") ?>'], ['{{ include("header.tpl", [ "key1" => "value1", ]) }}', 'include("header.tpl", [ +$this->include("header.tpl", [ "key1" => "value1", ]) ?>'], @@ -129,7 +129,6 @@ public function testCompile_customDirective():void foreach ($tests as [$in, $out]) { $this->assertEquals($out, $p->compile($in)); } - } public function testCompile_if_block():void @@ -163,7 +162,7 @@ public function testCompile_if_block():void } } - public function testCompileCode_ml_block():void + public function testCompileCode_ml_define():void { $p = new PregCompiler(); @@ -175,7 +174,21 @@ public function testCompileCode_ml_block():void CODE; $compiled = $p->compile($code); $this->assertEquals(<<<'CODE' - +CODE + ,$compiled); + + $code = <<<'CODE' +{{ +// comments +$a = random_int(1, 10); +}} +CODE; + $compiled = $p->compile($code); + $this->assertEquals(<<<'CODE' + CODE ,$compiled);