diff --git a/CHANGELOG.md b/CHANGELOG.md index d3a9d83..5ad40e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +## 1.2.0 + +- Feature #29: add {unset} tag +- Add hook for loading modifiers and tags + ## 1.1.0 - Bug #19: Bug with "if" expressions starting with "(" diff --git a/src/Fenom.php b/src/Fenom.php index 5696403..a1c4309 100644 --- a/src/Fenom.php +++ b/src/Fenom.php @@ -16,7 +16,7 @@ use Fenom\Template, * @author Ivan Shalganov */ class Fenom { - const VERSION = '1.1'; + const VERSION = '1.2'; /* Actions */ const INLINE_COMPILER = 1; @@ -27,7 +27,7 @@ class Fenom { /* Options */ const DENY_METHODS = 0x10; - const DENY_INLINE_FUNCS = 0x20; + const DENY_NATIVE_FUNCS = 0x20; const FORCE_INCLUDE = 0x40; const AUTO_RELOAD = 0x80; const FORCE_COMPILE = 0x100; @@ -37,6 +37,9 @@ class Fenom { const AUTO_TRIM = 0x1000; // reserved const DENY_STATICS = 0x2000; // reserved + /* @deprecated */ + const DENY_INLINE_FUNCS = 0x20; + /* Default parsers */ const DEFAULT_CLOSE_COMPILER = 'Fenom\Compiler::stdClose'; const DEFAULT_FUNC_PARSER = 'Fenom\Compiler::stdFuncParser'; @@ -50,7 +53,7 @@ class Fenom { */ private static $_options_list = array( "disable_methods" => self::DENY_METHODS, - "disable_native_funcs" => self::DENY_INLINE_FUNCS, + "disable_native_funcs" => self::DENY_NATIVE_FUNCS, "disable_cache" => self::DISABLE_CACHE, "force_compile" => self::FORCE_COMPILE, "auto_reload" => self::AUTO_RELOAD, @@ -461,40 +464,69 @@ class Fenom { /** * Return modifier function * - * @param $modifier + * @param string $modifier + * @param Fenom\Template $template * @return mixed - * @throws \Exception */ - public function getModifier($modifier) { + public function getModifier($modifier, Template $template = null) { if(isset($this->_modifiers[$modifier])) { return $this->_modifiers[$modifier]; } elseif($this->isAllowedFunction($modifier)) { return $modifier; } else { - throw new \Exception("Modifier $modifier not found"); + return $this->_loadModifier($modifier, $template); } } /** - * Return function - * + * @param string $modifier + * @param Fenom\Template $template + * @return bool + */ + protected function _loadModifier($modifier, $template) { + return false; + } + + /** * @param string $function + * @param Fenom\Template $template + * @return bool|string + * @deprecated + */ + public function getFunction($function, Template $template = null) { + return $this->getTag($function, $template); + } + + /** + * Returns tag info + * + * @param string $tag + * @param Fenom\Template $template * @return string|bool */ - public function getFunction($function) { - if(isset($this->_actions[$function])) { - return $this->_actions[$function]; + public function getTag($tag, Template $template = null) { + if(isset($this->_actions[$tag])) { + return $this->_actions[$tag]; } else { - return false; + return $this->_loadTag($tag, $template); } } + /** + * @param $tag + * @param Fenom\Template $template + * @return bool + */ + protected function _loadTag($tag, Template $template) { + return false; + } + /** * @param string $function * @return bool */ public function isAllowedFunction($function) { - if($this->_options & self::DENY_INLINE_FUNCS) { + if($this->_options & self::DENY_NATIVE_FUNCS) { return isset($this->_allowed_funcs[$function]); } else { return is_callable($function); diff --git a/src/Fenom/Compiler.php b/src/Fenom/Compiler.php index 30e390a..1ef5a58 100644 --- a/src/Fenom/Compiler.php +++ b/src/Fenom/Compiler.php @@ -879,7 +879,7 @@ class Compiler { $tpl->escape = false; if($tokens->is(':')) { $func = $tokens->getNext(Tokenizer::MACRO_STRING); - $tag = $tpl->getStorage()->getFunction($func); + $tag = $tpl->getStorage()->getTag($func, $tpl); if($tag["type"] == \Fenom::INLINE_FUNCTION) { $code = $tpl->parseAct($tokens); } elseif ($tag["type"] == \Fenom::BLOCK_FUNCTION) { diff --git a/src/Fenom/Template.php b/src/Fenom/Template.php index 50399fd..e5c9ce5 100644 --- a/src/Fenom/Template.php +++ b/src/Fenom/Template.php @@ -520,22 +520,22 @@ class Template extends Render { return $this->parseMacro($tokens, $name); } - if($act = $this->_fenom->getFunction($action)) { // call some function - switch($act["type"]) { + if($tag = $this->_fenom->getTag($action, $this)) { // call some function + switch($tag["type"]) { case Fenom::BLOCK_COMPILER: - $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack), $this->_body); + $scope = new Scope($action, $this, $this->_line, $tag, count($this->_stack), $this->_body); $code = $scope->open($tokens); if(!$scope->is_closed) { array_push($this->_stack, $scope); } return $code; case Fenom::INLINE_COMPILER: - return call_user_func($act["parser"], $tokens, $this); + return call_user_func($tag["parser"], $tokens, $this); case Fenom::INLINE_FUNCTION: - return $this->out(call_user_func($act["parser"], $act["function"], $tokens, $this)); + return $this->out(call_user_func($tag["parser"], $tag["function"], $tokens, $this)); case Fenom::BLOCK_FUNCTION: - $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack), $this->_body); - $scope->setFuncName($act["function"]); + $scope = new Scope($action, $this, $this->_line, $tag, count($this->_stack), $this->_body); + $scope->setFuncName($tag["function"]); array_push($this->_stack, $scope); $scope->escape = $this->escape; $this->escape = false; @@ -562,10 +562,10 @@ class Template extends Render { * * @static * @param Tokenizer $tokens - * @param bool $required - * @throws \LogicException - * @throws UnexpectedTokenException + * @param bool $required * @throws TokenizeException + * @throws UnexpectedTokenException + * @throws \Exception * @return string */ public function parseExp(Tokenizer $tokens, $required = false) { @@ -625,6 +625,9 @@ class Template extends Render { $_exp[] = $tokens->getAndNext(); } elseif($tokens->isNext("(") && !$tokens->getWhitespace()) { $func = $this->_fenom->getModifier($tokens->current()); + if(!$func) { + throw new \Exception("Function ".$tokens->getAndNext()." not found"); + } $tokens->next(); $func = $func.$this->parseArgs($tokens); if($tokens->is('|')) { @@ -1063,8 +1066,10 @@ class Template extends Render { */ public function parseModifier(Tokenizer $tokens, $value) { while($tokens->is("|")) { - $mods = $this->_fenom->getModifier( $modifier_name = $tokens->getNext(Tokenizer::MACRO_STRING) ); - + $mods = $this->_fenom->getModifier($tokens->getNext(Tokenizer::MACRO_STRING) ); + if(!$mods) { + throw new \Exception("Modifier ".$tokens->current()." not found"); + } $tokens->next(); $args = array(); diff --git a/tests/autoload.php b/tests/autoload.php index a3691fd..68e6c9a 100644 --- a/tests/autoload.php +++ b/tests/autoload.php @@ -9,6 +9,8 @@ define('FENOM_RESOURCES', __DIR__."/resources"); require_once FENOM_RESOURCES."/actions.php"; require_once __DIR__."/TestCase.php"; +ini_set('date.timezone', 'Europe/Moscow'); + function drop() { call_user_func_array("var_dump", func_get_args()); $e = new Exception(); diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 7ae60e0..738e888 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -319,7 +319,7 @@ class TemplateTest extends TestCase { array('Create: {var $v = --$a++} Result: {$v} end', 'Fenom\CompileException', "Can not use two increments and/or decrements for one variable"), array('Create: {var $v = $a|upper++} Result: {$v} end', 'Fenom\CompileException', "Unexpected token '++'"), array('Create: {var $v = max($a,2)++} Result: {$v} end', 'Fenom\CompileException', "Unexpected token '++'"), - array('Create: {var $v = max($a,2)} Result: {$v} end', 'Fenom\CompileException', "Modifier max not found", Fenom::DENY_INLINE_FUNCS), + array('Create: {var $v = max($a,2)} Result: {$v} end', 'Fenom\CompileException', "Function max not found", Fenom::DENY_NATIVE_FUNCS), array('Create: {var $v = 4*} Result: {$v} end', 'Fenom\CompileException', "Unexpected token '*'"), array('Create: {var $v = ""$a} Result: {$v} end', 'Fenom\CompileException', "Unexpected token '\$a'"), array('Create: {var $v = [1,2} Result: {$v} end', 'Fenom\CompileException', "Unexpected end of expression"),