Skip to content

Commit

Permalink
ticket #1396 - fixed regression: jtpl plugin 'include' couldn't handl…
Browse files Browse the repository at this point in the history
…e recursivity because of metas.
  • Loading branch information
laurentj committed Jul 16, 2011
1 parent ca5dc80 commit 88240f6
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 48 deletions.
4 changes: 4 additions & 0 deletions build/manifests/testapp.mn
Expand Up @@ -7,6 +7,8 @@ cd testapp
INSTALL.txt
cd testapp/plugins
.htaccess
cd testapp/plugins/tpl/common/
meta.testinc.php
cd testapp/responses
myHtmlResponse.class.php
cd testapp/www
Expand Down Expand Up @@ -151,6 +153,8 @@ cd testapp/modules/jelix_tests/templates
menu.tpl
test_include.tpl
test_include_included.tpl
test_include_recursive.tpl
test_include_recursive2.tpl
test_plugin_counter_init_allarg_noexeption.tpl
test_plugin_counter_init_exeption.tpl
test_plugin_counter_init_noexeption.tpl
Expand Down
103 changes: 57 additions & 46 deletions lib/jelix/tpl/jTpl.class.php
Expand Up @@ -197,7 +197,25 @@ public function getTemplateVars () {
* @param boolean $trusted says if the template file is trusted or not
*/
public function meta ($tpl, $outputtype = '', $trusted = true) {
$this->getTemplate($tpl,'template_meta_', $outputtype, $trusted);
#ifnot JTPL_STANDALONE
$sel = new jSelectorTpl($tpl,$outputtype,$trusted);
$tpl = $sel->toString();
#endif
if (in_array($tpl, $this->processedMeta)) {
// we want to process meta only one time, when a template is included
// several time in an other template, or, more important, when a template
// is included in a recursive manner (in this case, it did cause infinite loop, see #1396).
return;
}
$this->processedMeta[] = $tpl;
#ifnot JTPL_STANDALONE
$md = $this->getTemplate ($sel, $outputtype, $trusted);
#else
$md = $this->getTemplate ($tpl, $outputtype, $trusted);
#endif
$fct = 'template_meta_'.$md;
$fct($this);

return $this->_meta;
}

Expand All @@ -208,7 +226,22 @@ public function meta ($tpl, $outputtype = '', $trusted = true) {
* @param boolean $trusted says if the template file is trusted or not
*/
public function display ($tpl, $outputtype = '', $trusted = true) {
$this->getTemplate ($tpl, 'template_', $outputtype, $trusted);
#ifnot JTPL_STANDALONE
$sel = new jSelectorTpl($tpl,$outputtype,$trusted);
$tpl = $sel->toString();
#endif
$previousTpl = $this->_templateName;
$this->_templateName = $tpl;
$this->recursiveTpl[] = $tpl;
#ifnot JTPL_STANDALONE
$md = $this->getTemplate ($sel, $outputtype, $trusted);
#else
$md = $this->getTemplate ($tpl, $outputtype, $trusted);
#endif
$fct = 'template_'.$md;
$fct($this);
array_pop($this->recursiveTpl);
$this->_templateName = $previousTpl;
}

/**
Expand All @@ -220,23 +253,23 @@ public function display ($tpl, $outputtype = '', $trusted = true) {
*/
public $_templateName;

protected $recursiveTpl = array();
protected $processedMeta = array();

/**
* include the compiled template file and call one of the generated function
* @param string $tpl template selector
* @param string $fctname the internal function name (meta or content)
* @param string|jSelectorTpl $tpl template selector
* @param string $outputtype the type of output (html, text etc..)
* @param boolean $trusted says if the template file is trusted or not
* @return string the suffix name of the function to call
*/
protected function getTemplate ($tpl, $fctname, $outputtype = '', $trusted = true) {
protected function getTemplate ($tpl, $outputtype = '', $trusted = true) {
#ifnot JTPL_STANDALONE
$sel = new jSelectorTpl($tpl,$outputtype,$trusted);
$sel->userModifiers = $this->userModifiers;
$sel->userFunctions = $this->userFunctions;
jIncluder::inc($sel);
$this->_templateName = $sel->toString();
$fct = $fctname.md5($sel->module.'_'.$sel->resource.'_'.$sel->outputType.($trusted?'_t':''));
$tpl->userModifiers = $this->userModifiers;
$tpl->userFunctions = $this->userFunctions;
jIncluder::inc($tpl);
return md5($tpl->module.'_'.$tpl->resource.'_'.$tpl->outputType.($trusted?'_t':''));
#else
$this->_templateName = $tpl;
$tpl = jTplConfig::$templatePath . $tpl;
if ($outputtype == '')
$outputtype = 'html';
Expand Down Expand Up @@ -265,9 +298,8 @@ protected function getTemplate ($tpl, $fctname, $outputtype = '', $trusted = tru
$this->userModifiers, $this->userFunctions);
}
require_once($cachefile);
$fct = $fctname.md5($tpl.'_'.$outputtype.($trusted?'_t':''));
return md5($tpl.'_'.$outputtype.($trusted?'_t':''));
#endif
$fct($this);
}

/**
Expand All @@ -284,46 +316,25 @@ public function fetch ($tpl, $outputtype='', $trusted = true, $callMeta=true) {
try{
#ifnot JTPL_STANDALONE
$sel = new jSelectorTpl($tpl, $outputtype, $trusted);
$sel->userModifiers = $this->userModifiers;
$sel->userFunctions = $this->userFunctions;
jIncluder::inc($sel);
$md = md5($sel->module.'_'.$sel->resource.'_'.$sel->outputType.($trusted?'_t':''));
$this->_templateName = $sel->toString();
#else
$tpl = $sel->toString();
#endif
$previousTpl = $this->_templateName;
$this->_templateName = $tpl;
$tpl = jTplConfig::$templatePath . $tpl;

$cachefile = dirname($this->_templateName).'/';
if ($cachefile == './')
$cachefile = '';

if (jTplConfig::$cachePath == '/' || jTplConfig::$cachePath == '')
throw new Exception('cache path is invalid ! its value is: "'.jTplConfig::$cachePath.'".');

$cachefile = jTplConfig::$cachePath.$cachefile.$outputtype.($trusted?'_t':'').'_'.basename($tpl);

$mustCompile = jTplConfig::$compilationForce || !file_exists($cachefile);
if (!$mustCompile) {
if (filemtime($tpl) > filemtime($cachefile)) {
$mustCompile = true;
}
}

if ($mustCompile) {
include_once(JTPL_PATH . 'jTplCompiler.class.php');
$compiler = new jTplCompiler();
$compiler->compile($this->_templateName, $tpl, $outputtype,
$trusted, $this->userModifiers, $this->userFunctions);
}
require_once($cachefile);
$md = md5($tpl.'_'.$outputtype.($trusted?'_t':''));
$this->processedMeta[] = $tpl;
$this->recursiveTpl[] = $tpl;
#ifnot JTPL_STANDALONE
$md = $this->getTemplate ($sel, $outputtype, $trusted);
#else
$md = $this->getTemplate ($tpl, $outputtype, $trusted);
#endif
if ($callMeta) {
$fct = 'template_meta_'.$md;
$fct($this);
}
$fct = 'template_'.$md;
$fct($this);
array_pop($this->recursiveTpl);
$this->_templateName = $previousTpl;
$content = ob_get_clean();

} catch(Exception $e) {
Expand Down
1 change: 0 additions & 1 deletion lib/jelix/tpl/jTplCompiler.class.php
Expand Up @@ -166,7 +166,6 @@ function __construct () {
#endif
}


#if JTPL_STANDALONE
/**
* Launch the compilation of a template
Expand Down
@@ -0,0 +1,5 @@
{meta main count($items)}{meta_testinc counter}
c={=count($items)}
{assign $dummy=array_pop($items)}
x={$dummy}
{if count($items) > 0}{include 'test_include_recursive'}{/if}
@@ -0,0 +1,3 @@
{assign $items=array(1,2)}{include 'test_include_recursive'}
{assign $items=array(3,4)}{include 'test_include_recursive'}

21 changes: 20 additions & 1 deletion testapp/modules/jelix_tests/tests/jtpl.plugins.html.php
Expand Up @@ -253,6 +253,25 @@ function testInclude() {
", $content);
}

function testIncludeRecursive() {
// when a template includes itself, meta should be retrieved only one time
// to avoid infinite loop
$tpl = new jTpl();
$tpl->assign('items', array(1,2));
$meta = $tpl->meta('test_include_recursive');
$content = $tpl->fetch('test_include_recursive');
$this->assertEqual(array('main'=>'2', 'counter'=>1), $meta);
$this->assertEqualOrDiff("c=2\nx=2\nc=1\nx=1\n" , $content);

// if a template includes an other template more than one time,
// meta should be retrieved only one time
$tpl = new jTpl();
$tpl->assign('items', array());
$meta = $tpl->meta('test_include_recursive2');
$content = $tpl->fetch('test_include_recursive2');
$this->assertEqual(array('main'=>'0', 'counter'=>1), $meta);
$this->assertEqualOrDiff("c=2\nx=2\nc=1\nx=1\nc=2\nx=4\nc=1\nx=3\n\n", $content);
}
}

?>
10 changes: 10 additions & 0 deletions testapp/plugins/tpl/common/meta.testinc.php
@@ -0,0 +1,10 @@
<?php

function jtpl_meta_common_testinc($tpl, $variable)
{
if (isset($tpl->_meta[$variable])) {
$tpl->_meta[$variable]++;
}
else
$tpl->_meta[$variable] = 1;
}

0 comments on commit 88240f6

Please sign in to comment.