From 4773d77611389a7afb7f366fa7eef5eab5cf8097 Mon Sep 17 00:00:00 2001 From: bzick Date: Sat, 28 Jun 2014 16:38:50 +0400 Subject: [PATCH 1/6] dev #83 --- src/Fenom/Compiler.php | 21 ++++++++++++++------- src/Fenom/Template.php | 16 ++++------------ tests/cases/Fenom/TemplateTest.php | 9 ++++++--- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Fenom/Compiler.php b/src/Fenom/Compiler.php index c81caef..026ab2b 100644 --- a/src/Fenom/Compiler.php +++ b/src/Fenom/Compiler.php @@ -138,13 +138,20 @@ class Compiler $key = null; $before = $body = array(); if ($tokens->is(T_VARIABLE)) { - $from = $scope->tpl->parseTerm($tokens); - $prepend = ""; + $from = $scope->tpl->parseTerm($tokens, $is_var); + if($is_var) { + $check = '!empty('.$from.')'; + $prepend = ""; + } else { + $scope["var"] = $scope->tpl->tmpVar(); + $prepend = $scope["var"].' = (array)('.$from.')'; + $from = $check = $scope["var"]; + } } elseif ($tokens->is('[')) { $from = $scope->tpl->parseArray($tokens); - $uid = '$v' . $scope->tpl->i++; - $prepend = $uid . ' = ' . $from . ';'; - $from = $uid; + $scope["var"] = $scope->tpl->tmpVar(); + $prepend = $scope["var"].' = (array)('.$from.')'; + $from = $check = $scope["var"]; } else { throw new UnexpectedTokenException($tokens, null, "tag {foreach}"); } @@ -189,9 +196,9 @@ class Compiler $body = $body ? implode("; ", $body) . ";" : ""; $scope["after"] = $scope["after"] ? implode("; ", $scope["after"]) . ";" : ""; if ($key) { - return "$prepend if($from) { $before foreach($from as $key => $value) { $body"; + return "$prepend if($check) { $before foreach($from as $key => $value) { $body"; } else { - return "$prepend if($from) { $before foreach($from as $value) { $body"; + return "$prepend if($check) { $before foreach($from as $value) { $body"; } } diff --git a/src/Fenom/Template.php b/src/Fenom/Template.php index a2aca54..a4dfa71 100644 --- a/src/Fenom/Template.php +++ b/src/Fenom/Template.php @@ -1263,10 +1263,11 @@ class Template extends Render * [1, 2.3, 5+7/$var, 'string', "str {$var+3} ing", $var2, []] * * @param Tokenizer $tokens - * @throws UnexpectedTokenException + * @param int $count amount of elements + * @throws Error\UnexpectedTokenException * @return string */ - public function parseArray(Tokenizer $tokens) + public function parseArray(Tokenizer $tokens, &$count = 0) { if ($tokens->is("[")) { $_arr = "array("; @@ -1277,16 +1278,7 @@ class Template extends Render $key = true; $val = false; $_arr .= $tokens->getAndNext() . ' '; - } elseif ($tokens->is( - Tokenizer::MACRO_SCALAR, - T_VARIABLE, - T_STRING, - T_EMPTY, - T_ISSET, - "(", - "#" - ) && !$val - ) { + } elseif ($tokens->is(Tokenizer::MACRO_SCALAR, T_VARIABLE, T_STRING, T_EMPTY, T_ISSET, "(") && !$val) { $_arr .= $this->parseExpr($tokens); $key = false; $val = true; diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index b9ff1d2..8d36ea5 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -1267,12 +1267,15 @@ class TemplateTest extends TestCase ); } - public function _testSandbox() + /** + * @group sb + */ + public function testSandbox() { try { var_dump( - $this->fenom->setOptions(0)->compileCode( - "{autoescape true}{test_block_function:raw}{\$html}{/test_block_function}{/autoescape}" + $this->fenom->compileCode( + '{var $a = [3, 5,6]}' )->getBody() ); } catch (\Exception $e) { From 6b8ddd4ecccb4401f25aefd5cf95d640fe647f47 Mon Sep 17 00:00:00 2001 From: bzick Date: Sat, 28 Jun 2014 21:08:20 +0400 Subject: [PATCH 2/6] Done #83 --- src/Fenom/Compiler.php | 15 +++++----- src/Fenom/Template.php | 45 ++++++++++++---------------- tests/cases/Fenom/TemplateTest.php | 48 ++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 36 deletions(-) diff --git a/src/Fenom/Compiler.php b/src/Fenom/Compiler.php index 026ab2b..b4d46d5 100644 --- a/src/Fenom/Compiler.php +++ b/src/Fenom/Compiler.php @@ -134,24 +134,23 @@ class Compiler */ public static function foreachOpen(Tokenizer $tokens, Tag $scope) { - $p = array("index" => false, "first" => false, "last" => false); - $key = null; - $before = $body = array(); + $p = array("index" => false, "first" => false, "last" => false); + $key = null; + $before = $body = array(); + $prepend = ""; if ($tokens->is(T_VARIABLE)) { $from = $scope->tpl->parseTerm($tokens, $is_var); if($is_var) { $check = '!empty('.$from.')'; - $prepend = ""; } else { $scope["var"] = $scope->tpl->tmpVar(); $prepend = $scope["var"].' = (array)('.$from.')'; $from = $check = $scope["var"]; } } elseif ($tokens->is('[')) { - $from = $scope->tpl->parseArray($tokens); - $scope["var"] = $scope->tpl->tmpVar(); - $prepend = $scope["var"].' = (array)('.$from.')'; - $from = $check = $scope["var"]; + $count = 0; + $from = $scope->tpl->parseArray($tokens, $count); + $check = $count; } else { throw new UnexpectedTokenException($tokens, null, "tag {foreach}"); } diff --git a/src/Fenom/Template.php b/src/Fenom/Template.php index d869345..d2d6136 100644 --- a/src/Fenom/Template.php +++ b/src/Fenom/Template.php @@ -133,7 +133,7 @@ class Template extends Render /** * @param string $tag - * @return bool|\Fenom\Scope + * @return bool|\Fenom\Tag */ public function getParentScope($tag) { @@ -1281,35 +1281,28 @@ class Template extends Render public function parseArray(Tokenizer $tokens, &$count = 0) { if ($tokens->is("[")) { - $_arr = "array("; - $key = $val = false; + $arr = array(); $tokens->next(); while ($tokens->valid()) { - if ($tokens->is(',') && $val) { - $key = true; - $val = false; - $_arr .= $tokens->getAndNext() . ' '; - } elseif ($tokens->is(Tokenizer::MACRO_SCALAR, T_VARIABLE, T_STRING, T_EMPTY, T_ISSET, "(") && !$val) { - $_arr .= $this->parseExpr($tokens); - $key = false; - $val = true; - } elseif ($tokens->is('"') && !$val) { - $_arr .= $this->parseQuote($tokens); - $key = false; - $val = true; - } elseif ($tokens->is(T_DOUBLE_ARROW) && $val) { - $_arr .= ' ' . $tokens->getAndNext() . ' '; - $key = true; - $val = false; - } elseif (!$val && $tokens->is('[')) { - $_arr .= $this->parseArray($tokens); - $key = false; - $val = true; - } elseif ($tokens->is(']') && (!$key || $tokens->prev[0] === ',')) { + if ($tokens->is(']')) { $tokens->next(); - return $_arr . ')'; + return 'array(' . implode(', ', $arr) . ')'; + } + if ($tokens->is('[')) { + $arr[] = $this->parseArray($tokens); + $count++; } else { - break; + $expr = $this->parseExpr($tokens); + if($tokens->is(T_DOUBLE_ARROW)) { + $tokens->next(); + $arr[] = $expr.' => '.$this->parseExpr($tokens); + } else { + $arr[] = $expr; + } + $count++; + } + if($tokens->is(',')) { + $tokens->next(); } } } diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 7ce5f71..6bcca5e 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -572,6 +572,30 @@ class TemplateTest extends TestCase ); } + public static function providerArrays() + { + return array( + array('{var $arr = []}', array()), + array('{var $arr = [1]}', array(1)), + array('{var $arr = [1,]}', array(1)), + array('{var $arr = [1, 2, 3, 5]}', array(1, 2, 3, 5)), + array('{var $arr = [1, true, false, null, -1, 1.1, -2.2, 5, "str"]}', array(1, true, false, null, -1, 1.1, -2.2, 5, "str")), + array('{var $arr = [5 => 1, "two" => 2, 3]}', array(5 => 1, "two" => 2, 3)), + array('{var $arr = [1 + 1, 2 * 2, 3 / 3 + 7,]}', array(1 + 1, 2 * 2, 3 / 3 + 7)), + array('{var $arr = [$zero, $two => $one, $num.3 => $.const.PHP_VERSION]}', array(0, 2 => 1, "three" => PHP_VERSION)), + array('{var $arr = [5 - 1 => 1, "two"|up => "two"|low, 3 => count([1,2])]}', array(4 => 1, "TWO" => "two", 3 => 2)), + + array('{var $arr = [[1]]}', array(array(1))), + array('{var $arr = [[],[]]}', array(array(),array())), + array('{var $arr = [1, [2, 3], 5]}', array(1, array(2, 3), 5)), + array('{var $arr = [1, [true, false, null, -1, 1.1, -2.2, 5], "str"]}', array(1, array(true, false, null, -1, 1.1, -2.2, 5), "str")), + array('{var $arr = [5 => [1, "two" => 2], 3]}', array(5 => array(1, "two" => 2), 3)), + array('{var $arr = [1 + 1, [2 * 2, 3 / 3 + 7,],]}', array(1 + 1, array(2 * 2, 3 / 3 + 7))), + array('{var $arr = [$zero, [$two => $one, $num.3 => $.const.PHP_VERSION]]}', array(0, array(2 => 1, "three" => PHP_VERSION))), + array('{var $arr = [5 - 1 => 1, ["two"|up => ("two"|low ~ "..."), 3 => count([1,2])]]}', array(4 => 1, array("TWO" => "two...", 3 => 2))), + ); + } + public static function providerTernary() { $a = array( @@ -683,6 +707,7 @@ class TemplateTest extends TestCase ), array('Foreach: {foreach $empty as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'), array('Foreach: {foreach [] as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'), + array('Foreach: {foreach $unexists as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'), array( 'Foreach: {foreach $empty as $k => $e} {$k} => {$e}, {foreachelse} empty {/foreach} end', $a, @@ -1276,14 +1301,14 @@ class TemplateTest extends TestCase try { var_dump( $this->fenom->compileCode( - '{var $a = [3, 5,6]}' + '{foreach $fff as $k}{/foreach}' )->getBody() ); } catch (\Exception $e) { print_r($e->getMessage() . "\n" . $e->getTraceAsString()); while ($e->getPrevious()) { $e = $e->getPrevious(); - print_r("\n\n" . $e->getMessage() . "\n" . $e->getTraceAsString()); + print_r("\n\n" . $e->getMessage() . " in {$e->getFile()}:{$e->getLine()}\n" . $e->getTraceAsString()); } } exit; @@ -1419,6 +1444,25 @@ class TemplateTest extends TestCase $this->execError($code, $exception, $message, $options); } + /** + * @dataProvider providerArrays + * @group arrays + */ + public function testArrays($code, $vars) + { + $v = $this->getVars(); + $v['vars'] = $vars; + $this->exec($code.'{if $arr === $vars}equal{/if}', $v, 'equal'); + } + + /** + * @dataProvider providerCreateVarInvalid + */ +// public function testCreateVarInvalid($code, $exception, $message, $options = 0) +// { +// $this->execError($code, $exception, $message, $options); +// } + /** * @group ternary * @dataProvider providerTernary From c56623c1a4969f5625cb4f25810e7f53360886c4 Mon Sep 17 00:00:00 2001 From: bzick Date: Sat, 28 Jun 2014 22:15:30 +0400 Subject: [PATCH 3/6] Done #80 --- src/Fenom.php | 4 ++++ src/Fenom/Compiler.php | 15 +++++++++++++++ tests/cases/Fenom/TemplateTest.php | 21 +++++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/Fenom.php b/src/Fenom.php index 2663475..157b762 100644 --- a/src/Fenom.php +++ b/src/Fenom.php @@ -282,6 +282,10 @@ class Fenom 'type' => self::BLOCK_COMPILER, 'open' => 'Fenom\Compiler::ignoreOpen', 'close' => 'Fenom\Compiler::nope' + ), + 'unset' => array( + 'type' => self::INLINE_COMPILER, + 'parser' => 'Fenom\Compiler::tagUnset' ) ); diff --git a/src/Fenom/Compiler.php b/src/Fenom/Compiler.php index b4d46d5..b4da156 100644 --- a/src/Fenom/Compiler.php +++ b/src/Fenom/Compiler.php @@ -1007,4 +1007,19 @@ class Compiler { $tag->tpl->ignore('ignore'); } + + /** + * Tag {unset ...} + * @param Tokenizer $tokens + * @param Tag $tag + * @return string + */ + public static function tagUnset(Tokenizer $tokens, Tag $tag) + { + $unset = []; + while($tokens->valid()) { + $unset[] = $tag->tpl->parseVariable($tokens); + } + return 'unset('.implode(", ", $unset).')'; + } } diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 6bcca5e..4607d90 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -596,6 +596,14 @@ class TemplateTest extends TestCase ); } + public static function providerUnset() { + return array( + array('{var $a = 5} {unset $a} {if $a is not set}not set{/if}', 'not set'), + array('{var $a = ["b" => 5, "c" => 6]} {unset $a.b} {if $a.b is not set}not set{/if} but c is {$a.c}', 'not set but c is 6'), + array('{var $a = ["b" => 5, "c" => 6]} {unset $a.b $a.c} {if $a.b is not set}not set{/if} {if $a.c is not set}not set{/if}', 'not set not set'), + ); + } + public static function providerTernary() { $a = array( @@ -1296,12 +1304,12 @@ class TemplateTest extends TestCase /** * @group sb */ - public function testSandbox() + public function _testSandbox() { try { var_dump( $this->fenom->compileCode( - '{foreach $fff as $k}{/foreach}' + '{unset $a $a.c $b}' )->getBody() ); } catch (\Exception $e) { @@ -1455,6 +1463,15 @@ class TemplateTest extends TestCase $this->exec($code.'{if $arr === $vars}equal{/if}', $v, 'equal'); } + /** + * @dataProvider providerUnset + * @group unset + */ + public function testUnset($code, $result) + { + $this->exec($code, $this->getVars(), $result); + } + /** * @dataProvider providerCreateVarInvalid */ From 70d3b47ca29e6cecd58480b75d0bda108e6c6997 Mon Sep 17 00:00:00 2001 From: bzick Date: Sat, 28 Jun 2014 22:17:52 +0400 Subject: [PATCH 4/6] Doc for #80 --- docs/readme.md | 1 + docs/tags/unset.md | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 docs/tags/unset.md diff --git a/docs/readme.md b/docs/readme.md index 8486459..26556f8 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -32,6 +32,7 @@ Documentation * [macro](./tags/macro.md) and `import` — template functions * [autoescape](./tags/autoescape.md) — escape template fragment * [raw](./tags/raw.md) — unescape template fragment +* [unset](./tags/unset.md) — unset a given variables * or [add](./ext/extend.md#add-tags) yours diff --git a/docs/tags/unset.md b/docs/tags/unset.md new file mode 100644 index 0000000..2d3a065 --- /dev/null +++ b/docs/tags/unset.md @@ -0,0 +1,12 @@ +Tag {unset} +=========== + +Unset a given variables. + +```smarty + +{unset $a} unset single variable + +{unset $a $b $c.d.e} multiple unset + +``` \ No newline at end of file From 7c557e87172896abf3a6dddcb7272c1f37e80bf9 Mon Sep 17 00:00:00 2001 From: Ivan Shalganov Date: Sat, 28 Jun 2014 23:49:06 +0400 Subject: [PATCH 5/6] Update extend.md --- docs/ext/extend.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/ext/extend.md b/docs/ext/extend.md index 5db18b3..14a86f5 100644 --- a/docs/ext/extend.md +++ b/docs/ext/extend.md @@ -119,6 +119,7 @@ $fenom->addModifier('my_modifier', function ($variable, $param1, $param2) { ```php $fenom->addTest($name, $code); ?> +``` # Add template provider @@ -160,4 +161,4 @@ $this->setCacheDir("redis://hash/compiled/"); * `$cache = fopen("redis://hash/compiled/XnsbfeDnrd.php", "w");` * `fwrite($cache, "...