From eef14ecf06e6539401fe34c8bf5636b0632a2fdd Mon Sep 17 00:00:00 2001 From: Ivan Shalganov Date: Thu, 9 Jun 2016 22:58:05 +0300 Subject: [PATCH 01/15] Update CHANGELOG.md --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bae9f9a..38a9b9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ Changelog ========= +## 2.11.0 (2016-06-09) + +- Added method to get the name of the cache template `$fenom->getCacheName($template_name)`(#231) +- Fix bug with before-code in template inheritance (#229) +- Added `??` operator. +- Improve compile mechanism +- ++Docs +- ++Test + +## 2.10.0 (2016-05-08) + +- Add tag `{do ...}` +- ++Docs +- ++Tests + ## 2.9.0 (2016-05-08) - Add `$.block` From 7fffa19fa901315f06d9a0e4ddce2681bddfa826 Mon Sep 17 00:00:00 2001 From: bzick Date: Fri, 10 Jun 2016 15:51:23 +0300 Subject: [PATCH 02/15] Fix valid filename and length --- src/Fenom.php | 15 ++++++++++++--- tests/cases/Fenom/TemplateTest.php | 21 --------------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/Fenom.php b/src/Fenom.php index 6e15d1d..c117068 100644 --- a/src/Fenom.php +++ b/src/Fenom.php @@ -64,6 +64,11 @@ class Fenom public static $charset = "UTF-8"; + /** + * @var int maximum length of compiled filename (use sha1 of name if bigger) + */ + public static $filename_length = 200; + /** * @var int[] of possible options, as associative array * @see setOptions @@ -1075,13 +1080,17 @@ class Fenom if (is_array($tpl)) { $hash = implode(".", $tpl) . ":" . $options; foreach ($tpl as &$t) { - $t = str_replace(":", "_", basename($t)); + $t = urlencode(str_replace(":", "_", basename($t))); } - return $this->_compile_id . implode("~", $tpl) . "." . sprintf("%x.%x.php", crc32($hash), strlen($hash)); + $tpl = implode("~", $tpl); } else { $hash = $tpl . ":" . $options; - return sprintf($this->_compile_id . "%s.%x.%x.php", str_replace(":", "_", basename($tpl)), crc32($hash), strlen($hash)); + $tpl = urlencode(str_replace(":", "_", basename($tpl))); } + if($tpl > self::$filename_length) { + $tpl = sha1($tpl); + } + return $this->_compile_id . $tpl . "." . sprintf("%x.%x.php", crc32($hash), strlen($hash)); } /** diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 31247d3..882fa7d 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -1129,27 +1129,6 @@ class TemplateTest extends TestCase ); } - /** - * @group sb - */ - public function _testSandbox() - { - try { - var_dump( - $this->fenom->compileCode( - '{Fenom\Helper::method()->page->title}' - )->getBody() - ); - } catch (\Exception $e) { - print_r($e->getMessage() . "\n" . $e->getTraceAsString()); - while ($e->getPrevious()) { - $e = $e->getPrevious(); - print_r("\n\n" . $e->getMessage() . " in {$e->getFile()}:{$e->getLine()}\n" . $e->getTraceAsString()); - } - } - exit; - } - /** * @dataProvider providerScalars */ From 23cf3e72ad5b34db0fd74f51b9d6c6df551f0371 Mon Sep 17 00:00:00 2001 From: Vasily Krakovetsky Date: Wed, 29 Jun 2016 21:20:30 +0300 Subject: [PATCH 03/15] fix typo --- docs/ru/tags/extends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/tags/extends.md b/docs/ru/tags/extends.md index 54dd957..3ab8a82 100644 --- a/docs/ru/tags/extends.md +++ b/docs/ru/tags/extends.md @@ -48,7 +48,7 @@ ### `{paste}` -Иставка кода блока в любое место через тег `{paste}` +Вставка кода блока в любое место через тег `{paste}` ```smarty {block 'b1'} From 0d599cb211b1cc31c5577453aa28ad366ab530a3 Mon Sep 17 00:00:00 2001 From: Xesau Date: Tue, 5 Jul 2016 20:10:23 +0200 Subject: [PATCH 04/15] Translated one sentence from Russian to English... and added documentation for {parent} --- docs/en/tags/extends.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/en/tags/extends.md b/docs/en/tags/extends.md index 54310b9..e2ae8af 100644 --- a/docs/en/tags/extends.md +++ b/docs/en/tags/extends.md @@ -19,7 +19,7 @@ Also if a child template extends a parent template with the `{extends}` tag it m ### {use} -Что бы импортировать блоки из другого шаблона используйте тег {use}: +Import the blocks defined in another file. Specifying blocks in this template will override those from the other file. ```smarty {use 'blocks.tpl'} merge blocks from blocks.tpl template @@ -31,6 +31,8 @@ Also if a child template extends a parent template with the `{extends}` tag it m ### {parent} +Uses the code from the block as defined in the parent. + ```smarty {extends 'parent.tpl'} @@ -43,7 +45,7 @@ Also if a child template extends a parent template with the `{extends}` tag it m ### {paste} -Paste code of any block +Pastes the code of any block ```smarty {block 'b1'} @@ -65,4 +67,4 @@ Checks if clock exists {if $.block.header} block header exists {/if} -``` \ No newline at end of file +``` From ade29f5d67e743f881e1e34ebd1c3d452ad4b221 Mon Sep 17 00:00:00 2001 From: Igor Date: Fri, 12 Aug 2016 19:14:12 +0300 Subject: [PATCH 05/15] Update adapters.md --- docs/ru/adapters.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/ru/adapters.md b/docs/ru/adapters.md index e6d6e52..0082d37 100644 --- a/docs/ru/adapters.md +++ b/docs/ru/adapters.md @@ -5,4 +5,5 @@ * [Fenom + Kohana](https://github.com/2bj/kofenom) — Kofenom * Fenom + Symphony * Fenom + Symphony2 -* Fenom + Zend Framework 2 \ No newline at end of file +* Fenom + Zend Framework 2 +* [Fenom + MODX Revolution](https://docs.modx.pro/components/pdotools/parser#Шаблонизатор-Fenom) From d64706b675d7dc92501b6a1e37c39a2426fe2a2d Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Sat, 13 Aug 2016 20:53:11 +0500 Subject: [PATCH 06/15] =?UTF-8?q?=D0=97=D0=B0=D0=BC=D0=B5=D1=87=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit http://php.net/manual/ru/function.fnmatch.php --- docs/ru/mods/match.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/ru/mods/match.md b/docs/ru/mods/match.md index 47accde..068e1a1 100644 --- a/docs/ru/mods/match.md +++ b/docs/ru/mods/match.md @@ -23,4 +23,7 @@ {if $color|match:"*gr[ae]y"} какой-то оттенок серого {/if} -``` \ No newline at end of file +``` + +**Замечание:** +максимальная длинна проверяемой строки не должна превышать 4096 символов. From 3171d80d8b1d2a7fcbc1f2ff320ad4a972a474ae Mon Sep 17 00:00:00 2001 From: bzick Date: Mon, 22 Aug 2016 17:08:47 +0300 Subject: [PATCH 07/15] Fix #247 --- sandbox/fenom.php | 8 ++- src/Fenom/Template.php | 124 +++++++++++++++++++++++--------------- tests/autoload.php | 6 +- tests/cases/FenomTest.php | 2 +- 4 files changed, 83 insertions(+), 57 deletions(-) diff --git a/sandbox/fenom.php b/sandbox/fenom.php index 3f3c9fd..22d5513 100644 --- a/sandbox/fenom.php +++ b/sandbox/fenom.php @@ -5,9 +5,11 @@ require_once __DIR__.'/../tests/tools.php'; \Fenom::registerAutoload(); -$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/../tests/resources/compile'); -$fenom->setOptions(Fenom::AUTO_RELOAD); -var_dump($fenom->compileCode('{do $object->method()}')->getTemplateCode()); +$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled'); +$fenom->setOptions(Fenom::AUTO_RELOAD | Fenom::FORCE_VERIFY); +//var_dump($fenom->compile("nested.tpl", [])->getTemplateCode()); +//exit; +var_dump($fenom->fetch('bug247/home.tpl', [])); //var_dump($fenom->compile("bug158/main.tpl", [])->getTemplateCode()); //var_dump($fenom->display("bug158/main.tpl", [])); // $fenom->getTemplate("problem.tpl"); \ No newline at end of file diff --git a/src/Fenom/Template.php b/src/Fenom/Template.php index 097b7b6..9a5b449 100644 --- a/src/Fenom/Template.php +++ b/src/Fenom/Template.php @@ -10,11 +10,11 @@ namespace Fenom; use Fenom; -use Fenom\Error\UnexpectedTokenException; use Fenom\Error\CompileException; use Fenom\Error\InvalidUsageException; use Fenom\Error\SecurityException; use Fenom\Error\TokenizeException; +use Fenom\Error\UnexpectedTokenException; /** * Template compiler @@ -27,6 +27,12 @@ class Template extends Render const VAR_NAME = '$var'; const TPL_NAME = '$tpl'; + const COMPILE_STAGE_LOADED = 1; + const COMPILE_STAGE_PRE_FILTERED = 2; + const COMPILE_STAGE_PARSED = 3; + const COMPILE_STAGE_PROCESSED = 4; + const COMPILE_STAGE_POST_FILTERED = 5; + /** * Disable array parser. */ @@ -80,6 +86,7 @@ class Template extends Render * @var string */ private $_body; + private $_compile_stage = 0; /** * Call stack @@ -166,6 +173,7 @@ class Template extends Render } $this->_provider = $this->_fenom->getProvider($provider); $this->_src = $this->_provider->getSource($this->_base_name, $this->_time); + $this->_compile_stage = self::COMPILE_STAGE_LOADED; if ($compile) { $this->compile(); } @@ -196,10 +204,12 @@ class Template extends Render */ public function compile() { - $end = $pos = 0; + $end = $pos = 0; foreach ($this->_fenom->getPreFilters() as $filter) { $this->_src = call_user_func($filter, $this, $this->_src); } + $this->_compile_stage = self::COMPILE_STAGE_PRE_FILTERED; + while (($start = strpos($this->_src, '{', $pos)) !== false) { // search open-symbol of tags switch (substr($this->_src, $start + 1, 1)) { // check next character case "\n": @@ -265,6 +275,7 @@ class Template extends Render } $pos = $end + 1; // move search-pointer to end of the tag } + $this->_compile_stage = self::COMPILE_STAGE_PARSED; gc_collect_cycles(); $this->_appendText(substr($this->_src, $end ? $end + 1 : 0)); // append tail of the template @@ -283,10 +294,16 @@ class Template extends Render call_user_func_array($cb, array($this, &$this->_body)); } } + $this->_compile_stage = self::COMPILE_STAGE_PROCESSED; $this->addDepend($this); // for 'verify' performance foreach ($this->_fenom->getPostFilters() as $filter) { $this->_body = call_user_func($filter, $this, $this->_body); } + $this->_compile_stage = self::COMPILE_STAGE_POST_FILTERED; + } + + public function isStageDone($stage_no) { + return $this->_compile_stage >= $stage_no; } /** @@ -350,7 +367,7 @@ class Template extends Render } else { $text = str_replace("' . ($strip ? '' : PHP_EOL), $text); } - if($strip) { + if ($strip) { $text = preg_replace('/\s+/uS', ' ', str_replace(array("\r", "\n"), " ", $text)); $text = str_replace("> <", "><", $text); } @@ -376,7 +393,8 @@ class Template extends Render /** * @param $tag_name */ - public function ignore($tag_name) { + public function ignore($tag_name) + { $this->_ignore = $tag_name; } @@ -490,7 +508,7 @@ class Template extends Render $escape = $this->_options & Fenom::AUTO_ESCAPE; } if ($escape) { - return "echo htmlspecialchars($data, ENT_COMPAT, ".var_export(Fenom::$charset, true).");"; + return "echo htmlspecialchars($data, ENT_COMPAT, " . var_export(Fenom::$charset, true) . ");"; } else { return "echo $data;"; } @@ -519,13 +537,13 @@ class Template extends Render */ public function extend($tpl) { - if (!$this->_body) { + if (!$this->isStageDone(self::COMPILE_STAGE_PARSED)) { $this->compile(); } $parent = $this->_fenom->getRawTemplate()->load($tpl, false); - $parent->blocks = & $this->blocks; - $parent->macros = & $this->macros; - $parent->_before = & $this->_before; + $parent->blocks = &$this->blocks; + $parent->macros = &$this->macros; + $parent->_before = &$this->_before; $parent->extended = $this->getName(); if (!$this->ext_stack) { $this->ext_stack[] = $this->getName(); @@ -638,10 +656,12 @@ class Template extends Render } } if ($tags = $this->_fenom->getTagOwners($action)) { // unknown template tag - throw new TokenizeException("Unexpected tag '$action' (this tag can be used with '" . implode( + throw new TokenizeException( + "Unexpected tag '$action' (this tag can be used with '" . implode( "', '", $tags - ) . "')"); + ) . "')" + ); } else { throw new TokenizeException("Unexpected tag '$action'"); } @@ -675,9 +695,9 @@ class Template extends Render $term = $this->parseTerm($tokens, $var, -1); // term of the expression if ($term !== false) { if ($tokens->is('?', '!')) { - if($cond) { + if ($cond) { $term = array_pop($exp) . ' ' . $term; - $term = '('. array_pop($exp) . ' ' . $term . ')'; + $term = '(' . array_pop($exp) . ' ' . $term . ')'; $var = false; } $term = $this->parseTernary($tokens, $term, $var); @@ -707,7 +727,7 @@ class Template extends Render break; } $op = $tokens->getAndNext(); - if($op == '[') { + if ($op == '[') { $tokens->need(']')->next()->need('=')->next(); $op = '[]='; } @@ -742,7 +762,7 @@ class Template extends Render $tokens->next(); $concat[] = "' '"; } - if (!$term2 = "strval(".$this->parseTerm($tokens).")") { + if (!$term2 = "strval(" . $this->parseTerm($tokens) . ")") { throw new UnexpectedTokenException($tokens); } $concat[] = $term2; @@ -762,7 +782,7 @@ class Template extends Render throw new UnexpectedTokenException($tokens); } - if(count($exp) == 1 && $var) { + if (count($exp) == 1 && $var) { $is_var = true; } return implode(' ', $exp); @@ -785,7 +805,7 @@ class Template extends Render } else { $unary = ""; } - switch($tokens->key()) { + switch ($tokens->key()) { case T_LNUMBER: case T_DNUMBER: $code = $unary . $this->parseScalar($tokens); @@ -801,13 +821,13 @@ class Template extends Render /** @noinspection PhpMissingBreakStatementInspection */ case '$': $code = $this->parseAccessor($tokens, $is_var); - if(!$is_var) { + if (!$is_var) { $code = $unary . $code; break; } - /* no break */ + /* no break */ case T_VARIABLE: - if(!isset($code)) { + if (!isset($code)) { $code = $this->parseVariable($tokens); } if ($tokens->is("(") && $tokens->hasBackList(T_STRING, T_OBJECT_OPERATOR)) { @@ -816,25 +836,25 @@ class Template extends Render } $code = $unary . $this->parseChain($tokens, $code); } elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) { - if($this->_options & Fenom::FORCE_VERIFY) { + if ($this->_options & Fenom::FORCE_VERIFY) { $code = $unary . '(isset(' . $code . ') ? ' . $code . $tokens->getAndNext() . ' : null)'; } else { $code = $unary . $code . $tokens->getAndNext(); } } else { - if($this->_options & Fenom::FORCE_VERIFY) { + if ($this->_options & Fenom::FORCE_VERIFY) { $code = $unary . '(isset(' . $code . ') ? ' . $code . ' : null)'; } else { $is_var = true; - $code = $unary . $code; + $code = $unary . $code; } } break; case T_DEC: case T_INC: - if($this->_options & Fenom::FORCE_VERIFY) { - $var = $this->parseVariable($tokens); - $code = $unary . '(isset(' . $var . ') ? ' . $tokens->getAndNext() . $this->parseVariable($tokens).' : null)'; + if ($this->_options & Fenom::FORCE_VERIFY) { + $var = $this->parseVariable($tokens); + $code = $unary . '(isset(' . $var . ') ? ' . $tokens->getAndNext() . $this->parseVariable($tokens) . ' : null)'; } else { $code = $unary . $tokens->getAndNext() . $this->parseVariable($tokens); } @@ -853,7 +873,7 @@ class Template extends Render throw new \Exception("Function " . $tokens->getAndNext() . " not found"); } if (!is_string($func)) { // dynamic modifier - $call = 'call_user_func_array($tpl->getStorage()->getModifier("' . $modifier . '"), array'.$this->parseArgs($tokens->next()).')'; // @todo optimize + $call = 'call_user_func_array($tpl->getStorage()->getModifier("' . $modifier . '"), array' . $this->parseArgs($tokens->next()) . ')'; // @todo optimize } else { $call = $func . $this->parseArgs($tokens->next()); } @@ -890,13 +910,13 @@ class Template extends Render } } if (($allows & self::TERM_MODS) && $tokens->is('|')) { - $code = $this->parseModifier($tokens, $code); - $is_var = false; + $code = $this->parseModifier($tokens, $code); + $is_var = false; } - if(($allows & self::TERM_RANGE) && $tokens->is('.') && $tokens->isNext('.')) { + if (($allows & self::TERM_RANGE) && $tokens->is('.') && $tokens->isNext('.')) { $tokens->next()->next(); - $code = '(new \Fenom\RangeIterator('.$code.', '.$this->parseTerm($tokens, $var, self::TERM_MODS).'))'; - $is_var = false; + $code = '(new \Fenom\RangeIterator(' . $code . ', ' . $this->parseTerm($tokens, $var, self::TERM_MODS) . '))'; + $is_var = false; } return $code; } @@ -907,7 +927,8 @@ class Template extends Render * @param string $code start point (it is $var) * @return string */ - public function parseChain(Tokenizer $tokens, $code) { + public function parseChain(Tokenizer $tokens, $code) + { do { if ($tokens->is('(')) { $code .= $this->parseArgs($tokens); @@ -930,10 +951,10 @@ class Template extends Render public function parseVariable(Tokenizer $tokens, $var = null) { if (!$var) { - if($tokens->isNext('@')) { + if ($tokens->isNext('@')) { // $v = $tokens->get(T_VARIABLE); $prop = $tokens->next()->next()->get(T_STRING); - if($tag = $this->getParentScope("foreach")) { + if ($tag = $this->getParentScope("foreach")) { $tokens->next(); return Compiler::foreachProp($tag, $prop); } else { @@ -955,7 +976,7 @@ class Template extends Render $key = "[" . $tokens->getAndNext() . "]"; } elseif ($tokens->is('"')) { $key = "[" . $this->parseQuote($tokens) . "]"; - } elseif($tokens->is('.')) { + } elseif ($tokens->is('.')) { $tokens->back(); break; } else { @@ -963,7 +984,7 @@ class Template extends Render } $var .= $key; } elseif ($t === "[") { - if($tokens->isNext(']')) { + if ($tokens->isNext(']')) { break; } $tokens->next(); @@ -1001,16 +1022,23 @@ class Template extends Render public function parseAccessor(Tokenizer $tokens, &$is_var = false) { $accessor = $tokens->need('$')->next()->need('.')->next()->current(); - $parser = $this->getStorage()->getAccessor($accessor); - $is_var = false; - if($parser) { - if(is_array($parser)) { - if(isset($parser['callback'])) { + $parser = $this->getStorage()->getAccessor($accessor); + $is_var = false; + if ($parser) { + if (is_array($parser)) { + if (isset($parser['callback'])) { $tokens->next(); - return 'call_user_func($tpl->getStorage()->getAccessor('.var_export($accessor, true). - ', "callback"), '.var_export($accessor, true).', $tpl, $var)'; + return 'call_user_func($tpl->getStorage()->getAccessor(' . var_export($accessor, true) . + ', "callback"), ' . var_export($accessor, true) . ', $tpl, $var)'; } else { - return call_user_func_array($parser['parser'], array($parser['accessor'], $tokens->next(), $this, &$is_var)); + return call_user_func_array( + $parser['parser'], array( + $parser['accessor'], + $tokens->next(), + $this, + &$is_var + ) + ); } } else { return call_user_func_array($parser, array($tokens->next(), $this, &$is_var)); @@ -1365,15 +1393,15 @@ class Template extends Render $count++; } else { $expr = $this->parseExpr($tokens); - if($tokens->is(T_DOUBLE_ARROW)) { + if ($tokens->is(T_DOUBLE_ARROW)) { $tokens->next(); - $arr[] = $expr.' => '.$this->parseExpr($tokens); + $arr[] = $expr . ' => ' . $this->parseExpr($tokens); } else { $arr[] = $expr; } $count++; } - if($tokens->is(',')) { + if ($tokens->is(',')) { $tokens->next(); } } diff --git a/tests/autoload.php b/tests/autoload.php index 0259429..d8b47a4 100644 --- a/tests/autoload.php +++ b/tests/autoload.php @@ -9,8 +9,4 @@ require_once FENOM_RESOURCES . "/actions.php"; require_once __DIR__ . "/TestCase.php"; require_once __DIR__ . "/tools.php"; -ini_set('date.timezone', 'Europe/Moscow'); - -if(PHP_VERSION_ID > 50400) { - function php_gte_54() {} -} \ No newline at end of file +ini_set('date.timezone', 'Europe/Moscow'); \ No newline at end of file diff --git a/tests/cases/FenomTest.php b/tests/cases/FenomTest.php index 737d34c..e0c45e4 100644 --- a/tests/cases/FenomTest.php +++ b/tests/cases/FenomTest.php @@ -321,7 +321,7 @@ class FenomTest extends \Fenom\TestCase /** - * @requires function php_gte_54 + * @requires PHP 5.4 * @group pipe */ public function testPipe() From 514b0b6769ed4e93dae05ce4761c15377904a408 Mon Sep 17 00:00:00 2001 From: bzick Date: Mon, 22 Aug 2016 17:09:02 +0300 Subject: [PATCH 08/15] Fix #247 --- sandbox/templates/bug247/base.tpl | 11 +++++++++++ sandbox/templates/bug247/home.tpl | 1 + 2 files changed, 12 insertions(+) create mode 100644 sandbox/templates/bug247/base.tpl create mode 100644 sandbox/templates/bug247/home.tpl diff --git a/sandbox/templates/bug247/base.tpl b/sandbox/templates/bug247/base.tpl new file mode 100644 index 0000000..f7c618a --- /dev/null +++ b/sandbox/templates/bug247/base.tpl @@ -0,0 +1,11 @@ + + + + + + + + +{block 'content'}{/block} + + \ No newline at end of file diff --git a/sandbox/templates/bug247/home.tpl b/sandbox/templates/bug247/home.tpl new file mode 100644 index 0000000..b482960 --- /dev/null +++ b/sandbox/templates/bug247/home.tpl @@ -0,0 +1 @@ +{extends 'bug247/base.tpl'} \ No newline at end of file From cd4f68808859141ca773bb8d68b71094c9c08b45 Mon Sep 17 00:00:00 2001 From: bzick Date: Sat, 27 Aug 2016 22:30:34 +0300 Subject: [PATCH 09/15] Fix #249 --- sandbox/fenom.php | 66 +++++++++++++++++++++++++++++- sandbox/templates/bug249/bread.tpl | 38 +++++++++++++++++ src/Fenom/RangeIterator.php | 2 +- tests/cases/Fenom/TemplateTest.php | 5 +++ 4 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 sandbox/templates/bug249/bread.tpl diff --git a/sandbox/fenom.php b/sandbox/fenom.php index 22d5513..6b8ccf6 100644 --- a/sandbox/fenom.php +++ b/sandbox/fenom.php @@ -5,11 +5,73 @@ require_once __DIR__.'/../tests/tools.php'; \Fenom::registerAutoload(); +$vars = [ + [ + "id" => 1, + "name" => "Блаблабла", + "hidden_url" => "/" + ], + [ + "id" => 2, + "name" => "Каталог", + "hidden_url" => "/catalog" + ], + [ + "id" => 3, + "name" => "Сыромолочная группа", + "hidden_url" => "/catalog/cat_1.html" + ], + [ + "id" => 4, + "name" => "Сыры", + "hidden_url" => "/catalog/cat_2.html" + ], +]; + $fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled'); $fenom->setOptions(Fenom::AUTO_RELOAD | Fenom::FORCE_VERIFY); //var_dump($fenom->compile("nested.tpl", [])->getTemplateCode()); //exit; -var_dump($fenom->fetch('bug247/home.tpl', [])); +var_dump($fenom->fetch('bug249/bread.tpl', ["arr" => $vars])); +//var_dump($fenom->compile('bug249/bread.tpl', false)->getBody()); //var_dump($fenom->compile("bug158/main.tpl", [])->getTemplateCode()); //var_dump($fenom->display("bug158/main.tpl", [])); -// $fenom->getTemplate("problem.tpl"); \ No newline at end of file +// $fenom->getTemplate("problem.tpl"); + +/* + * + * Array +( + [0] => Array + ( + [id] => 1 + [name] => Блаблабла + [hidden_url] => / + ) + [1] => Array + ( + [id] => 2 + [name] => Каталог + [hidden_url] => /catalog/ + ) + [2] => Array + ( + [orig_id] => 1 + [hidden_url] => /catalog/cat_1.html + [name] => Сыромолочная группа + ) + [3] => Array + ( + [orig_id] => 2 + [hidden_url] => /catalog/cat_2.html + [name] => Сыры + ) + [4] => Array + ( + [orig_id] => 6 + [hidden_url] => /catalog/cat_6.html + [name] => Сыр плавленый + ) +) + + */ \ No newline at end of file diff --git a/sandbox/templates/bug249/bread.tpl b/sandbox/templates/bug249/bread.tpl new file mode 100644 index 0000000..df6d4d6 --- /dev/null +++ b/sandbox/templates/bug249/bread.tpl @@ -0,0 +1,38 @@ +{*
*} + {**} +{*
*} + +=== {(1..3)|length} === + +{foreach 1..3 as $c index=$i first=$first last=$last} + {$i}: {$last} +{/foreach} + +
+
    +
  • Главная
  • + {foreach $arr as $item first=$first last=$last} + {if !$first} +
  • /
  • +
  • {$last} + {if $last} + {$item.name} + {else} + {$item.name} + {/if} +
  • + {/if} + {/foreach} +
+
\ No newline at end of file diff --git a/src/Fenom/RangeIterator.php b/src/Fenom/RangeIterator.php index 2d5cfb1..8bb0a79 100644 --- a/src/Fenom/RangeIterator.php +++ b/src/Fenom/RangeIterator.php @@ -90,7 +90,7 @@ class RangeIterator implements \Iterator, \Countable */ public function count() { - return intval(($this->max - $this->min) / $this->step); + return intval(($this->max - $this->min + 1) / $this->step); } /** diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 882fa7d..061b9b8 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -1406,6 +1406,11 @@ class TemplateTest extends TestCase $a, 'Foreach: 0 => 1, 1 => 2, 2 => 3, end' ), + array( + 'Foreach: {foreach 1..3 as $k => $e last=$l} {$k} => {$e}, {if $l}last{/if} {/foreach} end', + $a, + 'Foreach: 0 => 1, 1 => 2, 2 => 3, last end' + ), array( 'Foreach: {foreach $.get.items as $e} {$e}, {/foreach} end', $a, From 05cda5426d133982ffb6299a01dad9f0c5b080eb Mon Sep 17 00:00:00 2001 From: Max Kostjukevich Date: Fri, 16 Sep 2016 09:16:30 +0300 Subject: [PATCH 10/15] Update extend.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit опечатки --- docs/ru/ext/extend.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/ext/extend.md b/docs/ru/ext/extend.md index 9457d02..4c6b33c 100644 --- a/docs/ru/ext/extend.md +++ b/docs/ru/ext/extend.md @@ -141,7 +141,7 @@ $fenom->addAccessor('project', function (Fenom\Tokenizer $tokens) { /* code */ } ## Готовые решения Орпеделить парсер для глобальной переменной весьма трудозатратно и требует полного понимания как работают парсеры в Fenom. -Это не удобно. Поэтому есть несколько предзаготовленных (умных) парсеоров, которые берут рутину на себя, а пользоватею остается указать ключевые параметры. +Это не удобно. Поэтому есть несколько предзаготовленных (умных) парсеров, которые берут рутину на себя, а пользователю остается указать ключевые параметры. Умные парсеты добавляются через метод `Fenom::addAccessorSmart(string $name, string $accessor, string $parser)`, где `$name` имя глобальной переменной, `$accessor` — параметр к парсеру, `$parser` — предопределенный парсер. From b92e0bbad331f89de8655ecbc081ee0fde2d1e55 Mon Sep 17 00:00:00 2001 From: bzick Date: Sun, 9 Oct 2016 23:40:37 +0300 Subject: [PATCH 11/15] Fix #241 + tests --- sandbox/fenom.php | 65 +---------------- sandbox/templates/bug241/recursive.tpl | 3 + src/Fenom.php | 4 +- src/Fenom/Compiler.php | 25 +++++-- src/Fenom/Template.php | 11 ++- tests/TestCase.php | 6 ++ tests/cases/Fenom/TemplateTest.php | 98 +++++++++++++++----------- 7 files changed, 95 insertions(+), 117 deletions(-) create mode 100644 sandbox/templates/bug241/recursive.tpl diff --git a/sandbox/fenom.php b/sandbox/fenom.php index 6b8ccf6..e4709c9 100644 --- a/sandbox/fenom.php +++ b/sandbox/fenom.php @@ -5,73 +5,12 @@ require_once __DIR__.'/../tests/tools.php'; \Fenom::registerAutoload(); -$vars = [ - [ - "id" => 1, - "name" => "Блаблабла", - "hidden_url" => "/" - ], - [ - "id" => 2, - "name" => "Каталог", - "hidden_url" => "/catalog" - ], - [ - "id" => 3, - "name" => "Сыромолочная группа", - "hidden_url" => "/catalog/cat_1.html" - ], - [ - "id" => 4, - "name" => "Сыры", - "hidden_url" => "/catalog/cat_2.html" - ], -]; - $fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled'); -$fenom->setOptions(Fenom::AUTO_RELOAD | Fenom::FORCE_VERIFY); +$fenom->setOptions(Fenom::AUTO_RELOAD | Fenom::FORCE_VERIFY | Fenom::FORCE_INCLUDE); //var_dump($fenom->compile("nested.tpl", [])->getTemplateCode()); //exit; -var_dump($fenom->fetch('bug249/bread.tpl', ["arr" => $vars])); +var_dump($fenom->compile('bug241/recursive.tpl', false)->getBody()); //var_dump($fenom->compile('bug249/bread.tpl', false)->getBody()); //var_dump($fenom->compile("bug158/main.tpl", [])->getTemplateCode()); //var_dump($fenom->display("bug158/main.tpl", [])); // $fenom->getTemplate("problem.tpl"); - -/* - * - * Array -( - [0] => Array - ( - [id] => 1 - [name] => Блаблабла - [hidden_url] => / - ) - [1] => Array - ( - [id] => 2 - [name] => Каталог - [hidden_url] => /catalog/ - ) - [2] => Array - ( - [orig_id] => 1 - [hidden_url] => /catalog/cat_1.html - [name] => Сыромолочная группа - ) - [3] => Array - ( - [orig_id] => 2 - [hidden_url] => /catalog/cat_2.html - [name] => Сыры - ) - [4] => Array - ( - [orig_id] => 6 - [hidden_url] => /catalog/cat_6.html - [name] => Сыр плавленый - ) -) - - */ \ No newline at end of file diff --git a/sandbox/templates/bug241/recursive.tpl b/sandbox/templates/bug241/recursive.tpl new file mode 100644 index 0000000..7b72475 --- /dev/null +++ b/sandbox/templates/bug241/recursive.tpl @@ -0,0 +1,3 @@ +{if $n < 10} + {include 'bug241/recursive.tpl' n=$n - 1} +{/if} \ No newline at end of file diff --git a/src/Fenom.php b/src/Fenom.php index c117068..d779731 100644 --- a/src/Fenom.php +++ b/src/Fenom.php @@ -944,9 +944,9 @@ class Fenom * * @return Fenom\Template */ - public function getRawTemplate() + public function getRawTemplate(Template $parent = null) { - return new Template($this, $this->_options); + return new Template($this, $this->_options, $parent); } /** diff --git a/src/Fenom/Compiler.php b/src/Fenom/Compiler.php index f72e52b..2a8dec3 100644 --- a/src/Fenom/Compiler.php +++ b/src/Fenom/Compiler.php @@ -38,13 +38,24 @@ class Compiler $p = $tpl->parseParams($tokens); if ($name) { if ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE) { - $inc = $tpl->getStorage()->compile($name, false); - $tpl->addDepend($inc); - $var = $tpl->tmpVar(); - if ($p) { - return $var . ' = $var; $var = ' . self::toArray($p) . ' + $var; ?>' . $inc->getBody() . '' . $inc->getBody() . 'parent) { + if($_t->parent->getName() == $name) { // recursion detected + $recursion = true; + } + $_t = $_t->parent; + } + if(!$recursion) { + $inc = $tpl->getStorage()->getRawTemplate($tpl); + $inc->load($name, true); + $tpl->addDepend($inc); + $var = $tpl->tmpVar(); + if ($p) { + return $var . ' = $var; $var = ' . self::toArray($p) . ' + $var; ?>' . $inc->getBody() . '' . $inc->getBody() . 'getStorage()->templateExists($name)) { throw new \LogicException("Template $name not found"); diff --git a/src/Fenom/Template.php b/src/Fenom/Template.php index 9a5b449..b6912c7 100644 --- a/src/Fenom/Template.php +++ b/src/Fenom/Template.php @@ -81,6 +81,12 @@ class Template extends Render public $extend_body = false; + /** + * Parent template + * @var Template + */ + public $parent; + /** * Template PHP code * @var string @@ -121,10 +127,11 @@ class Template extends Render /** * @param Fenom $fenom Template storage * @param int $options - * @return \Fenom\Template + * @param Template $parent */ - public function __construct(Fenom $fenom, $options) + public function __construct(Fenom $fenom, $options, Template $parent = null) { + $this->parent = $parent; $this->_fenom = $fenom; $this->_options = $options; $this->_filters = $this->_fenom->getFilters(); diff --git a/tests/TestCase.php b/tests/TestCase.php index c919bda..2299b4d 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -116,6 +116,12 @@ class TestCase extends \PHPUnit_Framework_TestCase return filemtime(FENOM_RESOURCES . '/template/' . $name); } + public function tpls(array $list) { + foreach($list as $name => $tpl) { + $this->tpl($name, $tpl); + } + } + /** * Compile and execute template * diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 061b9b8..a83f4b2 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -268,48 +268,6 @@ class TemplateTest extends TestCase ); } - public static function providerInclude() - { - $a = array( - "name" => "welcome", - "tpl" => "welcome.tpl", - "fragment" => "come", - "pr_fragment" => "Come", - "pr_name" => "Welcome", - "username" => "Master", - "email" => "dev@null.net" - ); - $result = 'Include Welcome, Master (dev@null.net) template'; - $result2 = 'Include Welcome, Flame (dev@null.net) template'; - $result3 = 'Include Welcome, Master (flame@dev.null) template'; - $result4 = 'Include Welcome, Flame (flame@dev.null) template'; - return array( - array('Include {include "welcome.tpl"} template', $a, $result), - array('Include {include "welcome.tpl"} template', $a, $result, Fenom::FORCE_INCLUDE), - array('Include {include $tpl} template', $a, $result), - array('Include {include "$tpl"} template', $a, $result), - array('Include {include "{$tpl}"} template', $a, $result), - array('Include {include "$name.tpl"} template', $a, $result), - array('Include {include "{$name}.tpl"} template', $a, $result), - array('Include {include "{$pr_name|lower}.tpl"} template', $a, $result), - array('Include {include "wel{$fragment}.tpl"} template', $a, $result), - array('Include {include "wel{$pr_fragment|lower}.tpl"} template', $a, $result), - array('Include {include "welcome.tpl" username="Flame"} template', $a, $result2), - array('Include {include "welcome.tpl" username="Flame"} template', $a, $result2, Fenom::FORCE_INCLUDE), - array('Include {include "welcome.tpl" email="flame@dev.null"} template', $a, $result3), - array( - 'Include {include "welcome.tpl" email="flame@dev.null"} template', - $a, - $result3, - Fenom::FORCE_INCLUDE - ), - array( - 'Include {include "welcome.tpl" username="Flame" email="flame@dev.null"} template', - $a, - $result4 - ), - ); - } public static function providerIncludeInvalid() { @@ -1195,12 +1153,66 @@ class TemplateTest extends TestCase $this->execError($code, $exception, $message, $options); } + + public static function providerInclude() + { + $a = array( + "name" => "welcome", + "tpl" => "welcome.tpl", + "fragment" => "come", + "pr_fragment" => "Come", + "pr_name" => "Welcome", + "username" => "Master", + "email" => "dev@null.net" + ); + + $result = 'Include Welcome, Master (dev@null.net) template'; + $result2 = 'Include Welcome, Flame (dev@null.net) template'; + $result3 = 'Include Welcome, Master (flame@dev.null) template'; + $result4 = 'Include Welcome, Flame (flame@dev.null) template'; + + $recursive_result = 'Include Hello, Master (dev@null.net) template'; + $recursive_result2 = 'Include Hello, Flame (dev@null.net) template'; + return array( + array('Include {include "welcome.tpl"} template', $a, $result), + array('Include {include "welcome.tpl"} template', $a, $result, Fenom::FORCE_INCLUDE), + array('Include {include "recursive.tpl"} template', $a, $recursive_result, Fenom::FORCE_INCLUDE), + array('Include {include $tpl} template', $a, $result), + array('Include {include "$tpl"} template', $a, $result), + array('Include {include "{$tpl}"} template', $a, $result), + array('Include {include "$name.tpl"} template', $a, $result), + array('Include {include "{$name}.tpl"} template', $a, $result), + array('Include {include "{$pr_name|lower}.tpl"} template', $a, $result), + array('Include {include "wel{$fragment}.tpl"} template', $a, $result), + array('Include {include "wel{$pr_fragment|lower}.tpl"} template', $a, $result), + array('Include {include "welcome.tpl" username="Flame"} template', $a, $result2), + array('Include {include "welcome.tpl" username="Flame"} template', $a, $result2, Fenom::FORCE_INCLUDE), + array('Include {include "recursive.tpl" username="Flame"} template', $a, $recursive_result2, Fenom::FORCE_INCLUDE), + array('Include {include "welcome.tpl" email="flame@dev.null"} template', $a, $result3), + array( + 'Include {include "welcome.tpl" email="flame@dev.null"} template', + $a, + $result3, + Fenom::FORCE_INCLUDE + ), + array( + 'Include {include "welcome.tpl" username="Flame" email="flame@dev.null"} template', + $a, + $result4, + ), + ); + } + /** - * @group include + * @group dev * @dataProvider providerInclude */ public function testInclude($code, $vars, $result, $options = 0) { + $this->tpls(array( + 'welcome.tpl' => 'Welcome, {$username} ({$email})', + 'recursive.tpl' => 'Hello, {$username} ({$email}){if false}{include "recursive.tpl"}{/if}' + )); $this->exec($code, $vars, $result, $options); } From 35455b761fa046550fc207b61a2620f9eede3a73 Mon Sep 17 00:00:00 2001 From: bzick Date: Mon, 10 Oct 2016 11:58:50 +0300 Subject: [PATCH 12/15] Fixed: Unrecognized option "src_dir" under "coveralls" --- .coveralls.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.coveralls.yml b/.coveralls.yml index 85cbc9f..dbc2427 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1,5 +1,4 @@ service_name: travis-ci -src_dir: src coverage_clover: build/logs/clover.xml From d139a1ebf361455061c16c3dc1cd2a48fc1b4e78 Mon Sep 17 00:00:00 2001 From: bzick Date: Fri, 18 Nov 2016 22:07:14 +0300 Subject: [PATCH 13/15] Fix #256 --- src/Fenom/Tag.php | 2 +- tests/cases/Fenom/TemplateTest.php | 70 ++++++++++++++++-------------- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/Fenom/Tag.php b/src/Fenom/Tag.php index 070ff42..4e69c39 100644 --- a/src/Fenom/Tag.php +++ b/src/Fenom/Tag.php @@ -237,7 +237,7 @@ class Tag extends \ArrayObject */ public function cutContent() { - $content = substr($this->_body, $this->_offset + 1); + $content = substr($this->_body, $this->_offset); $this->_body = substr($this->_body, 0, $this->_offset); return $content; } diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index a83f4b2..137d730 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -788,38 +788,6 @@ class TemplateTest extends TestCase ); } - public static function providerSwitch() - { - $code1 = 'Switch: {switch $a} - {case 1, "one"} one - {case 2, "two"} two - {case "string", default} str - {default} def - {/switch} end'; - - $code2 = 'Switch: {switch $a} - {case 1, "one"} one - {case 2, "two"} two - {case "string"} str - {/switch} end'; - - $code3 = 'Switch: {switch $a} invalid - {case 1, "one"} one - {/switch} end'; - - return array( - array($code1, array("a" => 1), 'Switch: one end'), - array($code1, array("a" => 'one'), 'Switch: one end'), - array($code1, array("a" => 2), 'Switch: two end'), - array($code1, array("a" => 'two'), 'Switch: two end'), - array($code1, array("a" => "string"), 'Switch: str end'), - array($code1, array("a" => "unk"), 'Switch: str def end'), - array($code2, array("a" => "unk"), 'Switch: end'), - array($code3, array("a" => 1), 'Switch: one end'), - array($code3, array("a" => 'one'), 'Switch: one end'), - ); - } - public static function providerSwitchInvalid() { return array( @@ -1474,6 +1442,44 @@ class TemplateTest extends TestCase $this->exec($code, $vars, $result); } + + + public static function providerSwitch() + { + $code1 = 'Switch: {switch $a} + {case 1, "one"} one + {case 2, "two"} two + {case "string", default} str + {default} def + {/switch} end'; + + $code2 = 'Switch: {switch $a} + {case 1, "one"} one + {case 2, "two"} two + {case "string"} str + {/switch} end'; + + $code3 = 'Switch: {switch $a} invalid + {case 1, "one"} one + {/switch} end'; + + $code4 = 'Switch:{switch $a}{case 1}one{/switch}end'; + + return array( + array($code1, array("a" => 1), 'Switch: one end'), + array($code1, array("a" => 'one'), 'Switch: one end'), + array($code1, array("a" => 2), 'Switch: two end'), + array($code1, array("a" => 'two'), 'Switch: two end'), + array($code1, array("a" => "string"), 'Switch: str end'), + array($code1, array("a" => "unk"), 'Switch: str def end'), + array($code2, array("a" => "unk"), 'Switch: end'), + array($code3, array("a" => 1), 'Switch: one end'), + array($code3, array("a" => 'one'), 'Switch: one end'), + array($code4, array("a" => 1), 'Switch:oneend'), + ); + } + + /** * @group switch * @dataProvider providerSwitch From 23646edb6ea1050a17e31a666cad2510cd71eafb Mon Sep 17 00:00:00 2001 From: bzick Date: Fri, 18 Nov 2016 22:26:03 +0300 Subject: [PATCH 14/15] PHP 7.1 supports --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ecf5b40..451f648 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ php: - 5.5 - 5.6 - 7.0 + - 7.1 before_script: - composer update --dev From e97ef95ef52263e41a54a66366285ba10c8bdad5 Mon Sep 17 00:00:00 2001 From: bzick Date: Fri, 18 Nov 2016 22:30:44 +0300 Subject: [PATCH 15/15] CI: add --quiet mode for composer --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 451f648..bb7cc0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ php: - 7.1 before_script: - - composer update --dev + - composer update --dev --quiet script: - phpunit