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
diff --git a/.travis.yml b/.travis.yml
index ecf5b40..bb7cc0c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,9 +8,10 @@ php:
- 5.5
- 5.6
- 7.0
+ - 7.1
before_script:
- - composer update --dev
+ - composer update --dev --quiet
script:
- phpunit
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`
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
+```
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)
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` — предопределенный парсер.
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 символов.
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'}
diff --git a/sandbox/fenom.php b/sandbox/fenom.php
index 3f3c9fd..e4709c9 100644
--- a/sandbox/fenom.php
+++ b/sandbox/fenom.php
@@ -5,9 +5,12 @@ 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 | Fenom::FORCE_INCLUDE);
+//var_dump($fenom->compile("nested.tpl", [])->getTemplateCode());
+//exit;
+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");
\ No newline at end of file
+// $fenom->getTemplate("problem.tpl");
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/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
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.php b/src/Fenom.php
index 6e15d1d..d779731 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
@@ -939,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);
}
/**
@@ -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/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/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/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/src/Fenom/Template.php b/src/Fenom/Template.php
index 097b7b6..b6912c7 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.
*/
@@ -75,11 +81,18 @@ class Template extends Render
public $extend_body = false;
+ /**
+ * Parent template
+ * @var Template
+ */
+ public $parent;
+
/**
* Template PHP code
* @var string
*/
private $_body;
+ private $_compile_stage = 0;
/**
* Call stack
@@ -114,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();
@@ -166,6 +180,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 +211,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 +282,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 +301,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 +374,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 +400,8 @@ class Template extends Render
/**
* @param $tag_name
*/
- public function ignore($tag_name) {
+ public function ignore($tag_name)
+ {
$this->_ignore = $tag_name;
}
@@ -490,7 +515,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 +544,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 +663,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 +702,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 +734,7 @@ class Template extends Render
break;
}
$op = $tokens->getAndNext();
- if($op == '[') {
+ if ($op == '[') {
$tokens->need(']')->next()->need('=')->next();
$op = '[]=';
}
@@ -742,7 +769,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 +789,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 +812,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 +828,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 +843,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 +880,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 +917,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 +934,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 +958,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 +983,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 +991,7 @@ class Template extends Render
}
$var .= $key;
} elseif ($t === "[") {
- if($tokens->isNext(']')) {
+ if ($tokens->isNext(']')) {
break;
}
$tokens->next();
@@ -1001,16 +1029,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 +1400,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/TestCase.php b/tests/TestCase.php
index 9ce1c7a..55dcf59 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/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/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php
index 31247d3..137d730 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()
{
@@ -830,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(
@@ -1129,27 +1055,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
*/
@@ -1216,12 +1121,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);
}
@@ -1427,6 +1386,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,
@@ -1478,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
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()