mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Add #48: allow call static method in templates and allow disable this option
This commit is contained in:
parent
7759df8453
commit
75bcc4e0ff
@ -1,13 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once __DIR__.'/../vendor/autoload.php';
|
namespace Ts {
|
||||||
|
class Math {
|
||||||
|
public static function multi($x, $y) {
|
||||||
|
return $x * $y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled', 0);
|
namespace {
|
||||||
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
$fenom->display("../templates/../fenom.php", array(
|
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled', Fenom::FORCE_COMPILE);
|
||||||
"user" => array(
|
|
||||||
"name" => "Ivka",
|
$fenom->display("greeting.tpl", array(
|
||||||
|
"user" => array(
|
||||||
|
"name" => "Ivka",
|
||||||
|
'type' => 'new'
|
||||||
|
),
|
||||||
'type' => 'new'
|
'type' => 'new'
|
||||||
),
|
));
|
||||||
'type' => 'new'
|
}
|
||||||
));
|
|
@ -23,7 +23,8 @@ use Fenom\Error\TokenizeException;
|
|||||||
*/
|
*/
|
||||||
class Template extends Render
|
class Template extends Render
|
||||||
{
|
{
|
||||||
|
const VAR_NAME = '$var';
|
||||||
|
const TPL_NAME = '$tpl';
|
||||||
/**
|
/**
|
||||||
* Disable array parser.
|
* Disable array parser.
|
||||||
*/
|
*/
|
||||||
@ -440,11 +441,8 @@ class Template extends Render
|
|||||||
{
|
{
|
||||||
if (!$this->_code) {
|
if (!$this->_code) {
|
||||||
// evaluate template's code
|
// evaluate template's code
|
||||||
// $code = ("\$this->_code = " . $this->_getClosureSource() . ";\n\$this->_macros = " . $this->_getMacrosArray() . ';');
|
|
||||||
// file_put_contents('/tmp/last.tpl', $code);
|
|
||||||
eval("\$this->_code = " . $this->_getClosureSource() . ";\n\$this->_macros = " . $this->_getMacrosArray() . ';');
|
eval("\$this->_code = " . $this->_getClosureSource() . ";\n\$this->_macros = " . $this->_getMacrosArray() . ';');
|
||||||
if (!$this->_code) {
|
if (!$this->_code) {
|
||||||
// exit;
|
|
||||||
throw new CompileException("Fatal error while creating the template");
|
throw new CompileException("Fatal error while creating the template");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,7 +550,8 @@ class Template extends Render
|
|||||||
* @static
|
* @static
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @throws \LogicException
|
* @throws \LogicException
|
||||||
* @throws TokenizeException
|
* @throws \RuntimeException
|
||||||
|
* @throws Error\TokenizeException
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function parseAct(Tokenizer $tokens)
|
public function parseAct(Tokenizer $tokens)
|
||||||
@ -573,6 +572,15 @@ class Template extends Render
|
|||||||
$name = $action . "." . $name;
|
$name = $action . "." . $name;
|
||||||
}
|
}
|
||||||
return $this->parseMacroCall($tokens, $name);
|
return $this->parseMacroCall($tokens, $name);
|
||||||
|
} elseif($tokens->is(T_DOUBLE_COLON, T_NS_SEPARATOR)) { // static method call
|
||||||
|
$tokens->back();
|
||||||
|
$p = $tokens->p;
|
||||||
|
$static = $this->parseStatic($tokens);
|
||||||
|
if($tokens->is("(")) {
|
||||||
|
return $this->out($this->parseExpr($tokens->seek($p)));
|
||||||
|
} else {
|
||||||
|
return $this->out(Compiler::smartFuncParser($static, $tokens, $this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($tag = $this->_fenom->getTag($action, $this)) { // call some function
|
if ($tag = $this->_fenom->getTag($action, $this)) { // call some function
|
||||||
@ -766,6 +774,10 @@ class Template extends Render
|
|||||||
throw new \Exception("Function " . $tokens->getAndNext() . " not found");
|
throw new \Exception("Function " . $tokens->getAndNext() . " not found");
|
||||||
}
|
}
|
||||||
$code = $unary . $func . $this->parseArgs($tokens->next());
|
$code = $unary . $func . $this->parseArgs($tokens->next());
|
||||||
|
} elseif($tokens->isNext(T_NS_SEPARATOR, T_DOUBLE_COLON)) {
|
||||||
|
$method = $this->parseStatic($tokens);
|
||||||
|
$args = $this->parseArgs($tokens);
|
||||||
|
$code = $unary . $method . $args;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1179,13 +1191,18 @@ class Template extends Render
|
|||||||
public function parseModifier(Tokenizer $tokens, $value)
|
public function parseModifier(Tokenizer $tokens, $value)
|
||||||
{
|
{
|
||||||
while ($tokens->is("|")) {
|
while ($tokens->is("|")) {
|
||||||
$mods = $this->_fenom->getModifier($tokens->getNext(Tokenizer::MACRO_STRING), $this);
|
$modifier = $tokens->getNext(Tokenizer::MACRO_STRING);
|
||||||
if (!$mods) {
|
if($tokens->isNext(T_DOUBLE_COLON, T_NS_SEPARATOR)) {
|
||||||
throw new \Exception("Modifier " . $tokens->current() . " not found");
|
$mods = $this->parseStatic($tokens);
|
||||||
|
} else {
|
||||||
|
$mods = $this->_fenom->getModifier($modifier, $this);
|
||||||
|
if (!$mods) {
|
||||||
|
throw new \Exception("Modifier " . $tokens->current() . " not found");
|
||||||
|
}
|
||||||
|
$tokens->next();
|
||||||
}
|
}
|
||||||
$tokens->next();
|
|
||||||
$args = array();
|
|
||||||
|
|
||||||
|
$args = array();
|
||||||
while ($tokens->is(":")) {
|
while ($tokens->is(":")) {
|
||||||
if (!$args[] = $this->parseTerm($tokens->next())) {
|
if (!$args[] = $this->parseTerm($tokens->next())) {
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
@ -1288,23 +1305,48 @@ class Template extends Render
|
|||||||
throw new InvalidUsageException("Macro '$name' require '$arg' argument");
|
throw new InvalidUsageException("Macro '$name' require '$arg' argument");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// $n = sprintf('%x_%x', crc32($this->_name), $this->i++);
|
|
||||||
if ($recursive) {
|
if ($recursive) {
|
||||||
$recursive['recursive'] = true;
|
$recursive['recursive'] = true;
|
||||||
return '$tpl->getMacro("' . $name . '")->__invoke('.Compiler::toArray($args).', $tpl);';
|
return '$tpl->getMacro("' . $name . '")->__invoke('.Compiler::toArray($args).', $tpl);';
|
||||||
} else {
|
} else {
|
||||||
// $body = '? >' . $macro["body"] . '<?php';
|
|
||||||
$vars = $this->tmpVar();
|
$vars = $this->tmpVar();
|
||||||
return $vars . ' = $var; $var = ' . Compiler::toArray($args) . ';' . PHP_EOL . '?>' .
|
return $vars . ' = $var; $var = ' . Compiler::toArray($args) . ';' . PHP_EOL . '?>' .
|
||||||
$macro["body"] . '<?php' . PHP_EOL . '$var = '.$vars.'; unset(' . $vars . ');';
|
$macro["body"] . '<?php' . PHP_EOL . '$var = '.$vars.'; unset(' . $vars . ');';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @throws \LogicException
|
||||||
|
* @throws \RuntimeException
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function parseStatic(Tokenizer $tokens)
|
||||||
|
{
|
||||||
|
if($this->_options & Fenom::DENY_STATICS) {
|
||||||
|
throw new \LogicException("Static methods are disabled");
|
||||||
|
}
|
||||||
|
$tokens->skipIf(T_NS_SEPARATOR);
|
||||||
|
$name = "";
|
||||||
|
if ($tokens->is(T_STRING)) {
|
||||||
|
$name .= $tokens->getAndNext();
|
||||||
|
while ($tokens->is(T_NS_SEPARATOR)) {
|
||||||
|
$name .= '\\' . $tokens->next()->get(T_STRING);
|
||||||
|
$tokens->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$tokens->need(T_DOUBLE_COLON)->next()->need(T_STRING);
|
||||||
|
$static = $name . "::" . $tokens->getAndNext();
|
||||||
|
if(!is_callable($static)) {
|
||||||
|
throw new \RuntimeException("Method $static doesn't exist");
|
||||||
|
}
|
||||||
|
return $static;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse argument list
|
* Parse argument list
|
||||||
* (1 + 2.3, 'string', $var, [2,4])
|
* (1 + 2.3, 'string', $var, [2,4])
|
||||||
*
|
*
|
||||||
* @static
|
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @throws TokenizeException
|
* @throws TokenizeException
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -617,4 +617,16 @@ class Tokenizer
|
|||||||
{
|
{
|
||||||
return $this->curr ? $this->curr[2] : false;
|
return $this->curr ? $this->curr[2] : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek to custom element
|
||||||
|
* @param int $p
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function seek($p)
|
||||||
|
{
|
||||||
|
$this->p = $p;
|
||||||
|
unset($this->prev, $this->curr, $this->next);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -780,12 +780,39 @@ class TemplateTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function providerStatic() {
|
||||||
|
return array(
|
||||||
|
array('{Fenom\TemplateTest::multi x=3 y=4}', '12'),
|
||||||
|
array('{Fenom\TemplateTest::multi(3,4)}', '12'),
|
||||||
|
array('{12 + Fenom\TemplateTest::multi(3,4)}', '24'),
|
||||||
|
array('{12 + 3|Fenom\TemplateTest::multi:4}', '24'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerStaticInvalid() {
|
||||||
|
return array(
|
||||||
|
array('{Fenom\TemplateTest::multi x=3 y=4}', 'Fenom\Error\SecurityException', "Static methods are disabled", Fenom::DENY_STATICS),
|
||||||
|
array('{Fenom\TemplateTest::multi(3,4)}', 'Fenom\Error\SecurityException', "Static methods are disabled", Fenom::DENY_STATICS),
|
||||||
|
array('{12 + Fenom\TemplateTest::multi(3,4)}', 'Fenom\Error\SecurityException', "Static methods are disabled", Fenom::DENY_STATICS),
|
||||||
|
array('{12 + 3|Fenom\TemplateTest::multi:4}', 'Fenom\Error\SecurityException', "Static methods are disabled", Fenom::DENY_STATICS),
|
||||||
|
|
||||||
|
array('{Fenom\TemplateTest::multi_invalid x=3 y=4}', 'Fenom\Error\CompileException', 'Method Fenom\TemplateTest::multi_invalid doesn\'t exist'),
|
||||||
|
array('{Fenom\TemplateTest::multi_invalid(3,4)}', 'Fenom\Error\CompileException', 'Method Fenom\TemplateTest::multi_invalid doesn\'t exist'),
|
||||||
|
array('{12 + Fenom\TemplateTest::multi_invalid(3,4)}', 'Fenom\Error\CompileException', 'Method Fenom\TemplateTest::multi_invalid doesn\'t exist'),
|
||||||
|
array('{12 + 3|Fenom\TemplateTest::multi_invalid:4}', 'Fenom\Error\CompileException', 'Method Fenom\TemplateTest::multi_invalid doesn\'t exist'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function _testSandbox()
|
public function _testSandbox()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
var_dump($this->fenom->setOptions(Fenom::FORCE_VERIFY)->addFilter(function ($txt) {return $txt;})->compileCode('- {$a} -')->fetch(array('a' => 1)));
|
var_dump($this->fenom->compileCode('{Fenom\TemplateTest::multi(3,4)}')->getBody());
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
|
while($e->getPrevious()) {
|
||||||
|
$e = $e->getPrevious();
|
||||||
|
print_r("\n\n".$e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@ -1037,5 +1064,27 @@ class TemplateTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->exec($code, self::getVars(), $result);
|
$this->exec($code, self::getVars(), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group static
|
||||||
|
* @dataProvider providerStatic
|
||||||
|
*/
|
||||||
|
public function testStatic($code, $result)
|
||||||
|
{
|
||||||
|
$this->exec($code, self::getVars(), $result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function multi($x, $y = 42) {
|
||||||
|
return $x * $y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group static-invalid
|
||||||
|
* @dataProvider providerStaticInvalid
|
||||||
|
*/
|
||||||
|
public function testStaticInvalid($code, $exception, $message, $options = 0)
|
||||||
|
{
|
||||||
|
$this->execError($code, $exception, $message, $options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user