Dev flags

This commit is contained in:
Ivan Shalganov 2014-04-09 18:03:49 +04:00
parent 61816e76bc
commit 777e315dce
9 changed files with 191 additions and 34 deletions

View File

@ -1,7 +1,7 @@
Fenom - Template Engine for PHP
===============================
> Composer package: `{"fenom/fenom": "1.*"}`. See on [Packagist.org](https://packagist.org/packages/fenom/fenom)
> Composer package: `{"fenom/fenom": "2.*"}`. See on [Packagist.org](https://packagist.org/packages/fenom/fenom)
[![Latest Stable Version](https://poser.pugx.org/fenom/fenom/v/stable.png)](https://packagist.org/packages/fenom/fenom)
[![Build Status](https://travis-ci.org/bzick/fenom.png?branch=master)](https://travis-ci.org/bzick/fenom)
@ -12,7 +12,6 @@ Fenom - Template Engine for PHP
* Simple [syntax](./docs/syntax.md)
* [Fast](./docs/benchmark.md)
* [Secure](./docs/settings.md)
* Simple
* [Flexible](./docs/ext/extensions.md)
* [Lightweight](./docs/benchmark.md#stats)
* [Powerful](./docs/readme.md)

120
docs/dev/schema.md Normal file
View File

@ -0,0 +1,120 @@
How Fenom works
===============
```
use Fenom;
use Fenom\Render;
use Fenom\Template;
use Fenom\Tokenizer;
______________________________
| |
| Fenom::display($tpl, $var) |
|____________________________|
|
| search the template
______________|___________________________
| Template loaded into Fenom::$_storage? |
| Fenom::getTemplate($tpl) |
|________________________________________|
| |
| yes | no
______________|__________ |
| Render the template | |
| Render::display($tpl) | |
|_______________________| |
| |
| (hot start) |
| ______________________________|__________________
| | Template already compiled and stored in cache |
| | Fenom::getTemplate($template) |
| |_______________________________________________|
| | |
| | yes | no
| ____________|_______________ |
| | Load template from cache | not found |
| | Fenom::_load(...) |-------------->|
| |__________________________| |
| | |
| | found |
| ____________|___________ |
| | Validate template | invalid |
| | Render::isValid(...) |------------------>|
| |______________________| |
| | |
| | valid |
| ____________|____________ |
| | Render the template | |
|<----| Render::display(...) | |
| |_______________________| |
| |
| _____________________________ ________|___________________
| | Initialize compiler | | Compile the template |
| | Template::load($tpl) |<-----| Fenom::compile($tpl) |
| |___________________________| |__________________________|
| |
| ____________|________________
| | Load template source |
| | Provider::getSource($tpl) |
| |___________________________|
| |
| ____________|______________
| | Start compilation |
| | Template::compile($tpl) |
| |_________________________|
| |
| ____________|______________
| | Search template tag |
| | Template::compile($tpl) |<------------------------------------------------------|
| |_________________________| |
| | | |
| | not found | found |
| | _____________|_______________ _______________________________ |
| | | Tokenize the tag's code | | Parse the tag | |
| | | new Tokenizer($tag) |--->| Template::parseTag($tokens) | |
| | |___________________________| |_____________________________| |
| | | | |
| | is tag | | is expression |
| | _______________________________ | _______________|________________ |
| | | Detect tag name | | | Detect expression | |
| | | Template::parseAct($tokens) |<--- | Template::parseAct($tokens) | |
| | | Get callback by tag name | | Parse expression | |
| | | Fenom::getTag($tag_name) | | Template::parseExpr($tokens) | |
| | |_____________________________| |______________________________| |
| | | | |
| | | found | |
| | _______________|_______________ | |
| | | Invoke callback | | |
| | | Template::parseAct($tokens) | | |
| | |_____________________________| | |
| | | | |
| | _______________|________________ | |
| | | Append code to template | | |
| | | Template::_appendCode($code) |<----------------------- |
| | |______________________________| |
| | | |
| | _______________|___________ |
| | | Finalize the tag | starts search next tag |
| | | Template::compile($tpl) |>------------------------------------------------
| | |_________________________|
| |
| __|___________________________________
| | Store template to cache |
| | Fenom::compile($tpl) |
| | Store template to Fenom::$_storage |
| | Fenom::getTemplate($tpl) |
| |____________________________________|
| |
| ____________|_____________
| | Render the template |
| | Template::display(...) |
| |________________________|
| |
| | (cold start)
__|_________|________
| |
| DONE |
|___________________|
```

View File

@ -298,17 +298,18 @@ Outputs
{/foreach}
```
### Tag's compile options
### Tag options
| name | code | type | description |
| ------- | ---- | ----- | ------------ |
| strip | s | block | |
| atrim | a | any | |
| raw | r | any | |
| btrim | b | any | |
| ignore | i | block | |
| ltrim | l | any | |
| rtrim | r | any | |
| trim | t | any | |
| raw | a | any | |
| escape | e | any | |
| ignore | i | block | |
```smarty
{script:s:a:r:b:i:t} ... {/script}
{script:ignore} ... {/script}
```

View File

@ -37,7 +37,8 @@ class Fenom
const DISABLE_CACHE = 0x400;
const FORCE_VERIFY = 0x800;
const AUTO_TRIM = 0x1000; // reserved
const DENY_STATICS = 0x2000; // reserved
const DENY_STATICS = 0x2000;
const AUTO_STRIP = 0x4000; // reserved
/* @deprecated */
const DENY_INLINE_FUNCS = 0x20;
@ -556,6 +557,7 @@ class Fenom
}
/**
* Modifier autoloader
* @param string $modifier
* @param Fenom\Template $template
* @return bool
@ -582,7 +584,8 @@ class Fenom
}
/**
* @param $tag
* Tags autoloader
* @param string $tag
* @param Fenom\Template $template
* @return bool
*/

View File

@ -256,7 +256,7 @@ class Compiler
$condition = "$var >= {$p['to']}";
if ($p["last"]) $c = "($var + {$p['step']}) < {$p['to']}";
} else {
throw new InvalidUsageException("Invalid step value if {for}");
throw new InvalidUsageException("Invalid step value");
}
} else {
$condition = "({$p['step']} > 0 && $var <= {$p['to']} || {$p['step']} < 0 && $var >= {$p['to']})";
@ -533,7 +533,7 @@ class Compiler
if ($name) {
$tpl->importBlocks($name);
} else {
throw new InvalidUsageException('template name must be given explicitly yet');
throw new InvalidUsageException('Invalid template name for tag {use}');
}
}
@ -551,7 +551,7 @@ class Compiler
}
$scope["cname"] = $scope->tpl->parsePlainArg($tokens, $name);
if (!$name) {
throw new \RuntimeException("Only static names for blocks allowed");
throw new \RuntimeException("Invalid block name");
}
$scope["name"] = $name;
$scope["use_parent"] = false;
@ -837,7 +837,7 @@ class Compiler
$tpl->parsePlainArg($tokens, $name);
if (!$name) {
throw new InvalidUsageException("Invalid usage tag {import}");
throw new InvalidUsageException("Invalid template name");
}
if ($tokens->is(T_AS)) {
$alias = $tokens->next()->get(Tokenizer::MACRO_STRING);

View File

@ -274,7 +274,7 @@ class Template extends Render
$_tag = substr($tag, 1, -1); // strip delimiters '{' and '}'
if ($this->_ignore) { // check ignore
if ($_tag === '/ignore') { // turn off ignore
if ($_tag === '/' . $this->_ignore) { // turn off ignore
$this->_ignore = false;
} else { // still ignore
$this->_appendText($tag);
@ -559,7 +559,7 @@ class Template extends Render
try {
if ($tokens->is(Tokenizer::MACRO_STRING)) {
if ($tokens->current() === "ignore") {
$this->_ignore = true;
$this->_ignore = "ignore";
$tokens->next();
return '';
} else {
@ -596,7 +596,7 @@ class Template extends Render
/** @var Scope $scope */
$scope = array_pop($this->_stack);
if ($scope->name !== $name) {
throw new TokenizeException("Unexpected closing of the tag '$name' (expecting closing of the tag {$scope->name}, opened on line {$scope->line})");
throw new TokenizeException("Unexpected closing of the tag '$name' (expecting closing of the tag {$scope->name}, opened in line {$scope->line})");
}
if ($scope->is_compiler) {
return $scope->close($tokens);
@ -644,12 +644,20 @@ class Template extends Render
} else {
return $this->out(Compiler::smartFuncParser($static, $tokens, $this));
}
} elseif($tokens->is(':')) { // parse tag options
do {
$tokens->options[ $tokens->next()->need(T_STRING)->getAndNext() ] = true;
} while($tokens->is(':'));
}
if ($tag = $this->_fenom->getTag($action, $this)) { // call some function
if ($tag = $this->_fenom->getTag($action, $this)) {
if(isset($tokens->options['ignore']) && ($tag["type"] & Fenom::BLOCK_COMPILER)) {
$this->_ignore = $action;
}
switch ($tag["type"]) {
case Fenom::BLOCK_COMPILER:
$scope = new Scope($action, $this, $this->_line, $tag, count($this->_stack), $this->_body);
$scope->options = &$tokens->options;
$code = $scope->open($tokens);
if (!$scope->is_closed) {
array_push($this->_stack, $scope);
@ -661,6 +669,7 @@ class Template extends Render
return $this->out(call_user_func($tag["parser"], $tag["function"], $tokens, $this));
case Fenom::BLOCK_FUNCTION:
$scope = new Scope($action, $this, $this->_line, $tag, count($this->_stack), $this->_body);
$scope->options = &$tokens->options;
$scope->setFuncName($tag["function"]);
array_push($this->_stack, $scope);
$scope->escape = $this->escape;

View File

@ -32,26 +32,30 @@ class AutoEscapeTest extends TestCase
// inline function
array('{test_function text=$html}, {$html}', "$html, $html", $vars, 0),
array('{test_function text=$html}, {$html}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{raw:test_function text=$html}, {$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{raw:test_function text="{$html|up}"}, {$html}', strtoupper($html) . ", $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{test_function:raw text=$html}, {$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{test_function:raw text="{$html|up}"}, {$html}', strtoupper($html) . ", $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$escaped, $html", $vars, 0),
array('{autoescape false}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
array('{autoescape true}{raw:test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
array('{autoescape false}{raw:test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{raw:test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{raw:test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
array('{autoescape true}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
array('{autoescape false}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
// block function. Have bugs
// array('{test_block_function}{$html}{/test_block_function}', $html, $vars, 0),
// array('{test_block_function}{$html}{/test_block_function}', $escaped, $vars, \Fenom::AUTO_ESCAPE),
// array('{raw:test_block_function}{$html}{/test_block_function}', $html, $vars, \Fenom::AUTO_ESCAPE),
// array('{raw:test_block_function}{"{$html|up}"}{/test_block_function}', strtoupper($html), $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $html", $vars, 0),
// array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $html", $vars, 0),
// block function
array('{test_block_function}{$html}{/test_block_function}', $html, $vars, 0),
array('{test_block_function}{$html}{/test_block_function}', $escaped, $vars, \Fenom::AUTO_ESCAPE),
array('{test_block_function:raw}{$html}{/test_block_function}', $html, $vars, \Fenom::AUTO_ESCAPE),
array('{test_block_function:raw}{"{$html|up}"}{/test_block_function}', strtoupper($html), $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $html", $vars, 0),
array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $html", $vars, 0),
array('{autoescape true}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $html", $vars, 0),
array('{autoescape false}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $html", $vars, 0),
);
}

View File

@ -18,6 +18,17 @@ class ExtendsTest extends TestCase
exit;
}
public static function providerExtendsInvalid()
{
return array(
array('{extends "extends/dynamic/child.3.tpl"} {extends "extends/dynamic/child.3.tpl"}', 'Fenom\Error\CompileException', "Only one {extends} allowed"),
array('{if true}{extends "extends/dynamic/child.3.tpl"}{/if}', 'Fenom\Error\CompileException', "Tag {extends} can not be nested"),
array('{if true}{use "extends/dynamic/use.tpl"}{/if}', 'Fenom\Error\CompileException', "Tag {use} can not be nested"),
array('{use $use_this}', 'Fenom\Error\CompileException', "Invalid template name for tag {use}"),
array('{block $use_this}{/block}', 'Fenom\Error\CompileException', "Invalid block name"),
);
}
public function testAutoExtendsManual()
{
$child = $this->fenom->getRawTemplate()->load('extends/auto/child.1.tpl', false);
@ -132,5 +143,14 @@ Before footer
Footer from use";
$this->assertSame($result, $this->fenom->fetch('extends/dynamic/child.4.tpl', array()));
}
/**
* @group static-invalid
* @dataProvider providerExtendsInvalid
*/
public function testExtendsInvalid($code, $exception, $message, $options = 0)
{
$this->execError($code, $exception, $message, $options);
}
}

View File

@ -651,6 +651,7 @@ class TemplateTest extends TestCase
array('For: {for first=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'first'"),
array('For: {for last=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'last'"),
array('For: {for $a=4 to=6 unk=4} block1 {/for} end', 'Fenom\Error\CompileException', "Unknown parameter 'unk'"),
array('For: {for $a=4 to=6 step=0} block1 {/for} end', 'Fenom\Error\CompileException', "Invalid step value"),
array('For: {for $a=4 to=6} $a: {$a}, {forelse} {break} {/for} end', 'Fenom\Error\CompileException', "Improper usage of the tag {break}"),
array('For: {for $a=4 to=6} $a: {$a}, {forelse} {continue} {/for} end', 'Fenom\Error\CompileException', "Improper usage of the tag {continue}"),
);
@ -847,7 +848,7 @@ class TemplateTest extends TestCase
public function _testSandbox()
{
try {
var_dump($this->fenom->compileCode('{Fenom\TemplateTest::multi(3,4)}')->getBody());
var_dump($this->fenom->compileCode('{var:ignore $a} value {/var}')->getBody());
} catch (\Exception $e) {
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
while ($e->getPrevious()) {