diff --git a/src/SurfStack/Templating/Template_Engine.php b/src/SurfStack/Templating/Template_Engine.php index 24e6ef9..2736e47 100644 --- a/src/SurfStack/Templating/Template_Engine.php +++ b/src/SurfStack/Templating/Template_Engine.php @@ -74,6 +74,8 @@ function setTemplate($template) // Store the template full path $this->template = stream_resolve_include_path($template); + + $this->setInternal('Template', $this->template); } /** @@ -539,6 +541,9 @@ protected function stripTags($content) // Strip multi-line comments //$stripTags[] = '/'.$stripSpace.'\{\*(.[^\}\{]*?)\*\}'.$stripSpace.'/s'; + // Strip section tags and all space around + $stripTags[] = '/\s*\{\s*(section)\s*(.*?)\}(.*?)\{\/\s*section\s*\}\s*/si'; + return preg_replace($stripTags, '', $content); } @@ -645,7 +650,7 @@ protected function loadPlugins() switch ($parent) { case 'Block': - $return[$name] = '/\{\s*('.$name.')\s*(.*?)\}(.*?)\{\/\s*'.$name.'\s*\}/i'; + $return[$name] = '/\{\s*('.$name.')\s*(.*?)\}(.*?)\{\/\s*'.$name.'\s*\}/si'; break; case 'Slice': $return[$name] = '/\{\s*('.$name.')\s*(.*?)\}/i'; diff --git a/src/SurfStack/Templating/plugin/Extend.php b/src/SurfStack/Templating/plugin/Extend.php new file mode 100644 index 0000000..a9633f0 --- /dev/null +++ b/src/SurfStack/Templating/plugin/Extend.php @@ -0,0 +1,228 @@ +arrPluginVariables['file'])) + { + $template = $this->arrPluginVariables['file']; + + if (!is_file(stream_resolve_include_path($template))) + { + throw new \ErrorException('The template, '.$template.', cannot be found.'); + } + + $this->parents[] = $this->arrEngineInternals['Template']; + + do + { + $parentName = array_shift($this->parents); + $currentTemplate = stream_resolve_include_path($parentName); + //$currentTemplate2 = $this->arrEngineInternals['TemplateDir'].'/'.$parentName; + + if (is_file($currentTemplate)) + { + $this->parseTemplate(file_get_contents($currentTemplate)); + + $this->finalTemplate = $currentTemplate; + } + /*else if (is_file($currentTemplate2)) + { + $this->parseTemplate(file_get_contents($currentTemplate2)); + + $this->finalTemplate = $currentTemplate2; + }*/ + else + { + throw new \ErrorException("Template parent, $parentName, cannot be found."); + } + } + while ($this->parents); + + return $this->overlayTemplate(); + } + else + { + throw new \InvalidArgumentException('You must specify the "file" argument when using the Extend plugin.'); + } + } + + /** + * Parse a string of name='value' and convert to an array + * @param string $strData + * @return array + */ + protected function parsePluginVariables($strData) + { + $arr = array(); + + // Extract the variables + if(preg_match_all('/(\w+=\'[^\']*\'|\w+=\"[^"]*"|\w+=[^\s]*)+/', $strData, $m)) + { + foreach($m[0] as $key => $k) + { + $arrSplit = explode('=', $k); + + $arr[$arrSplit[0]] = trim(join('', array_slice($arrSplit, 1)), '\'\"'); + } + } + + return $arr; + } + + /** + * Extract section and extend tags + * @param string $content + * @return string + */ + protected function parseTemplate($content) + { + // Extract the sections + if(preg_match_all($this->sectionRegex, $content, $m)) + { + for($i = 0, $total = count($m[0]); $i < $total; $i++) + { + $arrData = array(); + + $vars = $this->parsePluginVariables($m[1][$i]); + + if (isset($vars['name'])) + { + $this->storeSection($vars['name'], array( + 'content' => trim($m[2][$i]), + 'data' => $vars, + )); + } + } + } + + // Extract the extend + if(preg_match($this->extendRegex, $content, $m)) + { + $vars = $this->parsePluginVariables($m[1]); + + if (isset($vars['file'])) + { + $this->parents[] = $vars['file']; + } + } + } + + /** + * Store only the first section + * @param string $key + * @param array $value + */ + protected function storeSection($key, array $value) + { + if (!isset($this->sections[$key])) + { + $this->sections[$key] = $value; + } + else + { + $this->skipped += 1; + } + } + + /** + * Returns the replacement for the section in the final template + * @param array $matches + * @return string + */ + protected function dynamicSectionReplacement($matches) + { + $vars = $this->parsePluginVariables($matches[1]); + + if (isset($vars['name'])) + { + $name = $vars['name']; + + if (isset($this->sections[$name])) + { + $content = $this->sections[$name]['content']; + + if (strpos($content, '{parent}') !== -1) + { + return str_replace('{parent}', trim($matches[2]), $content); + } + else + { + return $content; + } + } + else + { + return trim($matches[2]); + } + } + } + + /** + * Returns the final template output + * @return string + */ + protected function overlayTemplate() + { + return preg_replace_callback($this->sectionRegex, array($this, 'dynamicSectionReplacement') , file_get_contents($this->finalTemplate)); + } +} \ No newline at end of file diff --git a/src/SurfStack/Templating/plugin/placeholder b/src/SurfStack/Templating/plugin/placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/SurfStack/Templating/Template_Engine_Test.php b/tests/SurfStack/Templating/Template_Engine_Test.php index d2c64f5..7ebc40a 100644 --- a/tests/SurfStack/Templating/Template_Engine_Test.php +++ b/tests/SurfStack/Templating/Template_Engine_Test.php @@ -307,6 +307,7 @@ public function testLoadPluginsArray() $this->assertSame($this->view->getLoadedPlugins(), array( 'Blank', 'Bold', + 'Extend', 'Passthru', 'Time', )); @@ -318,7 +319,7 @@ public function testLoadPluginsCount() $this->render(); - $this->assertSame($this->view->getNumberLoadedPlugins(), 4); + $this->assertSame($this->view->getNumberLoadedPlugins(), 5); } public function testVariableBlock() @@ -386,6 +387,19 @@ public function testVariableSliceGood() $this->assertTrue($this->view->isTemplateValid()); } + public function testExtend() + { + $this->view->setTemplate('child.tpl'); + + $this->view->setLoadPlugins(true); + + $this->render(); + + $content = str_replace("\r\n","\n", $this->output); + + $this->assertSame($content, "

Hello world!

\n\n
\nTest from grandparent\nTest from parent\n
\n\n
\nSafe from child\nSafe from grandparent\n
"); + } + public function testNoCacheTemplates() { $this->view->setCacheTemplates(false); diff --git a/tests/SurfStack/Templating/plugin/Extend.php b/tests/SurfStack/Templating/plugin/Extend.php new file mode 100644 index 0000000..a9633f0 --- /dev/null +++ b/tests/SurfStack/Templating/plugin/Extend.php @@ -0,0 +1,228 @@ +arrPluginVariables['file'])) + { + $template = $this->arrPluginVariables['file']; + + if (!is_file(stream_resolve_include_path($template))) + { + throw new \ErrorException('The template, '.$template.', cannot be found.'); + } + + $this->parents[] = $this->arrEngineInternals['Template']; + + do + { + $parentName = array_shift($this->parents); + $currentTemplate = stream_resolve_include_path($parentName); + //$currentTemplate2 = $this->arrEngineInternals['TemplateDir'].'/'.$parentName; + + if (is_file($currentTemplate)) + { + $this->parseTemplate(file_get_contents($currentTemplate)); + + $this->finalTemplate = $currentTemplate; + } + /*else if (is_file($currentTemplate2)) + { + $this->parseTemplate(file_get_contents($currentTemplate2)); + + $this->finalTemplate = $currentTemplate2; + }*/ + else + { + throw new \ErrorException("Template parent, $parentName, cannot be found."); + } + } + while ($this->parents); + + return $this->overlayTemplate(); + } + else + { + throw new \InvalidArgumentException('You must specify the "file" argument when using the Extend plugin.'); + } + } + + /** + * Parse a string of name='value' and convert to an array + * @param string $strData + * @return array + */ + protected function parsePluginVariables($strData) + { + $arr = array(); + + // Extract the variables + if(preg_match_all('/(\w+=\'[^\']*\'|\w+=\"[^"]*"|\w+=[^\s]*)+/', $strData, $m)) + { + foreach($m[0] as $key => $k) + { + $arrSplit = explode('=', $k); + + $arr[$arrSplit[0]] = trim(join('', array_slice($arrSplit, 1)), '\'\"'); + } + } + + return $arr; + } + + /** + * Extract section and extend tags + * @param string $content + * @return string + */ + protected function parseTemplate($content) + { + // Extract the sections + if(preg_match_all($this->sectionRegex, $content, $m)) + { + for($i = 0, $total = count($m[0]); $i < $total; $i++) + { + $arrData = array(); + + $vars = $this->parsePluginVariables($m[1][$i]); + + if (isset($vars['name'])) + { + $this->storeSection($vars['name'], array( + 'content' => trim($m[2][$i]), + 'data' => $vars, + )); + } + } + } + + // Extract the extend + if(preg_match($this->extendRegex, $content, $m)) + { + $vars = $this->parsePluginVariables($m[1]); + + if (isset($vars['file'])) + { + $this->parents[] = $vars['file']; + } + } + } + + /** + * Store only the first section + * @param string $key + * @param array $value + */ + protected function storeSection($key, array $value) + { + if (!isset($this->sections[$key])) + { + $this->sections[$key] = $value; + } + else + { + $this->skipped += 1; + } + } + + /** + * Returns the replacement for the section in the final template + * @param array $matches + * @return string + */ + protected function dynamicSectionReplacement($matches) + { + $vars = $this->parsePluginVariables($matches[1]); + + if (isset($vars['name'])) + { + $name = $vars['name']; + + if (isset($this->sections[$name])) + { + $content = $this->sections[$name]['content']; + + if (strpos($content, '{parent}') !== -1) + { + return str_replace('{parent}', trim($matches[2]), $content); + } + else + { + return $content; + } + } + else + { + return trim($matches[2]); + } + } + } + + /** + * Returns the final template output + * @return string + */ + protected function overlayTemplate() + { + return preg_replace_callback($this->sectionRegex, array($this, 'dynamicSectionReplacement') , file_get_contents($this->finalTemplate)); + } +} \ No newline at end of file diff --git a/tests/SurfStack/Templating/template/child.tpl b/tests/SurfStack/Templating/template/child.tpl index 079b80b..1536066 100644 --- a/tests/SurfStack/Templating/template/child.tpl +++ b/tests/SurfStack/Templating/template/child.tpl @@ -1 +1,6 @@ -{extend file='parent.tpl'} \ No newline at end of file +{extend file='parent.tpl'} + +{section name='safe'} +Safe from child +{parent} +{/section} \ No newline at end of file diff --git a/tests/SurfStack/Templating/template/grandparent.tpl b/tests/SurfStack/Templating/template/grandparent.tpl index 7186b78..da46b01 100644 --- a/tests/SurfStack/Templating/template/grandparent.tpl +++ b/tests/SurfStack/Templating/template/grandparent.tpl @@ -1,9 +1,13 @@ -

Sweet

+

Hello world!

+
{section name='test'} -Replace from grandparent +Test from grandparent {/section} +
+
{section name='safe'} -leave from grandparent -{/section} \ No newline at end of file +Safe from grandparent +{/section} +
\ No newline at end of file diff --git a/tests/SurfStack/Templating/template/parent.tpl b/tests/SurfStack/Templating/template/parent.tpl index 01472f9..2bc217e 100644 --- a/tests/SurfStack/Templating/template/parent.tpl +++ b/tests/SurfStack/Templating/template/parent.tpl @@ -1,5 +1,6 @@ {extend file='grandparent.tpl'} {section name='test'} +{parent} Test from parent -{/section} \ No newline at end of file +{/section}