mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Merge remote-tracking branch 'refs/remotes/origin/develop'
This commit is contained in:
commit
7a84cf4ceb
22
CHANGELOG.md
22
CHANGELOG.md
@ -1,10 +1,21 @@
|
||||
CHANGELOG
|
||||
Changelog
|
||||
=========
|
||||
|
||||
## 1.3.1 (2013-08-29)
|
||||
## 1.4.0
|
||||
|
||||
- Bug: accessor don't work in modifier
|
||||
- Removed too many EOL in template code
|
||||
- Redesign tag {switch}
|
||||
- Add tag {insert}
|
||||
- Add variable verification before using (option `Fenom::FORCE_VERIFY`)
|
||||
- Improve internal parsers
|
||||
- Fix #45: intersection of names of tmp vars
|
||||
- Fix #44: invalid `_depend` format in template
|
||||
- Docs++
|
||||
- Tests++
|
||||
|
||||
### 1.3.1 (2013-08-29)
|
||||
|
||||
- Fix: accessor don't work in modifier
|
||||
- Removed too many EOLs in template code
|
||||
- Tests++
|
||||
|
||||
## 1.3.0 (2013-08-23)
|
||||
@ -15,7 +26,7 @@ CHANGELOG
|
||||
- Recognize macros parser
|
||||
- Fix `auto_reload` option
|
||||
- Tests++
|
||||
- Docs--
|
||||
- Docs++
|
||||
|
||||
### 1.2.2 (2013-08-07)
|
||||
|
||||
@ -30,7 +41,6 @@ CHANGELOG
|
||||
- Feature #28: macros may be called recursively
|
||||
- Feature #29: add {unset} tag
|
||||
- Add hook for loading modifiers and tags
|
||||
- Add hook for loading modifiers and tags
|
||||
- Feature #3: Add string operator '~'
|
||||
- Improve parsers: parserExp, parserVar, parserVariable, parserMacro
|
||||
- Fix ternary bug
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
require_once __DIR__.'/../../vendor/autoload.php';
|
||||
|
||||
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled', Fenom::FORCE_COMPILE);
|
||||
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled', 0);
|
||||
|
||||
$fenom->display("greeting.tpl", array(
|
||||
"user" => array(
|
||||
"name" => "Ivka"
|
||||
)
|
||||
"name" => "Ivka",
|
||||
'type' => 'new'
|
||||
),
|
||||
'type' => 'new'
|
||||
));
|
@ -1,8 +1,5 @@
|
||||
Greeting,
|
||||
{if $user}
|
||||
{$user.name}!
|
||||
{else}
|
||||
anonymous?
|
||||
{/if}
|
||||
{import 'macros.tpl' as mc}
|
||||
|
||||
3
|
||||
A1
|
||||
{mc.factorial num=10}
|
||||
A2
|
5
benchmark/sandbox/templates/macros.tpl
Normal file
5
benchmark/sandbox/templates/macros.tpl
Normal file
@ -0,0 +1,5 @@
|
||||
{macro factorial(num)}
|
||||
{if $num}
|
||||
{$num} {macro.factorial num=$num-1} {$num}
|
||||
{/if}
|
||||
{/macro}
|
@ -131,11 +131,11 @@ Tests can be negated by using the `not in` operator.
|
||||
|
||||
* `$a in $b` - variable `$a` contains in `$b`, $b may be string, plain or assoc array.
|
||||
* `$a in list $b` - variable `$a` contains in array `$b` as value
|
||||
* `$a in keys $b` - variable `$a` contains in array `$b` as key
|
||||
* `$a in keys $b` - array `$b` contain key `$a`
|
||||
* `$a in string $b` - variable `$a` contains in string `$b` as substring
|
||||
|
||||
```smarty
|
||||
{'df' in 'abcdefg'}
|
||||
{5 in [1, 5, 25, 125]}
|
||||
{2 in keys [1, 5, 25, 125]}
|
||||
{99 in keys [1, 5, 25, 99 => 125]}
|
||||
```
|
@ -42,9 +42,9 @@ Documentation
|
||||
* [if](./tags/if.md), `elseif` and `else`
|
||||
* [foreach](./tags/foreach.md), `foreaelse`, `break` and `continue`
|
||||
* [for](./tags/for.md), `forelse`, `break` and `continue`
|
||||
* [switch](./tags/switch.md), `case`, `default` and `break`
|
||||
* [switch](./tags/switch.md), `case`, `default`
|
||||
* [cycle](./tags/cycle.md)
|
||||
* [include](./tags/include.md)
|
||||
* [include](./tags/include.md), `insert`
|
||||
* [extends](./tags/extends.md), `use`, `block` and `parent`
|
||||
* [filter](./tags/filter.md)
|
||||
* [ignore](./tags/ignore.md)
|
||||
|
@ -13,4 +13,33 @@ Tag {include} [RU]
|
||||
{include "about.tpl" page=$item limit=50}
|
||||
```
|
||||
|
||||
Все изменения переменных в подключаемом шаблоне не будут воздействовать на родительский шаблон.
|
||||
Все изменения переменных в подключаемом шаблоне не будут воздействовать на родительский шаблон.
|
||||
|
||||
### {insert}
|
||||
|
||||
The tag insert template code instead self.
|
||||
|
||||
* No dynamic name allowed
|
||||
* No variables as attribute allowed
|
||||
|
||||
For example, main.tpl:
|
||||
|
||||
```smarty
|
||||
a: {$a}
|
||||
{insert 'b.tpl'}
|
||||
c: {$c}
|
||||
```
|
||||
|
||||
b.tpl:
|
||||
|
||||
```
|
||||
b: {$b}
|
||||
```
|
||||
|
||||
Во время разбора шаблона код шаблона `b.tpl` будет вставлен в код шаблона `main.tpl` как есть:
|
||||
|
||||
```smarty
|
||||
a: {$a}
|
||||
b: {$b}
|
||||
c: {$c}
|
||||
```
|
||||
|
@ -5,9 +5,36 @@ Tag {switch}
|
||||
{switch <condition>}
|
||||
{case <value1>}
|
||||
...
|
||||
{case <value2>}
|
||||
{case <value2>, <value3>, ...}
|
||||
...
|
||||
{case <value3>}
|
||||
...
|
||||
{default}
|
||||
...
|
||||
{/switch}
|
||||
```
|
||||
|
||||
For example,
|
||||
|
||||
```smarty
|
||||
{switch $type}
|
||||
{case 'new'}
|
||||
It is new item
|
||||
{case 'current', 'new'}
|
||||
It is new or current item
|
||||
{case 'current'}
|
||||
It is current item
|
||||
{case 'new'}
|
||||
It is new item, again
|
||||
{default}
|
||||
I don't know the type {$type}
|
||||
{/switch}
|
||||
```
|
||||
|
||||
set `$type = 'new'`, then template output
|
||||
|
||||
```
|
||||
It is new item
|
||||
It is new or current item
|
||||
It is new item, again
|
||||
```
|
@ -157,17 +157,16 @@ class Fenom
|
||||
'close' => 'Fenom\Compiler::stdClose',
|
||||
'tags' => array(
|
||||
'elseif' => 'Fenom\Compiler::tagElseIf',
|
||||
'else' => 'Fenom\Compiler::tagElse',
|
||||
'else' => 'Fenom\Compiler::tagElse'
|
||||
)
|
||||
),
|
||||
'switch' => array( // {switch ...} {case ...} {break} {default} {/switch}
|
||||
'switch' => array( // {switch ...} {case ..., ...} {default} {/switch}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::switchOpen',
|
||||
'close' => 'Fenom\Compiler::stdClose',
|
||||
'close' => 'Fenom\Compiler::switchClose',
|
||||
'tags' => array(
|
||||
'case' => 'Fenom\Compiler::tagCase',
|
||||
'default' => 'Fenom\Compiler::tagDefault',
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'default' => 'Fenom\Compiler::tagDefault'
|
||||
),
|
||||
'float_tags' => array('break' => 1)
|
||||
),
|
||||
@ -196,6 +195,10 @@ class Fenom
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => 'Fenom\Compiler::tagInclude'
|
||||
),
|
||||
'insert' => array( // {include ...}
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => 'Fenom\Compiler::tagInsert'
|
||||
),
|
||||
'var' => array( // {var ...}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::varOpen',
|
||||
@ -205,8 +208,7 @@ class Fenom
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::tagBlockOpen',
|
||||
'close' => 'Fenom\Compiler::tagBlockClose',
|
||||
'tags' => array(
|
||||
'parent' => 'Fenom\Compiler::tagParent'
|
||||
'tags' => array(// 'parent' => 'Fenom\Compiler::tagParent' // not implemented yet
|
||||
),
|
||||
'float_tags' => array('parent' => 1)
|
||||
),
|
||||
@ -608,15 +610,18 @@ class Fenom
|
||||
*
|
||||
* @param string $scm scheme name
|
||||
* @param Fenom\ProviderInterface $provider provider object
|
||||
* @return $this
|
||||
*/
|
||||
public function addProvider($scm, \Fenom\ProviderInterface $provider)
|
||||
{
|
||||
$this->_providers[$scm] = $provider;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options
|
||||
* @param int|array $options
|
||||
* @return $this
|
||||
*/
|
||||
public function setOptions($options)
|
||||
{
|
||||
@ -625,6 +630,7 @@ class Fenom
|
||||
}
|
||||
$this->_storage = array();
|
||||
$this->_options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -758,10 +764,11 @@ class Fenom
|
||||
{
|
||||
$file_name = $this->_getCacheName($tpl, $opts);
|
||||
if (is_file($this->_compile_dir . "/" . $file_name)) {
|
||||
$fenom = $this;
|
||||
$fenom = $this; // used in template
|
||||
$_tpl = include($this->_compile_dir . "/" . $file_name);
|
||||
/* @var Fenom\Render $tpl */
|
||||
if($_tpl->isValid()) {
|
||||
/* @var Fenom\Render $_tpl */
|
||||
// var_dump($tpl, $_tpl->isValid()); exit;
|
||||
if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD) && $_tpl->isValid()) {
|
||||
return $_tpl;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ class Compiler
|
||||
$cname = $tpl->parsePlainArg($tokens, $name);
|
||||
$p = $tpl->parseParams($tokens);
|
||||
if ($p) { // if we have additionally variables
|
||||
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { // if FORCE_INCLUDE enabled and template name known
|
||||
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) {
|
||||
$inc = $tpl->getStorage()->compile($name, false);
|
||||
$tpl->addDepend($inc);
|
||||
return '$_tpl = (array)$tpl; $tpl->exchangeArray(' . self::toArray($p) . '+$_tpl); ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
||||
@ -44,7 +44,7 @@ class Compiler
|
||||
return '$tpl->getStorage()->getTemplate(' . $cname . ')->display(' . self::toArray($p) . '+(array)$tpl);';
|
||||
}
|
||||
} else {
|
||||
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { // if FORCE_INCLUDE enabled and template name known
|
||||
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) {
|
||||
$inc = $tpl->getStorage()->compile($name, false);
|
||||
$tpl->addDepend($inc);
|
||||
return '$_tpl = (array)$tpl; ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
||||
@ -54,6 +54,24 @@ class Compiler
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag {insert ...}
|
||||
* @param Tokenizer $tokens
|
||||
* @param Template $tpl
|
||||
* @return string
|
||||
* @throws Error\InvalidUsageException
|
||||
*/
|
||||
public static function tagInsert(Tokenizer $tokens, Template $tpl)
|
||||
{
|
||||
$tpl->parsePlainArg($tokens, $name);
|
||||
if (!$name) {
|
||||
throw new InvalidUsageException("Tag {insert} accept only static template name");
|
||||
}
|
||||
$inc = $tpl->getStorage()->compile($name, false);
|
||||
$tpl->addDepend($inc);
|
||||
return '?>' . $tpl->getBody() . '<?php';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open tag {if ...}
|
||||
@ -117,7 +135,7 @@ class Compiler
|
||||
$key = null;
|
||||
$before = $body = array();
|
||||
if ($tokens->is(T_VARIABLE)) {
|
||||
$from = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
||||
$from = $scope->tpl->parseTerm($tokens);
|
||||
$prepend = "";
|
||||
} elseif ($tokens->is('[')) {
|
||||
$from = $scope->tpl->parseArray($tokens);
|
||||
@ -129,11 +147,11 @@ class Compiler
|
||||
}
|
||||
$tokens->get(T_AS);
|
||||
$tokens->next();
|
||||
$value = $scope->tpl->parseVar($tokens);
|
||||
$value = $scope->tpl->parseVariable($tokens);
|
||||
if ($tokens->is(T_DOUBLE_ARROW)) {
|
||||
$tokens->next();
|
||||
$key = $value;
|
||||
$value = $scope->tpl->parseVar($tokens);
|
||||
$value = $scope->tpl->parseVariable($tokens);
|
||||
}
|
||||
|
||||
$scope["after"] = array();
|
||||
@ -146,7 +164,7 @@ class Compiler
|
||||
}
|
||||
$tokens->getNext("=");
|
||||
$tokens->next();
|
||||
$p[$param] = $scope->tpl->parseVar($tokens);
|
||||
$p[$param] = $scope->tpl->parseVariable($tokens);
|
||||
}
|
||||
|
||||
if ($p["index"]) {
|
||||
@ -208,8 +226,9 @@ class Compiler
|
||||
* @static
|
||||
* @param Tokenizer $tokens
|
||||
* @param Scope $scope
|
||||
* @throws Error\UnexpectedTokenException
|
||||
* @throws Error\InvalidUsageException
|
||||
* @return string
|
||||
* @throws InvalidUsageException
|
||||
*/
|
||||
public static function forOpen(Tokenizer $tokens, Scope $scope)
|
||||
{
|
||||
@ -217,7 +236,10 @@ class Compiler
|
||||
$scope["after"] = $before = $body = array();
|
||||
$i = array('', '');
|
||||
$c = "";
|
||||
$var = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
||||
$var = $scope->tpl->parseTerm($tokens, $is_var);
|
||||
if (!$is_var) {
|
||||
throw new UnexpectedTokenException($tokens);
|
||||
}
|
||||
$tokens->get("=");
|
||||
$tokens->next();
|
||||
$val = $scope->tpl->parseExpr($tokens);
|
||||
@ -310,12 +332,34 @@ class Compiler
|
||||
*/
|
||||
public static function switchOpen(Tokenizer $tokens, Scope $scope)
|
||||
{
|
||||
$scope["no-break"] = $scope["no-continue"] = true;
|
||||
$scope["switch"] = 'switch(' . $scope->tpl->parseExpr($tokens) . ') {';
|
||||
$scope["expr"] = $scope->tpl->parseExpr($tokens);
|
||||
$scope["case"] = array();
|
||||
$scope["last"] = array();
|
||||
$scope["default"] = '';
|
||||
// lazy init
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resort cases for {switch}
|
||||
* @param Scope $scope
|
||||
*/
|
||||
private static function _caseResort(Scope $scope)
|
||||
{
|
||||
$content = $scope->cutContent();
|
||||
if ($scope["last"] === false) {
|
||||
$scope["default"] .= $content;
|
||||
} else {
|
||||
foreach ($scope["last"] as $case) {
|
||||
if (!isset($scope["case"][$case])) {
|
||||
$scope["case"][$case] = "";
|
||||
}
|
||||
$scope["case"][$case] .= $content;
|
||||
}
|
||||
}
|
||||
$scope["last"] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag {case ...}
|
||||
*
|
||||
@ -326,12 +370,52 @@ class Compiler
|
||||
*/
|
||||
public static function tagCase(Tokenizer $tokens, Scope $scope)
|
||||
{
|
||||
$code = 'case ' . $scope->tpl->parseExpr($tokens) . ': ';
|
||||
if ($scope["switch"]) {
|
||||
unset($scope["no-break"], $scope["no-continue"]);
|
||||
$code = $scope["switch"] . "\n" . $code;
|
||||
$scope["switch"] = "";
|
||||
self::_caseResort($scope);
|
||||
do {
|
||||
$scope["last"][] = $scope->tpl->parseScalar($tokens, false);
|
||||
if ($tokens->is(',')) {
|
||||
$tokens->next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tag {default}
|
||||
*
|
||||
* @static
|
||||
* @param Tokenizer $tokens
|
||||
* @param Scope $scope
|
||||
* @return string
|
||||
*/
|
||||
public static function tagDefault($tokens, Scope $scope)
|
||||
{
|
||||
self::_caseResort($scope);
|
||||
$scope["last"] = false;
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Close tag {switch}
|
||||
*
|
||||
* @static
|
||||
* @param Tokenizer $tokens
|
||||
* @param Scope $scope
|
||||
* @return string
|
||||
*/
|
||||
public static function switchClose(Tokenizer $tokens, Scope $scope)
|
||||
{
|
||||
self::_caseResort($scope);
|
||||
$expr = $scope["expr"];
|
||||
$code = "";
|
||||
$default = $scope["default"];
|
||||
foreach ($scope["case"] as $case => $content) {
|
||||
$code .= "if($expr == $case) {\n?>$content<?php\n} else";
|
||||
}
|
||||
$code .= " {\n?>$default<?php\n}";
|
||||
return $code;
|
||||
}
|
||||
|
||||
@ -353,25 +437,6 @@ class Compiler
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag {default}
|
||||
*
|
||||
* @static
|
||||
* @param Tokenizer $tokens
|
||||
* @param Scope $scope
|
||||
* @return string
|
||||
*/
|
||||
public static function tagDefault($tokens, Scope $scope)
|
||||
{
|
||||
$code = 'default: ';
|
||||
if ($scope["switch"]) {
|
||||
unset($scope["no-break"], $scope["no-continue"]);
|
||||
$code = $scope["switch"] . "\n" . $code;
|
||||
$scope["switch"] = "";
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag {break}
|
||||
*
|
||||
@ -698,7 +763,7 @@ class Compiler
|
||||
*/
|
||||
public static function varOpen(Tokenizer $tokens, Scope $scope)
|
||||
{
|
||||
$var = $scope->tpl->parseVar($tokens);
|
||||
$var = $scope->tpl->parseVariable($tokens);
|
||||
if ($tokens->is('=')) { // inline tag {var ...}
|
||||
$scope->is_closed = true;
|
||||
$tokens->next();
|
||||
@ -975,7 +1040,7 @@ class Compiler
|
||||
{
|
||||
$vars = array();
|
||||
while ($tokens->valid()) {
|
||||
$vars[] = $tpl->parseVar($tokens);
|
||||
$vars[] = $tpl->parseVariable($tokens);
|
||||
}
|
||||
if (!$vars) {
|
||||
throw new InvalidUsageException("Unset must accept variable(s)");
|
||||
|
@ -175,7 +175,7 @@ class Render extends \ArrayObject
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
if (count($this->_depends) === 1) { // if no external dependencies, only self
|
||||
if (count($this->_depends[0]) === 1) { // if no external dependencies, only self
|
||||
$provider = $this->_fenom->getProvider($this->_scm);
|
||||
if ($provider->getLastModified($this->_name) !== $this->_time) {
|
||||
return false;
|
||||
@ -198,7 +198,7 @@ class Render extends \ArrayObject
|
||||
*/
|
||||
public function getMacro($name)
|
||||
{
|
||||
if(empty($this->_macros[$name])) {
|
||||
if (empty($this->_macros[$name])) {
|
||||
throw new RuntimeException('macro not found');
|
||||
}
|
||||
return $this->_macros[$name];
|
||||
@ -247,7 +247,7 @@ class Render extends \ArrayObject
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
if($name == 'info') {
|
||||
if ($name == 'info') {
|
||||
return array(
|
||||
'name' => $this->_name,
|
||||
'schema' => $this->_scm,
|
||||
|
@ -223,10 +223,6 @@ class Template extends Render
|
||||
unset($comment); // cleanup
|
||||
break;
|
||||
default:
|
||||
// var_dump($this->_src[$pos]);
|
||||
// if($this->_src[$pos] === "\n") {
|
||||
// $pos++;
|
||||
// }
|
||||
$this->_appendText(substr($this->_src, $pos, $start - $pos));
|
||||
$end = $start + 1;
|
||||
do {
|
||||
@ -388,7 +384,7 @@ class Template extends Render
|
||||
"\t'name' => " . var_export($this->_name, true) . ",\n" .
|
||||
"\t'base_name' => " . var_export($this->_base_name, true) . ",\n" .
|
||||
"\t'time' => {$this->_time},\n" .
|
||||
"\t'depends' => " . var_export($this->_base_name, true) . ",\n" .
|
||||
"\t'depends' => " . var_export($this->_depends, true) . ",\n" .
|
||||
"\t'macros' => " . $this->_getMacrosArray() . ",\n
|
||||
));\n";
|
||||
}
|
||||
@ -406,7 +402,7 @@ class Template extends Render
|
||||
$macros[] = "\t\t'" . $m["name"] . "' => function (\$tpl) {\n?>" . $m["body"] . "<?php\n}";
|
||||
}
|
||||
}
|
||||
return "array(\n" . implode(",\n", $macros).")";
|
||||
return "array(\n" . implode(",\n", $macros) . ")";
|
||||
} else {
|
||||
return 'array()';
|
||||
}
|
||||
@ -432,7 +428,7 @@ class Template extends Render
|
||||
{
|
||||
if (!$this->_code) {
|
||||
// evaluate template's code
|
||||
eval("\$this->_code = " . $this->_getClosureSource() . ";\n\$this->_macros = ".$this->_getMacrosArray() .';');
|
||||
eval("\$this->_code = " . $this->_getClosureSource() . ";\n\$this->_macros = " . $this->_getMacrosArray() . ';');
|
||||
if (!$this->_code) {
|
||||
throw new CompileException("Fatal error while creating the template");
|
||||
}
|
||||
@ -447,7 +443,6 @@ class Template extends Render
|
||||
*/
|
||||
public function addDepend(Render $tpl)
|
||||
{
|
||||
// var_dump($tpl->getScm(),"$tpl", (new \Exception())->getTraceAsString() );
|
||||
$this->_depends[$tpl->getScm()][$tpl->getName()] = $tpl->getTime();
|
||||
}
|
||||
|
||||
@ -606,7 +601,6 @@ class Template extends Render
|
||||
* Parse expressions. The mix of operators and terms.
|
||||
*
|
||||
* @param Tokenizer $tokens
|
||||
* @return string
|
||||
* @throws Error\UnexpectedTokenException
|
||||
*/
|
||||
public function parseExpr(Tokenizer $tokens)
|
||||
@ -619,6 +613,18 @@ class Template extends Render
|
||||
// parse term
|
||||
$term = $this->parseTerm($tokens, $var); // term of the expression
|
||||
if ($term !== false) {
|
||||
if($this->_options & Fenom::FORCE_VERIFY) {
|
||||
$term = '(isset('.$term.') ? '.$term.' : null)';
|
||||
$var = false;
|
||||
}
|
||||
if ($tokens->is('|')) {
|
||||
$term = $this->parseModifier($tokens, $term);
|
||||
$var = false;
|
||||
}
|
||||
if ($tokens->is('?', '!')) {
|
||||
$term = $this->parseTernary($tokens, $term, $tokens->current());
|
||||
$var = false;
|
||||
}
|
||||
$exp[] = $term;
|
||||
$op = false;
|
||||
} else {
|
||||
@ -683,14 +689,14 @@ class Template extends Render
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse any term of expression: -2, ++$var, 'adf'|mod:4
|
||||
* Parse any term of expression: -2, ++$var, 'adf'
|
||||
*
|
||||
* @param Tokenizer $tokens
|
||||
* @param bool $is_var
|
||||
* @return bool|string
|
||||
* @param bool $is_var is parsed term - plain variable
|
||||
* @throws Error\UnexpectedTokenException
|
||||
* @throws Error\TokenizeException
|
||||
* @throws \Exception
|
||||
* @return bool|string
|
||||
*/
|
||||
public function parseTerm(Tokenizer $tokens, &$is_var = false)
|
||||
{
|
||||
@ -701,63 +707,50 @@ class Template extends Render
|
||||
$unary = "";
|
||||
}
|
||||
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
||||
return $unary . $this->parseScalar($tokens, true);
|
||||
$code = $unary . $this->parseScalar($tokens, true);
|
||||
} elseif ($tokens->is(T_CONSTANT_ENCAPSED_STRING, '"', T_ENCAPSED_AND_WHITESPACE)) {
|
||||
if ($unary) {
|
||||
throw new UnexpectedTokenException($tokens->back());
|
||||
}
|
||||
return $this->parseScalar($tokens, true);
|
||||
$code = $this->parseScalar($tokens, true);
|
||||
} elseif ($tokens->is(T_VARIABLE)) {
|
||||
$var = $this->parseVar($tokens);
|
||||
if ($tokens->is(Tokenizer::MACRO_INCDEC, "|", "!", "?")) {
|
||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
||||
} elseif ($tokens->is("(") && $tokens->hasBackList(T_STRING)) { // method call
|
||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
||||
} elseif ($unary) {
|
||||
return $unary . $var;
|
||||
$code = $unary . $this->parseVariable($tokens);
|
||||
if ($tokens->is("(") && $tokens->hasBackList(T_STRING, T_OBJECT_OPERATOR)) {
|
||||
if ($this->_options & Fenom::DENY_METHODS) {
|
||||
throw new \LogicException("Forbidden to call methods");
|
||||
}
|
||||
$code .= $this->parseArgs($tokens);
|
||||
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||
$code .= $tokens->getAndNext();
|
||||
} else {
|
||||
$is_var = true;
|
||||
return $var;
|
||||
}
|
||||
} elseif ($tokens->is('$')) {
|
||||
$var = $this->parseAccessor($tokens, $is_var);
|
||||
if ($tokens->is(Tokenizer::MACRO_INCDEC, "|", "!", "?")) {
|
||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
||||
} else {
|
||||
return $unary . $var;
|
||||
}
|
||||
$code = $unary . $var;
|
||||
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||
return $unary . $this->parseVariable($tokens);
|
||||
$code = $unary . $tokens->getAndNext() . $this->parseVariable($tokens);
|
||||
} elseif ($tokens->is("(")) {
|
||||
$tokens->next();
|
||||
$exp = $unary . "(" . $this->parseExpr($tokens) . ")";
|
||||
$code = $unary . "(" . $this->parseExpr($tokens) . ")";
|
||||
$tokens->need(")")->next();
|
||||
return $exp;
|
||||
} elseif ($tokens->is(T_STRING)) {
|
||||
if ($tokens->isSpecialVal()) {
|
||||
return $unary . $tokens->getAndNext();
|
||||
$code = $unary . $tokens->getAndNext();
|
||||
} elseif ($tokens->isNext("(") && !$tokens->getWhitespace()) {
|
||||
$func = $this->_fenom->getModifier($tokens->current(), $this);
|
||||
if (!$func) {
|
||||
throw new \Exception("Function " . $tokens->getAndNext() . " not found");
|
||||
}
|
||||
$tokens->next();
|
||||
$func = $func . $this->parseArgs($tokens);
|
||||
if ($tokens->is('|')) {
|
||||
return $unary . $this->parseModifier($tokens, $func);
|
||||
} else {
|
||||
return $unary . $func;
|
||||
}
|
||||
$code = $unary . $func . $this->parseArgs($tokens->next());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} elseif ($tokens->is(T_ISSET, T_EMPTY)) {
|
||||
$func = $tokens->getAndNext();
|
||||
if ($tokens->is("(") && $tokens->isNext(T_VARIABLE)) {
|
||||
$tokens->next();
|
||||
$exp = $func . "(" . $this->parseVar($tokens) . ")";
|
||||
$code = $unary . $func . "(" . $this->parseVariable($tokens->next()) . ")";
|
||||
$tokens->need(')')->next();
|
||||
return $unary . $exp;
|
||||
} else {
|
||||
throw new TokenizeException("Unexpected token " . $tokens->getNext() . ", isset() and empty() accept only variables");
|
||||
}
|
||||
@ -765,43 +758,29 @@ class Template extends Render
|
||||
if ($unary) {
|
||||
throw new UnexpectedTokenException($tokens->back());
|
||||
}
|
||||
return $this->parseArray($tokens);
|
||||
$code = $this->parseArray($tokens);
|
||||
} elseif ($unary) {
|
||||
$tokens->back();
|
||||
throw new UnexpectedTokenException($tokens);
|
||||
throw new UnexpectedTokenException($tokens->back());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse simple variable (without modifier etc)
|
||||
*
|
||||
* @param Tokenizer $tokens
|
||||
* @return string
|
||||
*/
|
||||
public function parseVar(Tokenizer $tokens)
|
||||
{
|
||||
$var = $tokens->get(T_VARIABLE);
|
||||
$_var = '$tpl["' . substr($var, 1) . '"]';
|
||||
$tokens->next();
|
||||
$_var = $this->_var($tokens, $_var);
|
||||
if ($this->_options & Fenom::FORCE_VERIFY) {
|
||||
return 'isset(' . $_var . ') ? ' . $_var . ' : null';
|
||||
} else {
|
||||
return $_var;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse variable name: $a, $a.b, $a.b[c]
|
||||
* @param Tokenizer $tokens
|
||||
* @param $var
|
||||
* @return string
|
||||
* @throws Error\UnexpectedTokenException
|
||||
*/
|
||||
protected function _var(Tokenizer $tokens, $var)
|
||||
public function parseVariable(Tokenizer $tokens, $var = null)
|
||||
{
|
||||
if(!$var) {
|
||||
$var = '$tpl["' . substr( $tokens->get(T_VARIABLE), 1) . '"]';
|
||||
$tokens->next();
|
||||
}
|
||||
while ($t = $tokens->key()) {
|
||||
if ($t === ".") {
|
||||
$tokens->next();
|
||||
@ -844,62 +823,6 @@ class Template extends Render
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse complex variable
|
||||
* $var.foo[bar]["a"][1+3/$var]|mod:3:"w":$var3|mod3
|
||||
* ++$var|mod
|
||||
* $var--|mod
|
||||
*
|
||||
* @see parseModifier
|
||||
* @static
|
||||
* @param Tokenizer $tokens
|
||||
* @param int $options set parser options
|
||||
* @param string $var already parsed plain variable
|
||||
* @throws \LogicException
|
||||
* @throws InvalidUsageException
|
||||
* @return string
|
||||
*/
|
||||
public function parseVariable(Tokenizer $tokens, $options = 0, $var = null)
|
||||
{
|
||||
$stained = false;
|
||||
if (!$var) {
|
||||
if ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||
$stained = true;
|
||||
$var = $tokens->getAndNext() . $this->parseVar($tokens, $options);
|
||||
} else {
|
||||
$var = $this->parseVar($tokens, $options);
|
||||
}
|
||||
if ($tokens->is(T_OBJECT_OPERATOR)) { // parse
|
||||
$var .= '->' . $tokens->getNext(T_STRING);
|
||||
$tokens->next();
|
||||
}
|
||||
}
|
||||
|
||||
if ($tokens->is("(") && $tokens->hasBackList(T_STRING, T_OBJECT_OPERATOR)) {
|
||||
if ($stained) {
|
||||
throw new InvalidUsageException("Can not increment or decrement of the method result");
|
||||
}
|
||||
if ($this->_options & Fenom::DENY_METHODS) {
|
||||
throw new \LogicException("Forbidden to call methods");
|
||||
}
|
||||
$var .= $this->parseArgs($tokens);
|
||||
$stained = true;
|
||||
}
|
||||
if ($tokens->is('?', '!')) {
|
||||
return $this->parseTernary($tokens, $var, $tokens->current());
|
||||
}
|
||||
if ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||
if ($stained) {
|
||||
throw new InvalidUsageException("Can not use two increments and/or decrements for one variable");
|
||||
}
|
||||
$var .= $tokens->getAndNext();
|
||||
}
|
||||
if ($tokens->is('|') && !($options & self::DENY_MODS)) {
|
||||
return $this->parseModifier($tokens, $var);
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse accessor
|
||||
*/
|
||||
@ -907,16 +830,16 @@ class Template extends Render
|
||||
{
|
||||
$is_var = false;
|
||||
$vars = array(
|
||||
'get' => '$_GET',
|
||||
'post' => '$_POST',
|
||||
'get' => '$_GET',
|
||||
'post' => '$_POST',
|
||||
'session' => '$_SESSION',
|
||||
'cookie' => '$_COOKIE',
|
||||
'cookie' => '$_COOKIE',
|
||||
'request' => '$_REQUEST',
|
||||
'files' => '$_FILES',
|
||||
'files' => '$_FILES',
|
||||
'globals' => '$GLOBALS',
|
||||
'server' => '$_SERVER',
|
||||
'env' => '$_ENV',
|
||||
'tpl' => '$tpl->info'
|
||||
'server' => '$_SERVER',
|
||||
'env' => '$_ENV',
|
||||
'tpl' => '$tpl->info'
|
||||
);
|
||||
if ($this->_options & Fenom::DENY_ACCESSOR) {
|
||||
throw new \LogicException("Accessor are disabled");
|
||||
@ -925,7 +848,7 @@ class Template extends Render
|
||||
$tokens->next();
|
||||
if (isset($vars[$key])) {
|
||||
$is_var = true;
|
||||
return $this->_var($tokens, $vars[$key]);
|
||||
return $this->parseVariable($tokens, $vars[$key]);
|
||||
}
|
||||
switch ($key) {
|
||||
case 'const':
|
||||
@ -942,11 +865,7 @@ class Template extends Render
|
||||
throw new UnexpectedTokenException($tokens);
|
||||
}
|
||||
|
||||
if ($tokens->is('|')) {
|
||||
return $this->parseModifier($tokens, $var);
|
||||
} else {
|
||||
return $var;
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1021,12 +940,8 @@ class Template extends Render
|
||||
return '(' . $value . ' ' . $equal . '= ' . $action . ')';
|
||||
}
|
||||
return $invert . '(' . $value . ' instanceof \\' . $this->parseName($tokens) . ')';
|
||||
} elseif ($tokens->is(T_VARIABLE)) {
|
||||
return '(' . $value . ' ' . $equal . '= ' . $this->parseVariable($tokens) . ')';
|
||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR)) {
|
||||
return '(' . $value . ' ' . $equal . '= ' . $this->parseScalar($tokens) . ')';
|
||||
} elseif ($tokens->is('[')) {
|
||||
return '(' . $value . ' ' . $equal . '= ' . $this->parseArray($tokens) . ')';
|
||||
} elseif ($tokens->is(T_VARIABLE, '[', Tokenizer::MACRO_SCALAR, '"')) {
|
||||
return '(' . $value . ' ' . $equal . '= ' . $this->parseTerm($tokens) . ')';
|
||||
} elseif ($tokens->is(T_NS_SEPARATOR)) { //
|
||||
return $invert . '(' . $value . ' instanceof \\' . $this->parseName($tokens) . ')';
|
||||
} else {
|
||||
@ -1085,7 +1000,7 @@ class Template extends Render
|
||||
if (!$checker) {
|
||||
$checker = "auto";
|
||||
}
|
||||
return $invert . sprintf($checkers[$checker], $value, $this->parseVariable($tokens));
|
||||
return $invert . sprintf($checkers[$checker], $value, $this->parseTerm($tokens));
|
||||
} else {
|
||||
throw new UnexpectedTokenException($tokens);
|
||||
}
|
||||
@ -1115,30 +1030,25 @@ class Template extends Render
|
||||
* Parse scalar values
|
||||
*
|
||||
* @param Tokenizer $tokens
|
||||
* @param bool $allow_mods
|
||||
* @throws Error\UnexpectedTokenException
|
||||
* @return string
|
||||
* @throws TokenizeException
|
||||
*/
|
||||
public function parseScalar(Tokenizer $tokens, $allow_mods = true)
|
||||
public function parseScalar(Tokenizer $tokens)
|
||||
{
|
||||
$_scalar = "";
|
||||
if ($token = $tokens->key()) {
|
||||
switch ($token) {
|
||||
case T_CONSTANT_ENCAPSED_STRING:
|
||||
case T_LNUMBER:
|
||||
case T_DNUMBER:
|
||||
$_scalar .= $tokens->getAndNext();
|
||||
break;
|
||||
case T_ENCAPSED_AND_WHITESPACE:
|
||||
case '"':
|
||||
$_scalar .= $this->parseQuote($tokens);
|
||||
break;
|
||||
default:
|
||||
throw new TokenizeException("Unexpected scalar token '" . $tokens->current() . "'");
|
||||
}
|
||||
if ($allow_mods && $tokens->is("|")) {
|
||||
return $this->parseModifier($tokens, $_scalar);
|
||||
}
|
||||
$token = $tokens->key();
|
||||
switch ($token) {
|
||||
case T_CONSTANT_ENCAPSED_STRING:
|
||||
case T_LNUMBER:
|
||||
case T_DNUMBER:
|
||||
$_scalar .= $tokens->getAndNext();
|
||||
break;
|
||||
case T_ENCAPSED_AND_WHITESPACE:
|
||||
case '"':
|
||||
$_scalar .= $this->parseQuote($tokens);
|
||||
break;
|
||||
default:
|
||||
throw new UnexpectedTokenException($tokens);
|
||||
}
|
||||
return $_scalar;
|
||||
}
|
||||
@ -1152,7 +1062,7 @@ class Template extends Render
|
||||
*/
|
||||
public function parseQuote(Tokenizer $tokens)
|
||||
{
|
||||
if ($tokens->is('"', "`")) {
|
||||
if ($tokens->is('"')) {
|
||||
$stop = $tokens->current();
|
||||
$_str = '"';
|
||||
$tokens->next();
|
||||
@ -1208,17 +1118,6 @@ class Template extends Render
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tokenizer $tokens
|
||||
* @param null $first_member
|
||||
*/
|
||||
public function parseConcat(Tokenizer $tokens, $first_member = null)
|
||||
{
|
||||
$concat = array();
|
||||
if ($first_member) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse modifiers
|
||||
* |modifier:1:2.3:'string':false:$var:(4+5*$var3)|modifier2:"str {$var+3} ing":$arr.item
|
||||
@ -1240,25 +1139,8 @@ class Template extends Render
|
||||
$args = array();
|
||||
|
||||
while ($tokens->is(":")) {
|
||||
$token = $tokens->getNext(Tokenizer::MACRO_SCALAR, T_VARIABLE, '"', Tokenizer::MACRO_STRING, "(", "[", '$');
|
||||
|
||||
if ($tokens->is(Tokenizer::MACRO_SCALAR) || $tokens->isSpecialVal()) {
|
||||
$args[] = $token;
|
||||
$tokens->next();
|
||||
} elseif ($tokens->is(T_VARIABLE)) {
|
||||
$args[] = $this->parseVariable($tokens, self::DENY_MODS);
|
||||
} elseif ($tokens->is('$')) {
|
||||
$args[] = $this->parseAccessor($tokens, $is_var);
|
||||
} elseif ($tokens->is('"', '`', T_ENCAPSED_AND_WHITESPACE)) {
|
||||
$args[] = $this->parseQuote($tokens);
|
||||
} elseif ($tokens->is('(')) {
|
||||
$args[] = $this->parseExpr($tokens);
|
||||
} elseif ($tokens->is('[')) {
|
||||
$args[] = $this->parseArray($tokens);
|
||||
} elseif ($tokens->is(T_STRING) && $tokens->isNext('(')) {
|
||||
$args[] = $tokens->getAndNext() . $this->parseArgs($tokens);
|
||||
} else {
|
||||
break;
|
||||
if (!$args[] = $this->parseTerm($tokens->next())) {
|
||||
throw new UnexpectedTokenException($tokens);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1358,14 +1240,14 @@ class Template extends Render
|
||||
throw new InvalidUsageException("Macro '$name' require '$arg' argument");
|
||||
}
|
||||
}
|
||||
$n = $this->i++;
|
||||
$n = sprintf('%u_%d', crc32($this->_name), $this->i++);
|
||||
if ($recursive) {
|
||||
$recursive['recursive'] = true;
|
||||
$body = '$tpl->getMacro("' . $name . '")->__invoke($tpl);';
|
||||
} else {
|
||||
$body = '?>' . $macro["body"] . '<?php';
|
||||
}
|
||||
return '$_tpl' . $n . ' = $tpl->exchangeArray(' . Compiler::toArray($args) . ');' . PHP_EOL . $body . PHP_EOL . '$tpl->exchangeArray($_tpl' . $n . '); unset($_tpl' . $n . ');';
|
||||
return '$_tpl' . $n . ' = $tpl->exchangeArray(' . Compiler::toArray($args) . ');' . PHP_EOL . $body . PHP_EOL . '$tpl->exchangeArray($_tpl' . $n . '); /* X */ unset($_tpl' . $n . ');';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1457,7 +1339,7 @@ class Template extends Render
|
||||
} else {
|
||||
$params[$key] = 'true';
|
||||
}
|
||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, '"', '`', T_VARIABLE, "[", '(')) {
|
||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, '"', T_VARIABLE, "[", '(')) {
|
||||
$params[] = $this->parseExpr($tokens);
|
||||
} else {
|
||||
break;
|
||||
|
@ -104,8 +104,8 @@ class Tokenizer
|
||||
\T_LOGICAL_AND => 1, \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_METHOD_C => 1, \T_NAMESPACE => 1, \T_NS_C => 1,
|
||||
\T_NEW => 1, \T_PRINT => 1, \T_PRIVATE => 1, \T_PUBLIC => 1, \T_PROTECTED => 1, \T_REQUIRE => 1,
|
||||
\T_REQUIRE_ONCE => 1, \T_RETURN => 1, \T_RETURN => 1, \T_STRING => 1, \T_SWITCH => 1, \T_THROW => 1,
|
||||
\T_TRAIT => 1, \T_TRAIT_C => 1, \T_TRY => 1, \T_UNSET => 1, \T_VAR => 1,
|
||||
\T_WHILE => 1, \T_YIELD => 1, \T_USE => 1
|
||||
\T_TRAIT => 1, \T_TRAIT_C => 1, \T_TRY => 1, \T_UNSET => 1, \T_USE => 1, \T_VAR => 1,
|
||||
\T_WHILE => 1, \T_YIELD => 1
|
||||
),
|
||||
self::MACRO_INCDEC => array(
|
||||
\T_INC => 1, \T_DEC => 1
|
||||
@ -130,9 +130,10 @@ class Tokenizer
|
||||
\T_IS_NOT_EQUAL => 1, \T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1,
|
||||
),
|
||||
self::MACRO_EQUALS => array(
|
||||
\T_AND_EQUAL => 1, \T_CONCAT_EQUAL => 1, \T_DIV_EQUAL => 1, \T_MINUS_EQUAL => 1, \T_MOD_EQUAL => 1,
|
||||
\T_AND_EQUAL => 1, \T_DIV_EQUAL => 1, \T_MINUS_EQUAL => 1, \T_MOD_EQUAL => 1,
|
||||
\T_MUL_EQUAL => 1, \T_OR_EQUAL => 1, \T_PLUS_EQUAL => 1, \T_SL_EQUAL => 1, \T_SR_EQUAL => 1,
|
||||
\T_XOR_EQUAL => 1, '=' => 1
|
||||
\T_XOR_EQUAL => 1, '=' => 1,
|
||||
// \T_CONCAT_EQUAL => 1,
|
||||
),
|
||||
self::MACRO_SCALAR => array(
|
||||
\T_LNUMBER => 1, \T_DNUMBER => 1, \T_CONSTANT_ENCAPSED_STRING => 1
|
||||
|
@ -137,6 +137,7 @@ class TemplateTest extends TestCase
|
||||
array('Mod: {$date|date:"Y m d"}!', $b, 'Mod: 2012 07 26!'),
|
||||
array('Mod: {$tags|strip_tags}!', $b, 'Mod: my name is Legion!'),
|
||||
array('Mod: {$b.c|json_encode}!', $b, 'Mod: "Username"!'),
|
||||
array('Mod: {($time/1024/1024)|round:2}!', $b, 'Mod: 1281.09!'),
|
||||
array('Mod: {time()|date:"Y m d"}!', $b, 'Mod: ' . date("Y m d") . '!'),
|
||||
);
|
||||
}
|
||||
@ -341,7 +342,7 @@ class TemplateTest extends TestCase
|
||||
array('Create: {var $v = 1++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||
array('Create: {var $v = c} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token 'c'"),
|
||||
array('Create: {var $v = ($a)++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||
array('Create: {var $v = --$a++} Result: {$v} end', 'Fenom\Error\CompileException', "Can not use two increments and/or decrements for one variable"),
|
||||
array('Create: {var $v = --$a++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||
array('Create: {var $v = $a|upper++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||
array('Create: {var $v = max($a,2)++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||
array('Create: {var $v = max($a,2)} Result: {$v} end', 'Fenom\Error\CompileException', "Function max not found", Fenom::DENY_NATIVE_FUNCS),
|
||||
@ -494,37 +495,40 @@ class TemplateTest extends TestCase
|
||||
public static function providerSwitch()
|
||||
{
|
||||
$code1 = 'Switch: {switch $a}
|
||||
{case 1} one {break}
|
||||
{case 2} two {break}
|
||||
{case "string"} str {break}
|
||||
{case 1, "one"} one
|
||||
{case 2, "two"} two
|
||||
{case "string"} str
|
||||
{default} def
|
||||
{/switch} end';
|
||||
|
||||
$code2 = 'Switch: {switch $a}
|
||||
{case 1} one {break}
|
||||
{case 2} two {break}
|
||||
{case "string"} str {break}
|
||||
{case 1, "one"} one
|
||||
{case 2, "two"} two
|
||||
{case "string"} str
|
||||
{/switch} end';
|
||||
|
||||
$code3 = 'Switch: {switch $a} invalid
|
||||
{case 1} one {break}
|
||||
{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($code2, array("a" => "unk"), 'Switch: end'),
|
||||
array($code3, array("a" => 1), 'Switch: invalid one end'),
|
||||
array($code3, array("a" => 1), 'Switch: one end'),
|
||||
array($code3, array("a" => 'one'), 'Switch: one end'),
|
||||
);
|
||||
}
|
||||
|
||||
public static function providerSwitchInvalid()
|
||||
{
|
||||
return array(
|
||||
array('Switch: {switch}{case 1} one {break}{/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||
array('Switch: {switch 1}{case} one {break}{/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||
array('Switch: {switch 1}{break}{case} one {/switch} end', 'Fenom\Error\CompileException', "Improper usage of the tag {break}"),
|
||||
array('Switch: {switch}{case 1} one {/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||
array('Switch: {switch 1}{case} one{/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||
array('Switch: {switch 1}{case $var} one {/switch} end', 'Fenom\Error\CompileException', "Unexpected token '\$var' in expression"),
|
||||
);
|
||||
}
|
||||
|
||||
@ -575,7 +579,7 @@ class TemplateTest extends TestCase
|
||||
array('For: {for} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||
array('For: {for $a=} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||
array('For: {for $a+1=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token '+'"),
|
||||
array('For: {for max($a,$b)=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'max'"),
|
||||
array('For: {for max($a,$b)=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token '='"),
|
||||
array('For: {for to=6 $a=3} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'to'"),
|
||||
array('For: {for index=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'index'"),
|
||||
array('For: {for first=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'first'"),
|
||||
@ -719,7 +723,7 @@ class TemplateTest extends TestCase
|
||||
public function _testSandbox()
|
||||
{
|
||||
try {
|
||||
var_dump($this->fenom->compileCode('{"string"|append:$.get.one}')->getBody());
|
||||
var_dump($this->fenom->setOptions(Fenom::FORCE_VERIFY)->compileCode('{if $unexist} block1 {else} block2 {/if}')->getBody());
|
||||
} catch (\Exception $e) {
|
||||
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
||||
}
|
||||
@ -875,6 +879,7 @@ class TemplateTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @group switch
|
||||
* @dataProvider providerSwitch
|
||||
*/
|
||||
public function testSwitch($code, $vars, $result)
|
||||
@ -883,6 +888,7 @@ class TemplateTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @group switch-bad
|
||||
* @dataProvider providerSwitchInvalid
|
||||
*/
|
||||
public function testSwitchInvalid($code, $exception, $message, $options = 0)
|
||||
|
Loading…
Reference in New Issue
Block a user