mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Dev flags
This commit is contained in:
parent
61816e76bc
commit
777e315dce
@ -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
120
docs/dev/schema.md
Normal 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 |
|
||||
|___________________|
|
||||
|
||||
```
|
@ -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}
|
||||
```
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
|
Loading…
Reference in New Issue
Block a user