From 3b9e848cb12607f323773f8eba820fd184174f4b Mon Sep 17 00:00:00 2001 From: matthes Date: Wed, 25 Jul 2018 13:56:40 +0200 Subject: [PATCH] added custom sections --- composer.lock | 5 +++-- docs/README.md | 10 +++++----- src/TextTemplate.php | 38 +++++++++++++++++++------------------- test/sections.phpt | 6 +++++- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/composer.lock b/composer.lock index 22abd72..403f8a0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "e4c9f8628231e32c7910d2fff2021323", + "content-hash": "d0f104779b4849573513ffc4cbef6465", "packages": [], "packages-dev": [ { @@ -2237,7 +2237,8 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.4" + "php": ">=5.4", + "ext-pcre": "*" }, "platform-dev": [] } diff --git a/docs/README.md b/docs/README.md index 2f3091a..6683859 100644 --- a/docs/README.md +++ b/docs/README.md @@ -260,15 +260,15 @@ This example will replace the htmlspecialchars() escaper by the strip_tags() fun Sections are like functions but provide the content they enclose: ``` -{section name="someName"} +{sectionxy name="someName"} Some Content -{/section} +{/sectionxy} ``` ``` -{section name="someName" > out} +{sectionxy name="someName" > out} Some Content -{/section} +{/sectionxy} {= out} ``` @@ -276,7 +276,7 @@ Some Content To use sections you must just set the callback: ```php -$textTemplate->setSectionCallback(function ($params, $content, $context, $cmdParam) { +$textTemplate->setSectionCallback("sectionxy", function ($content, $params, $command, $context, $cmdParam) { return "Content to replace section content with"; }); ``` diff --git a/src/TextTemplate.php b/src/TextTemplate.php index 1f44269..f226b77 100644 --- a/src/TextTemplate.php +++ b/src/TextTemplate.php @@ -53,9 +53,9 @@ class TextTemplate { private $mFunctions = []; /** - * @var null|callable + * @var callable[] */ - private $sectionCallback = null; + private $sections = []; public function __construct ($text="") { @@ -71,10 +71,9 @@ public function __construct ($text="") { * * @param $enableSectionMode */ - public function setSectionCallback($sectionCallback) + public function addSection($name, $sectionCallback) { - - $this->sectionCallback = $sectionCallback; + $this->sections[$name] = $sectionCallback; } @@ -193,11 +192,14 @@ public function _replaceNestingLevels ($input) { $indexCounter = 0; $nestingIndex = []; + $blockTags = array_keys($this->sections); + $blockTags[] = "if"; + $blockTags[] = "for"; + $lines = explode("\n", $input); for ($li=0; $li < count ($lines); $li++) { $lines[$li] = preg_replace_callback('/\{(?!=)\s*(\/?)\s*([a-z]+)(.*?)\}/im', - function ($matches) use (&$nestingIndex, &$indexCounter, &$li) { - $blockTags = ["if", "for", "section"]; + function ($matches) use (&$nestingIndex, &$indexCounter, &$li, $blockTags) { $slash = $matches[1]; $tag = $matches[2]; $rest = $matches[3]; @@ -470,19 +472,21 @@ private function _runIf (&$context, $content, $cmdParam, $softFail, &$ifConditio - private function _runSection(&$context, $content, $cmdParam, $softFail) + private function _runSection($command, &$context, $content, $cmdParam, $softFail) { - if ($this->sectionCallback === null) { - return $this->_parseBlock($context, $content, $softFail); + if ( ! isset($this->sections[$command])) { + if ($softFail === true) + return "!!ERR:Undefined section '$command'!!"; + throw new TemplateParsingException("Undefined section {$command}...{/$command} in block '$cmdParam'"); } $funcParams = $this->_parseFunctionParameters($cmdParam, $context, $softFail); $content = $this->_parseBlock($context, $content, $softFail); try { - $func = $this->sectionCallback; + $func = $this->sections[$command]; $out = $func( - $funcParams["paramArr"], $content, $context, $cmdParam + $content, $funcParams["paramArr"], $command, $context, $cmdParam ); if ($funcParams["retAs"] !== null) { $context[$funcParams["retAs"]] = $out; @@ -526,8 +530,8 @@ private function _parseFunctionParameters ($cmdParam, &$context, $softFail) private function _parseBlock (&$context, $block, $softFail) { // (?!\{): Lookahead Regex: Don't touch double {{ - - $result = preg_replace_callback('/(\{(?!=)((?if|for|section)(?[0-9]+))(?.*?)\}(?.*?)\n?\{\/\2\}|\{(?!=)(?[a-z]+)\s*(?.*?)\}|\{\=(?.+?)\})/ism', + $bCommands = implode("|", array_keys($this->sections)); + $result = preg_replace_callback('/(\{(?!=)((?if|for|' . $bCommands . ')(?[0-9]+))(?.*?)\}(?.*?)\n?\{\/\2\}|\{(?!=)(?[a-z]+)\s*(?.*?)\}|\{\=(?.+?)\})/ism', function ($matches) use (&$context, $softFail) { if (isset ($matches["value"]) && $matches["value"] != null) { return $this->_parseValueOfTags($context, $matches["value"], $softFail); @@ -557,13 +561,9 @@ function ($matches) use (&$context, $softFail) { $this->ifConditionMatch[$nestingLevel] ); - case "section": - return $this->_runSection($context, $content, $cmdParam, $softFail); default: - if ( ! $softFail) - throw new TemplateParsingException("Invalid block-command '$command' in block '{$matches[0]}'"); - return "!! Invalid block-command: '$command' !!"; + return $this->_runSection($command, $context, $content, $cmdParam, $softFail); } } else { // Regular Commands diff --git a/test/sections.phpt b/test/sections.phpt index 95c4995..c338331 100644 --- a/test/sections.phpt +++ b/test/sections.phpt @@ -8,6 +8,8 @@ namespace Test; require __DIR__ . "/../vendor/autoload.php"; + +use http\Exception\InvalidArgumentException; use Leuffen\TextTemplate\TextTemplate; use Tester\Assert; use Tester\Environment; @@ -38,8 +40,10 @@ EOT; $template = new TextTemplate($tpl); $sec = []; -$template->setSectionCallback(function ($params, $content, $context, $cmdParam) use (&$sec) { +$template->addSection("section", function ($content, $params, $command, $context, $cmdParam) use (&$sec) { $sec[$params["name"]] = $content; + if ($command !== "section") + throw new InvalidArgumentException("Command missing"); return "*" . trim ($content) . "*"; }); $textResult = $template->apply([]);