Add filters for templates (#30)

This commit is contained in:
bzick 2013-08-01 01:05:19 +04:00
parent e68f3dd99a
commit f1d252a3cc
4 changed files with 99 additions and 36 deletions

View File

@ -7,8 +7,8 @@
* For the full copyright and license information, please view the license.md
* file that was distributed with this source code.
*/
use Fenom\Template,
Fenom\ProviderInterface;
use Fenom\ProviderInterface;
use Fenom\Template;
/**
* Fenom Template Engine
@ -67,10 +67,26 @@ class Fenom
"disable_statics" => self::DENY_STATICS,
);
/**
* @var callable[]
*/
public $pre_filters = array();
/**
* @var callable[]
*/
public $filters = array();
/**
* @var callable[]
*/
public $post_filters = array();
/**
* @var Fenom\Render[] Templates storage
*/
protected $_storage = array();
/**
* @var string compile directory
*/
@ -81,10 +97,6 @@ class Fenom
*/
protected $_options = 0;
protected $_on_pre_cmp = array();
protected $_on_cmp = array();
protected $_on_post_cmp = array();
/**
* @var ProviderInterface
*/
@ -98,28 +110,28 @@ class Fenom
* @var string[] list of modifiers [modifier_name => callable]
*/
protected $_modifiers = array(
"upper" => 'strtoupper',
"up" => 'strtoupper',
"lower" => 'strtolower',
"low" => 'strtolower',
"upper" => 'strtoupper',
"up" => 'strtoupper',
"lower" => 'strtolower',
"low" => 'strtolower',
"date_format" => 'Fenom\Modifier::dateFormat',
"date" => 'Fenom\Modifier::date',
"truncate" => 'Fenom\Modifier::truncate',
"escape" => 'Fenom\Modifier::escape',
"e" => 'Fenom\Modifier::escape', // alias of escape
"unescape" => 'Fenom\Modifier::unescape',
"strip" => 'Fenom\Modifier::strip',
"length" => 'Fenom\Modifier::length',
"iterable" => 'Fenom\Modifier::isIterable'
"date" => 'Fenom\Modifier::date',
"truncate" => 'Fenom\Modifier::truncate',
"escape" => 'Fenom\Modifier::escape',
"e" => 'Fenom\Modifier::escape', // alias of escape
"unescape" => 'Fenom\Modifier::unescape',
"strip" => 'Fenom\Modifier::strip',
"length" => 'Fenom\Modifier::length',
"iterable" => 'Fenom\Modifier::isIterable'
);
/**
* @var array of allowed PHP functions
*/
protected $_allowed_funcs = array(
"count" => 1, "is_string" => 1, "is_array" => 1, "is_numeric" => 1, "is_int" => 1,
"is_object" => 1, "strtotime" => 1, "gettype" => 1, "is_double" => 1, "json_encode" => 1, "json_decode" => 1,
"ip2long" => 1, "long2ip" => 1, "strip_tags" => 1, "nl2br" => 1, "explode" => 1, "implode" => 1
"count" => 1, "is_string" => 1, "is_array" => 1, "is_numeric" => 1, "is_int" => 1,
"is_object" => 1, "strtotime" => 1, "gettype" => 1, "is_double" => 1, "json_encode" => 1, "json_decode" => 1,
"ip2long" => 1, "long2ip" => 1, "strip_tags" => 1, "nl2br" => 1, "explode" => 1, "implode" => 1
);
/**
@ -292,27 +304,47 @@ class Fenom
/**
*
* @param callable $cb
* @return self
*/
public function addPreCompileFilter($cb)
public function addPreFilter($cb)
{
$this->_on_pre_cmp[] = $cb;
$this->pre_filters[] = $cb;
return $this;
}
public function getPreFilters() {
return $this->pre_filters;
}
/**
*
* @param callable $cb
* @return self
*/
public function addPostCompileFilter($cb)
public function addPostFilter($cb)
{
$this->_on_post_cmp[] = $cb;
$this->post_filters[] = $cb;
return $this;
}
public function getPostFilters() {
return $this->post_filters;
}
/**
* @param callable $cb
* @return self
*/
public function addCompileFilter($cb)
public function addFilter($cb)
{
$this->_on_cmp[] = $cb;
$this->filters[] = $cb;
return $this;
}
public function getFilters() {
return $this->filters;
}
/**

View File

@ -8,8 +8,8 @@
* file that was distributed with this source code.
*/
namespace Fenom;
use Fenom,
Fenom\Error\UnexpectedTokenException;
use Fenom;
use Fenom\Error\UnexpectedTokenException;
use Fenom\Error\CompileException;
use Fenom\Error\InvalidUsageException;
use Fenom\Error\SecurityException;
@ -97,7 +97,7 @@ class Template extends Render
private $_before;
private $_filter = array();
private $_filters = array();
private static $_checkers = array(
'integer' => 'is_int(%s)',
@ -136,6 +136,7 @@ class Template extends Render
{
$this->_fenom = $fenom;
$this->_options = $options;
$this->_filters = $this->_fenom->getFilters();
}
/**
@ -196,6 +197,9 @@ class Template extends Render
{
$end = $pos = 0;
$this->escape = $this->_options & Fenom::AUTO_ESCAPE;
foreach($this->_fenom->getPreFilters() as $filter) {
$this->_src = call_user_func($filter, $this->_src, $this);
}
while (($start = strpos($this->_src, '{', $pos)) !== false) { // search open-symbol of tags
switch ($this->_src[$start + 1]) { // check next character
@ -275,11 +279,15 @@ class Template extends Render
}
}
$this->addDepend($this); // for 'verify' performance
foreach($this->_fenom->getPostFilters() as $filter) {
$this->_body = call_user_func($filter, $this->_body, $this);
}
}
/**
* Execute some code in loading cache
* Execute some code at loading cache
* @param $code
* @return void
*/
public function before($code)
{
@ -303,15 +311,18 @@ class Template extends Render
private function _appendText($text)
{
$this->_line += substr_count($text, "\n");
if ($this->_filter) {
if ($this->_filters) {
if (strpos($text, "<?") === false) {
foreach ($this->_filters as $filter) {
$text = call_user_func($filter, $text, $this);
}
$this->_body .= $text;
} else {
$fragments = explode("<?", $text);
foreach ($fragments as &$fragment) {
if ($fragment) {
foreach ($this->_filter as $filter) {
$fragment = call_user_func($filter, $fragment);
foreach ($this->_filters as $filter) {
$fragment = call_user_func($filter, $fragment, $this);
}
}
}

View File

@ -47,7 +47,7 @@ class MacrosTest extends TestCase
$this->tpl("macro_recursive.tpl", '{macro factorial(num)}
{if $num}
{$num} {macro.factorial num=$num-1}
{$num} {macro.factorial num=$num-1} {$num}
{/if}
{/macro}
@ -104,6 +104,6 @@ class MacrosTest extends TestCase
$this->fenom->compile('macro_recursive.tpl');
$this->fenom->flush();
$tpl = $this->fenom->getTemplate('macro_recursive.tpl');
$this->assertSame("10 9 8 7 6 5 4 3 2 1", Modifier::strip($tpl->fetch(array()), true));
$this->assertSame("10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10", Modifier::strip($tpl->fetch(array()), true));
}
}

View File

@ -114,4 +114,24 @@ class FenomTest extends \Fenom\TestCase
// printf("remove %010b from option %010b, flags %010b\n", $option, $this->fenom->getOptions(), $flags & ~$option);
// $this->assertSame($this->fenom->getOptions(), $flags & ~$option);
}
public function testFilter() {
$punit = $this;
$this->fenom->addPreFilter(function ($src, $tpl) use ($punit) {
$this->assertInstanceOf('Fenom\Template', $tpl);
return "== $src ==";
});
$this->fenom->addPostFilter(function ($code, $tpl) use ($punit) {
$this->assertInstanceOf('Fenom\Template', $tpl);
return "+++ $code +++";
});
$this->fenom->addFilter(function ($text, $tpl) use ($punit) {
$this->assertInstanceOf('Fenom\Template', $tpl);
return "|--- $text ---|";
});
$this->assertSame('+++ |--- == hello ---||--- world == ---| +++', $this->fenom->compileCode('hello {var $user} god {/var} world')->fetch(array()));
}
}