mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Dev accessor. Add ~~ operator. ++Docs. ++Tests
This commit is contained in:
parent
af7546a8ec
commit
e55402c2f4
@ -127,11 +127,13 @@ Fenom поддерживает префиксные и постфиксные о
|
||||
* `--$a` - префиксный декремент, уменьшает $a на единицу, затем возвращает значение $a.
|
||||
* `$a--` - постфиксный декремент, возвращает значение $a, затем уменьшает $a на единицу.
|
||||
|
||||
### Строковый оператор
|
||||
### Строковые операторы
|
||||
|
||||
Оператор конкатенации `~` возвращает строку, представляющую собой соединение левого и правого аргумента.
|
||||
|
||||
`$a ~ $b` - возвращает результат объединения сток `$a` и `$b`
|
||||
`$a ~~ $b` - возвращает результат объединения сток `$a` и `$b` через пробел
|
||||
`$a ~= $b` - присвоение с объединением
|
||||
|
||||
### Тернарные операторы
|
||||
|
||||
|
@ -81,25 +81,31 @@
|
||||
|
||||
Безименная системная переменная начинается с `$.` и предоставляет доступ к глобальным системным переменным и системной информации:
|
||||
|
||||
* `$.get` — `$_GET`.
|
||||
* `$.post` — `$_POST`.
|
||||
* `$.cookie` — `$_COOKIE`.
|
||||
* `$.session` — `$_SESSION`.
|
||||
* `$.globals` — `$GLOBALS`.
|
||||
* `$.request` — `$_REQUEST`.
|
||||
* `$.files` — `$_FILES`.
|
||||
* `$.server` — `$_SERVER`.
|
||||
* `$.env` — `$_ENV`.
|
||||
* `$.env` — массив `$_ENV`.
|
||||
* `$.get` — массив `$_GET`.
|
||||
* `$.post` — массив `$_POST`.
|
||||
* `$.files` — массив `$_FILES`.
|
||||
* `$.cookie` — массив `$_COOKIE`.
|
||||
* `$.server` — массив `$_SERVER`.
|
||||
* `$.session` — массив `$_SESSION`.
|
||||
* `$.globals` — массив `$GLOBALS`.
|
||||
* `$.request` — массив `$_REQUEST`.
|
||||
* `$.tpl.name` возвращает текущее название шаблона.
|
||||
* `$.tpl.schema` возвращает код провайдера шаблона.
|
||||
* `$.tpl.basename` возвращает текущее название шаблона без схемы.
|
||||
* `$.tpl.scm` возвращает схему шаблона.
|
||||
* `$.tpl.options` возвращает параметры шбалона в виде целого числа.
|
||||
* `$.tpl.depends` возвращает массив шаблонов на которые ссылается текущий шаблон.
|
||||
* `$.tpl.time` возвращает штамп времени когда шаблон последний раз менялся
|
||||
* `$.version` возвращает версию Fenom.
|
||||
* `$.const` обращение к PHP константе: `$.const.PHP_EOL` .
|
||||
|
||||
```smarty
|
||||
{if $.get.debug? && $.const.DEBUG}
|
||||
...
|
||||
{/if}
|
||||
```
|
||||
* `$.const.*` обращение к PHP константе: `$.const.PHP_EOL` обращение к константе `PHP_EOL`. Поддерживается пространство имен
|
||||
которое разделяется через точку: `$.const.Storage.FS::DIR_SEPARATOR` обращение к PHP константе `Storage\FS::DIR_SEPARATOR`
|
||||
если такой констатнты нет будет взята константа `Storage\FS\DIR_SEPARATOR`.
|
||||
* `$.php.*` обращение к статическомому методу. `$.php.Storage.FS::put($filename, $data)` обращение к методу `Storage\FS::put($filename, $data)`.
|
||||
`$.php.Storage.FS.put($filename, $data)` `Storage\FS\put($filename, $data)`
|
||||
* `$.tag.*` обращение к тегу. `$.tag.mailto($filename, $data)` {mailto ""}.
|
||||
* `$.func.*`
|
||||
* `$.fetch($name, $values)`
|
||||
* `$.macro` `$.macro.math.plus` `$.macro.math.plus(...)`
|
||||
|
||||
## Скалярные значения
|
||||
|
||||
@ -307,7 +313,7 @@ NULL - это отсутствие присутствия, а FALSE - прису
|
||||
Все сущности шаблона можно разжелить на две группы:
|
||||
|
||||
* заполнитель (placeholder) — вывод переменной в шаблоне, например `{$name}`
|
||||
* тег — конструкция выполняющаяя некоторые действия, выглядит как именованный заполнитель (placeholder), например `{include $name}`
|
||||
* тег — конструкция, выполняющаяя некоторые действия, которая выглядит как именованный заполнитель (placeholder), например `{include $name}`
|
||||
|
||||
Теги так же можно разделить на две группы:
|
||||
|
||||
@ -316,6 +322,10 @@ NULL - это отсутствие присутствия, а FALSE - прису
|
||||
* Компиляторы. В отличии от функций компиляторы вызываются во время компиляции шаблона и возвращают PHP код, который описывает некоторое действие.
|
||||
Компиляторы и формируют основные конструкции типа `if`, `foreach` и т.д.
|
||||
|
||||
```
|
||||
{set $a = $.func.mailto($email)}
|
||||
```
|
||||
|
||||
### Игнорирование кода
|
||||
|
||||
В шаблонизаторе Fenom используются фигурные скобки для отделения HTML от кода Fenom.
|
||||
|
@ -17,7 +17,7 @@ use Fenom\Template;
|
||||
*/
|
||||
class Fenom
|
||||
{
|
||||
const VERSION = '2.0';
|
||||
const VERSION = '2.4';
|
||||
/* Actions */
|
||||
const INLINE_COMPILER = 1;
|
||||
const BLOCK_COMPILER = 5;
|
||||
@ -81,6 +81,11 @@ class Fenom
|
||||
*/
|
||||
public $tag_filters = array();
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $call_filters = array();
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
@ -340,6 +345,24 @@ class Fenom
|
||||
'third' => '!(%s %% 3)'
|
||||
);
|
||||
|
||||
protected $_accessors = array(
|
||||
'get' => 'Fenom\Accessor::getVar',
|
||||
'env' => 'Fenom\Accessor::getVar',
|
||||
'post' => 'Fenom\Accessor::getVar',
|
||||
'request' => 'Fenom\Accessor::getVar',
|
||||
'cookie' => 'Fenom\Accessor::getVar',
|
||||
'globals' => 'Fenom\Accessor::getVar',
|
||||
'server' => 'Fenom\Accessor::getVar',
|
||||
'session' => 'Fenom\Accessor::getVar',
|
||||
'files' => 'Fenom\Accessor::getVar',
|
||||
'tpl' => 'Fenom\Accessor::tpl',
|
||||
'version' => 'Fenom\Accessor::version',
|
||||
'const' => 'Fenom\Accessor::constant',
|
||||
'php' => 'Fenom\Accessor::php',
|
||||
'tag' => 'Fenom\Accessor::Tag',
|
||||
'fetch' => 'Fenom\Accessor::Fetch',
|
||||
);
|
||||
|
||||
/**
|
||||
* Just factory
|
||||
*
|
||||
@ -510,12 +533,7 @@ class Fenom
|
||||
* @param array $tags
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addBlockCompiler(
|
||||
$compiler,
|
||||
$open_parser,
|
||||
$close_parser = self::DEFAULT_CLOSE_COMPILER,
|
||||
array $tags = array()
|
||||
) {
|
||||
public function addBlockCompiler($compiler, $open_parser, $close_parser = self::DEFAULT_CLOSE_COMPILER, array $tags = array()) {
|
||||
$this->_actions[$compiler] = array(
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => $open_parser,
|
||||
@ -772,6 +790,53 @@ class Fenom
|
||||
return $this->_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add global accessor ($.)
|
||||
* @param string $name
|
||||
* @param callable $parser
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addAccessor($name, $parser)
|
||||
{
|
||||
$this->_accessors[$name] = $parser;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove accessor
|
||||
* @param string $name
|
||||
* @return Fenom
|
||||
*/
|
||||
public function removeAccessor($name)
|
||||
{
|
||||
unset($this->_accessors[$name]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an accessor
|
||||
* @param string $name
|
||||
* @return callable
|
||||
*/
|
||||
public function getAccessor($name) {
|
||||
if(isset($this->_accessors[$name])) {
|
||||
return $this->_accessors[$name];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add filter for $.php accessor.
|
||||
* Uses glob syntax.
|
||||
* @param string $pattern
|
||||
* @return $this
|
||||
*/
|
||||
public function addCallFilter($pattern) {
|
||||
$this->call_filters[] = $pattern;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $scm
|
||||
* @return Fenom\ProviderInterface
|
||||
|
113
src/Fenom/Accessor.php
Normal file
113
src/Fenom/Accessor.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Fenom.
|
||||
*
|
||||
* (c) 2013 Ivan Shalganov
|
||||
*
|
||||
* For the full copyright and license information, please view the license.md
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace Fenom;
|
||||
|
||||
use Fenom\Error\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* Class Accessor
|
||||
* @package Fenom
|
||||
*/
|
||||
class Accessor {
|
||||
public static $vars = array(
|
||||
'get' => '$_GET',
|
||||
'post' => '$_POST',
|
||||
'session' => '$_SESSION',
|
||||
'cookie' => '$_COOKIE',
|
||||
'request' => '$_REQUEST',
|
||||
'files' => '$_FILES',
|
||||
'globals' => '$GLOBALS',
|
||||
'server' => '$_SERVER',
|
||||
'env' => '$_ENV'
|
||||
);
|
||||
|
||||
/**
|
||||
* Accessor for global variables
|
||||
* @param Tokenizer $tokens
|
||||
* @param Template $tpl
|
||||
*/
|
||||
public static function getVar(Tokenizer $tokens, Template $tpl) {
|
||||
$name = $tokens->prev[Tokenizer::TEXT];
|
||||
if(isset(self::$vars[$name])) {
|
||||
$var = $tpl->parseVariable($tokens, self::$vars[$name]);
|
||||
return "(isset($var) ? $var : null)";
|
||||
} else {
|
||||
throw new UnexpectedTokenException($tokens->back());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for template information
|
||||
* @param Tokenizer $tokens
|
||||
*/
|
||||
public static function tpl(Tokenizer $tokens) {
|
||||
$method = $tokens->skip('.')->need(T_STRING)->getAndNext();
|
||||
if(method_exists('Fenom\Render', 'get'.$method)) {
|
||||
return '$tpl->get'.ucfirst($method).'()';
|
||||
} else {
|
||||
throw new UnexpectedTokenException($tokens->back());
|
||||
}
|
||||
}
|
||||
|
||||
public static function version() {
|
||||
return 'Fenom::VERSION';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tokenizer $tokens
|
||||
* @return string
|
||||
*/
|
||||
public static function constant(Tokenizer $tokens) {
|
||||
$const = [$tokens->skip('.')->need(Tokenizer::MACRO_STRING)->getAndNext()];
|
||||
while($tokens->is('.')) {
|
||||
$const[] = $tokens->next()->need(Tokenizer::MACRO_STRING)->getAndNext();
|
||||
}
|
||||
$const = implode('\\', $const);
|
||||
if($tokens->is(T_DOUBLE_COLON)) {
|
||||
$const .= '::'.$tokens->next()->need(Tokenizer::MACRO_STRING)->getAndNext();
|
||||
}
|
||||
return '@constant('.var_export($const, true).')';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tokenizer $tokens
|
||||
* @param Template $tpl
|
||||
* @return string
|
||||
*/
|
||||
public static function php(Tokenizer $tokens, Template $tpl) {
|
||||
$callable = [$tokens->skip('.')->need(Tokenizer::MACRO_STRING)->getAndNext()];
|
||||
while($tokens->is('.')) {
|
||||
$callable[] = $tokens->next()->need(Tokenizer::MACRO_STRING)->getAndNext();
|
||||
}
|
||||
$callable = implode('\\', $callable);
|
||||
if($tokens->is(T_DOUBLE_COLON)) {
|
||||
$callable .= '::'.$tokens->next()->need(Tokenizer::MACRO_STRING)->getAndNext();
|
||||
}
|
||||
if(!is_callable($callable)) {
|
||||
throw new \LogicException("PHP method ".str_replace('\\', '.', $callable).' does not exists.');
|
||||
}
|
||||
if($tokens->is('(')) {
|
||||
$arguments = 'array'.$tpl->parseArgs($tokens).'';
|
||||
} else {
|
||||
$arguments = 'array()';
|
||||
}
|
||||
return 'call_user_func_array('.var_export($callable, true).', '.$arguments.')';
|
||||
|
||||
}
|
||||
|
||||
public static function tag(Tokenizer $tokens, Template $tpl) {
|
||||
$tag = $tokens->get(Tokenizer::MACRO_STRING);
|
||||
$info = $tpl->getStorage()->getTag($tag, $tpl);
|
||||
if($info['type'] !== \Fenom::INLINE_FUNCTION) {
|
||||
throw new \LogicException("Only inline functions allowed in accessor");
|
||||
}
|
||||
}
|
||||
}
|
@ -90,8 +90,7 @@ class Render extends \ArrayObject
|
||||
$this->_time = $props["time"];
|
||||
$this->_depends = $props["depends"];
|
||||
$this->_macros = $props["macros"];
|
||||
// $this->_blocks = $props["blocks"];
|
||||
$this->_code = $code;
|
||||
$this->_code = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,19 +248,6 @@ class Render extends \ArrayObject
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name == 'info') {
|
||||
return array(
|
||||
'name' => $this->_name,
|
||||
'schema' => $this->_scm,
|
||||
'time' => $this->_time
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return $name == 'info';
|
||||
return $this->$name = null;
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +268,7 @@ class Template extends Render
|
||||
throw new CompileException("Unclosed tag" . (count($_names) > 1 ? "s" : "") . ": " . implode(
|
||||
", ",
|
||||
$_names
|
||||
), 0, 1, $this->_name, $scope->line); // $scope already defined there!
|
||||
), 0, 1, $this->_name, $scope->line); // for PHPStorm: $scope already defined there!
|
||||
}
|
||||
$this->_src = ""; // cleanup
|
||||
if ($this->_post) {
|
||||
@ -662,7 +662,7 @@ class Template extends Render
|
||||
// parse term
|
||||
$term = $this->parseTerm($tokens, $var); // term of the expression
|
||||
if ($term !== false) {
|
||||
if ($this->_options & Fenom::FORCE_VERIFY) {
|
||||
if ($var && ($this->_options & Fenom::FORCE_VERIFY)) {
|
||||
$term = '(isset(' . $term . ') ? ' . $term . ' : null)';
|
||||
$var = false;
|
||||
}
|
||||
@ -728,6 +728,10 @@ class Template extends Render
|
||||
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
||||
$concat[] = "strval(" . $this->parseTerm($tokens) . ")";
|
||||
} else {
|
||||
if($tokens->is('~')) {
|
||||
$tokens->next();
|
||||
$concat[] = " ";
|
||||
}
|
||||
if(!$concat[] = $this->parseTerm($tokens)) {
|
||||
throw new UnexpectedTokenException($tokens);
|
||||
}
|
||||
@ -788,7 +792,8 @@ class Template extends Render
|
||||
}
|
||||
return $code;
|
||||
} elseif ($tokens->is('$')) {
|
||||
$var = $this->parseAccessor($tokens, $is_var);
|
||||
$is_var = false;
|
||||
$var = $this->parseAccessor($tokens);
|
||||
return $unary . $var;
|
||||
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||
return $unary . $tokens->getAndNext() . $this->parseVariable($tokens);
|
||||
@ -913,44 +918,18 @@ class Template extends Render
|
||||
|
||||
/**
|
||||
* Parse accessor
|
||||
* @param Tokenizer $tokens
|
||||
* @return string
|
||||
*/
|
||||
public function parseAccessor(Tokenizer $tokens, &$is_var)
|
||||
public function parseAccessor(Tokenizer $tokens)
|
||||
{
|
||||
$is_var = false;
|
||||
$vars = array(
|
||||
'get' => '$_GET',
|
||||
'post' => '$_POST',
|
||||
'session' => '$_SESSION',
|
||||
'cookie' => '$_COOKIE',
|
||||
'request' => '$_REQUEST',
|
||||
'files' => '$_FILES',
|
||||
'globals' => '$GLOBALS',
|
||||
'server' => '$_SERVER',
|
||||
'env' => '$_ENV',
|
||||
'tpl' => '$tpl->info'
|
||||
);
|
||||
if ($this->_options & Fenom::DENY_ACCESSOR) {
|
||||
throw new \LogicException("Accessor are disabled");
|
||||
$accessor = $tokens->need('$')->next()->need('.')->next()->current();
|
||||
$callback = $this->getStorage()->getAccessor($accessor);
|
||||
if($callback) {
|
||||
return call_user_func($callback, $tokens->next(), $this);
|
||||
} else {
|
||||
throw new \RuntimeException("Unknown accessor '$accessor'");
|
||||
}
|
||||
$key = $tokens->need('$')->next()->need('.')->next()->current();
|
||||
$tokens->next();
|
||||
if (isset($vars[$key])) {
|
||||
$is_var = true;
|
||||
return $this->parseVariable($tokens, $vars[$key]);
|
||||
}
|
||||
switch ($key) {
|
||||
case 'const':
|
||||
$tokens->need('.')->next();
|
||||
$var = '@constant(' . var_export($this->parseName($tokens), true) . ')';
|
||||
break;
|
||||
case 'version':
|
||||
$var = '\Fenom::VERSION';
|
||||
break;
|
||||
default:
|
||||
throw new UnexpectedTokenException($tokens->back());
|
||||
}
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,17 +11,6 @@ namespace Fenom;
|
||||
|
||||
use Fenom\Error\UnexpectedTokenException;
|
||||
|
||||
/**
|
||||
* for PHP <5.4 compatible
|
||||
*/
|
||||
defined('T_INSTEADOF') || define('T_INSTEADOF', 341);
|
||||
defined('T_TRAIT') || define('T_TRAIT', 355);
|
||||
defined('T_TRAIT_C') || define('T_TRAIT_C', 365);
|
||||
/**
|
||||
* for PHP <5.5 compatible
|
||||
*/
|
||||
defined('T_YIELD') || define('T_YIELD', 267);
|
||||
|
||||
/**
|
||||
* Each token have structure
|
||||
* - Token (constant T_* or text)
|
||||
@ -93,154 +82,62 @@ class Tokenizer
|
||||
*/
|
||||
public static $macros = array(
|
||||
self::MACRO_STRING => array(
|
||||
\T_ABSTRACT => 1,
|
||||
\T_ARRAY => 1,
|
||||
\T_AS => 1,
|
||||
\T_BREAK => 1,
|
||||
\T_BREAK => 1,
|
||||
\T_CASE => 1,
|
||||
\T_CATCH => 1,
|
||||
\T_CLASS => 1,
|
||||
\T_CLASS_C => 1,
|
||||
\T_CLONE => 1,
|
||||
\T_CONST => 1,
|
||||
\T_CONTINUE => 1,
|
||||
\T_DECLARE => 1,
|
||||
\T_DEFAULT => 1,
|
||||
\T_DIR => 1,
|
||||
\T_DO => 1,
|
||||
\T_ECHO => 1,
|
||||
\T_ELSE => 1,
|
||||
\T_ELSEIF => 1,
|
||||
\T_EMPTY => 1,
|
||||
\T_ENDDECLARE => 1,
|
||||
\T_ENDFOR => 1,
|
||||
\T_ENDFOREACH => 1,
|
||||
\T_ENDIF => 1,
|
||||
\T_ENDSWITCH => 1,
|
||||
\T_ENDWHILE => 1,
|
||||
\T_EVAL => 1,
|
||||
\T_EXIT => 1,
|
||||
\T_EXTENDS => 1,
|
||||
\T_FILE => 1,
|
||||
\T_FINAL => 1,
|
||||
\T_FOR => 1,
|
||||
\T_FOREACH => 1,
|
||||
\T_FUNCTION => 1,
|
||||
\T_FUNC_C => 1,
|
||||
\T_GLOBAL => 1,
|
||||
\T_GOTO => 1,
|
||||
\T_HALT_COMPILER => 1,
|
||||
\T_IF => 1,
|
||||
\T_IMPLEMENTS => 1,
|
||||
\T_INCLUDE => 1,
|
||||
\T_INCLUDE_ONCE => 1,
|
||||
\T_INSTANCEOF => 1,
|
||||
\T_INSTEADOF => 1,
|
||||
\T_INTERFACE => 1,
|
||||
\T_ISSET => 1,
|
||||
\T_LINE => 1,
|
||||
\T_LIST => 1,
|
||||
\T_LOGICAL_AND => 1,
|
||||
\T_LOGICAL_OR => 1,
|
||||
\T_LOGICAL_XOR => 1,
|
||||
\T_METHOD_C => 1,
|
||||
\T_NAMESPACE => 1,
|
||||
\T_NS_C => 1,
|
||||
\T_NEW => 1,
|
||||
\T_PRINT => 1,
|
||||
\T_PRIVATE => 1,
|
||||
\T_PUBLIC => 1,
|
||||
\T_PROTECTED => 1,
|
||||
\T_REQUIRE => 1,
|
||||
\T_REQUIRE_ONCE => 1,
|
||||
\T_RETURN => 1,
|
||||
\T_RETURN => 1,
|
||||
\T_STRING => 1,
|
||||
\T_SWITCH => 1,
|
||||
\T_THROW => 1,
|
||||
\T_TRAIT => 1,
|
||||
\T_TRAIT_C => 1,
|
||||
\T_TRY => 1,
|
||||
\T_UNSET => 1,
|
||||
\T_USE => 1,
|
||||
\T_VAR => 1,
|
||||
\T_WHILE => 1,
|
||||
\T_YIELD => 1
|
||||
\T_ABSTRACT => 1, \T_ARRAY => 1, \T_AS => 1, \T_BREAK => 1,
|
||||
\T_BREAK => 1, \T_CASE => 1, \T_CATCH => 1, \T_CLASS => 1,
|
||||
\T_CLASS_C => 1, \T_CLONE => 1, \T_CONST => 1, \T_CONTINUE => 1,
|
||||
\T_DECLARE => 1, \T_DEFAULT => 1, \T_DIR => 1, \T_DO => 1,
|
||||
\T_ECHO => 1, \T_ELSE => 1, \T_ELSEIF => 1, \T_EMPTY => 1,
|
||||
\T_ENDDECLARE => 1, \T_ENDFOR => 1, \T_ENDFOREACH => 1, \T_ENDIF => 1,
|
||||
\T_ENDSWITCH => 1, \T_ENDWHILE => 1, \T_EVAL => 1, \T_EXIT => 1,
|
||||
\T_EXTENDS => 1, \T_FILE => 1, \T_FINAL => 1, \T_FOR => 1,
|
||||
\T_FOREACH => 1, \T_FUNCTION => 1, \T_FUNC_C => 1, \T_GLOBAL => 1,
|
||||
\T_GOTO => 1, \T_HALT_COMPILER => 1, \T_IF => 1, \T_IMPLEMENTS => 1,
|
||||
\T_INCLUDE => 1, \T_INCLUDE_ONCE => 1, \T_INSTANCEOF => 1, 341 /* T_INSTEADOF */ => 1,
|
||||
\T_INTERFACE => 1, \T_ISSET => 1, \T_LINE => 1, \T_LIST => 1,
|
||||
\T_LOGICAL_AND => 1, \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_METHOD_C => 1,
|
||||
\T_NAMESPACE => 1, \T_NS_C => 1, \T_NEW => 1, \T_PRINT => 1,
|
||||
\T_PRIVATE => 1, \T_PUBLIC => 1, \T_PROTECTED => 1, \T_REQUIRE => 1,
|
||||
\T_REQUIRE_ONCE => 1, \T_RETURN => 1, \T_RETURN => 1, \T_STRING => 1,
|
||||
\T_SWITCH => 1, \T_THROW => 1, 355 /* T_TRAIT */ => 1, 365 /* T_TRAIT_C */ => 1,
|
||||
\T_TRY => 1, \T_UNSET => 1, \T_USE => 1, \T_VAR => 1,
|
||||
\T_WHILE => 1, 267 /* T_YIELD */ => 1
|
||||
),
|
||||
self::MACRO_INCDEC => array(
|
||||
\T_INC => 1,
|
||||
\T_DEC => 1
|
||||
\T_INC => 1, \T_DEC => 1
|
||||
),
|
||||
self::MACRO_UNARY => array(
|
||||
"!" => 1,
|
||||
"~" => 1,
|
||||
"-" => 1
|
||||
"!" => 1, "~" => 1, "-" => 1
|
||||
),
|
||||
self::MACRO_BINARY => array(
|
||||
\T_BOOLEAN_AND => 1,
|
||||
\T_BOOLEAN_OR => 1,
|
||||
\T_IS_GREATER_OR_EQUAL => 1,
|
||||
\T_IS_EQUAL => 1,
|
||||
\T_IS_IDENTICAL => 1,
|
||||
\T_IS_NOT_EQUAL => 1,
|
||||
\T_IS_NOT_IDENTICAL => 1,
|
||||
\T_IS_SMALLER_OR_EQUAL => 1,
|
||||
\T_LOGICAL_AND => 1,
|
||||
\T_LOGICAL_OR => 1,
|
||||
\T_LOGICAL_XOR => 1,
|
||||
\T_SL => 1,
|
||||
\T_SR => 1,
|
||||
"+" => 1,
|
||||
"-" => 1,
|
||||
"*" => 1,
|
||||
"/" => 1,
|
||||
">" => 1,
|
||||
"<" => 1,
|
||||
"^" => 1,
|
||||
"%" => 1,
|
||||
\T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1, \T_IS_GREATER_OR_EQUAL => 1,
|
||||
\T_IS_EQUAL => 1, \T_IS_IDENTICAL => 1, \T_IS_NOT_EQUAL => 1,
|
||||
\T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1, \T_LOGICAL_AND => 1,
|
||||
\T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_SL => 1,
|
||||
\T_SR => 1, "+" => 1, "-" => 1,
|
||||
"*" => 1, "/" => 1, ">" => 1,
|
||||
"<" => 1, "^" => 1, "%" => 1,
|
||||
"&" => 1
|
||||
),
|
||||
self::MACRO_BOOLEAN => array(
|
||||
\T_LOGICAL_OR => 1,
|
||||
\T_LOGICAL_XOR => 1,
|
||||
\T_BOOLEAN_AND => 1,
|
||||
\T_BOOLEAN_OR => 1,
|
||||
\T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1,
|
||||
\T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1,
|
||||
\T_LOGICAL_AND => 1
|
||||
),
|
||||
self::MACRO_MATH => array(
|
||||
"+" => 1,
|
||||
"-" => 1,
|
||||
"*" => 1,
|
||||
"/" => 1,
|
||||
"^" => 1,
|
||||
"%" => 1,
|
||||
"&" => 1,
|
||||
"|" => 1
|
||||
"+" => 1, "-" => 1, "*" => 1,
|
||||
"/" => 1, "^" => 1, "%" => 1,
|
||||
"&" => 1, "|" => 1
|
||||
),
|
||||
self::MACRO_COND => array(
|
||||
\T_IS_EQUAL => 1,
|
||||
\T_IS_IDENTICAL => 1,
|
||||
">" => 1,
|
||||
"<" => 1,
|
||||
\T_SL => 1,
|
||||
\T_SR => 1,
|
||||
\T_IS_NOT_EQUAL => 1,
|
||||
\T_IS_NOT_IDENTICAL => 1,
|
||||
\T_IS_SMALLER_OR_EQUAL => 1,
|
||||
\T_IS_EQUAL => 1, \T_IS_IDENTICAL => 1, ">" => 1,
|
||||
"<" => 1, \T_SL => 1, \T_SR => 1,
|
||||
\T_IS_NOT_EQUAL => 1, \T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1,
|
||||
),
|
||||
self::MACRO_EQUALS => array(
|
||||
\T_AND_EQUAL => 1,
|
||||
\T_DIV_EQUAL => 1,
|
||||
\T_MINUS_EQUAL => 1,
|
||||
\T_MOD_EQUAL => 1,
|
||||
\T_MUL_EQUAL => 1,
|
||||
\T_OR_EQUAL => 1,
|
||||
\T_PLUS_EQUAL => 1,
|
||||
\T_SL_EQUAL => 1,
|
||||
\T_SR_EQUAL => 1,
|
||||
\T_XOR_EQUAL => 1,
|
||||
'=' => 1,
|
||||
\T_AND_EQUAL => 1, \T_DIV_EQUAL => 1, \T_MINUS_EQUAL => 1,
|
||||
\T_MOD_EQUAL => 1, \T_MUL_EQUAL => 1, \T_OR_EQUAL => 1,
|
||||
\T_PLUS_EQUAL => 1, \T_SL_EQUAL => 1, \T_SR_EQUAL => 1,
|
||||
\T_XOR_EQUAL => 1, '=' => 1,
|
||||
),
|
||||
self::MACRO_SCALAR => array(
|
||||
\T_LNUMBER => 1,
|
||||
|
@ -276,9 +276,13 @@ class TestCase extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
}
|
||||
|
||||
const HELPER_CONSTANT = 'helper.const';
|
||||
|
||||
class Helper
|
||||
{
|
||||
|
||||
const CONSTANT = "helper.class.const";
|
||||
|
||||
public $word = 'helper';
|
||||
|
||||
public function __construct($word)
|
||||
@ -306,3 +310,7 @@ class Helper
|
||||
}
|
||||
}
|
||||
|
||||
function helper_func($string, $pad = 10) {
|
||||
return str_pad($string, $pad, ".");
|
||||
}
|
||||
|
||||
|
144
tests/cases/Fenom/AccessorTest.php
Normal file
144
tests/cases/Fenom/AccessorTest.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Fenom;
|
||||
|
||||
|
||||
class AccessorTest extends TestCase
|
||||
{
|
||||
public static function providerGetVar()
|
||||
{
|
||||
return array(
|
||||
array("get"),
|
||||
array("post"),
|
||||
array("cookie"),
|
||||
array("request"),
|
||||
array("files"),
|
||||
array("globals"),
|
||||
array("server"),
|
||||
array("session"),
|
||||
array("env"),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerGetVar
|
||||
* @backupGlobals
|
||||
* @param string $var
|
||||
*/
|
||||
public function testGetVar($var)
|
||||
{
|
||||
$_GET['one'] = 'get1';
|
||||
$_POST['one'] = 'post1';
|
||||
$_COOKIE['one'] = 'cookie1';
|
||||
$_REQUEST['one'] = 'request1';
|
||||
$_FILES['one'] = 'files1';
|
||||
$GLOBALS['one'] = 'globals1';
|
||||
$_SERVER['one'] = 'server1';
|
||||
$_SESSION['one'] = 'session1';
|
||||
$_ENV['one'] = 'env1';
|
||||
$this->exec('{$.'.$var.'.one}', self::getVars(), "{$var}1");
|
||||
$this->exec('{$.'.$var.'.undefined}', self::getVars(), "");
|
||||
}
|
||||
|
||||
public static function providerTpl()
|
||||
{
|
||||
return array(
|
||||
array("name"),
|
||||
array("scm"),
|
||||
array("basename"),
|
||||
array("options"),
|
||||
array("time"),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerTpl
|
||||
* @param string $name
|
||||
*/
|
||||
public function testTpl($name)
|
||||
{
|
||||
$this->tpl("accessor.tpl", '{$.tpl.'.$name.'}');
|
||||
$tpl = $this->fenom->setOptions(\Fenom::FORCE_VERIFY)->getTemplate('accessor.tpl');
|
||||
$this->assertSame(strval($tpl->{"get$name"}()), $tpl->fetch(self::getVars()));
|
||||
}
|
||||
|
||||
public function testVersion()
|
||||
{
|
||||
$this->assertRender('{$.version}', \Fenom::VERSION);
|
||||
}
|
||||
|
||||
public static function providerConst()
|
||||
{
|
||||
return array(
|
||||
array("$.const.PHP_VERSION_ID", PHP_VERSION_ID),
|
||||
array('$.const.UNDEFINED', ''),
|
||||
array("$.const.FENOM_RESOURCES", FENOM_RESOURCES),
|
||||
array("$.const.Fenom.HELPER_CONSTANT", HELPER_CONSTANT),
|
||||
array("$.const.Fenom.UNDEFINED", ''),
|
||||
array("$.const.Fenom::VERSION", \Fenom::VERSION),
|
||||
array("$.const.Fenom::UNDEFINED", ''),
|
||||
array("$.const.Fenom.Helper::CONSTANT", Helper::CONSTANT),
|
||||
array("$.const.Fenom.Helper::UNDEFINED", ''),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerConst
|
||||
* @param $tpl
|
||||
* @param $value
|
||||
* @group const
|
||||
*/
|
||||
public function testConst($tpl, $value)
|
||||
{
|
||||
$this->assertRender('{'.$tpl.'}', strval($value));
|
||||
}
|
||||
|
||||
|
||||
public static function providerPHP() {
|
||||
return array(
|
||||
array('$.php.strrev("string")', strrev("string")),
|
||||
array('$.php.Fenom.helper_func("string", 12)', helper_func("string", 12)),
|
||||
array('$.php.Fenom.TestCase::dots("string")', TestCase::dots("string")),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerPHP
|
||||
* @group php
|
||||
*/
|
||||
public function testPHP($tpl, $result) {
|
||||
$this->assertRender('{'.$tpl.'}', $result);
|
||||
}
|
||||
|
||||
|
||||
public static function providerAccessor()
|
||||
{
|
||||
return array(
|
||||
array('{$.get.one}', 'get1'),
|
||||
array('{$.post.one}', 'post1'),
|
||||
array('{$.request.one}', 'request1'),
|
||||
array('{$.session.one}', 'session1'),
|
||||
array('{$.files.one}', 'files1'),
|
||||
array('{$.globals.one}', 'globals1'),
|
||||
array('{$.cookie.one}', 'cookie1'),
|
||||
array('{$.server.one}', 'server1'),
|
||||
array('{"string"|append:"_":$.get.one}', 'string_get1'),
|
||||
array('{$.get.one?}', '1'),
|
||||
array('{$.get.one is set}', '1'),
|
||||
array('{$.get.two is empty}', '1'),
|
||||
array('{$.version}', \Fenom::VERSION),
|
||||
array('{$.tpl.name}', 'runtime.tpl'),
|
||||
array('{$.tpl.time}', '0'),
|
||||
array('{$.tpl.schema}', ''),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function providerAccessorInvalid()
|
||||
{
|
||||
return array(
|
||||
array('{$.nope.one}', 'Fenom\Error\CompileException', "Unexpected token 'nope'"),
|
||||
array('{$.get.one}', 'Fenom\Error\SecurityException', 'Accessor are disabled', \Fenom::DENY_ACCESSOR),
|
||||
);
|
||||
}
|
||||
}
|
@ -17,15 +17,7 @@ class TemplateTest extends TestCase
|
||||
{
|
||||
parent::setUp();
|
||||
$this->tpl('welcome.tpl', '<b>Welcome, {$username} ({$email})</b>');
|
||||
$_GET['one'] = 'get1';
|
||||
$_POST['one'] = 'post1';
|
||||
$_REQUEST['one'] = 'request1';
|
||||
$_FILES['one'] = 'files1';
|
||||
$_SERVER['one'] = 'server1';
|
||||
$_SESSION['one'] = 'session1';
|
||||
$GLOBALS['one'] = 'globals1';
|
||||
$_ENV['one'] = 'env1';
|
||||
$_COOKIE['one'] = 'cookie1';
|
||||
|
||||
}
|
||||
|
||||
public static function providerVars()
|
||||
@ -1217,40 +1209,6 @@ class TemplateTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public static function providerAccessor()
|
||||
{
|
||||
return array(
|
||||
array('{$.get.one}', 'get1'),
|
||||
array('{$.post.one}', 'post1'),
|
||||
array('{$.request.one}', 'request1'),
|
||||
array('{$.session.one}', 'session1'),
|
||||
array('{$.files.one}', 'files1'),
|
||||
array('{$.globals.one}', 'globals1'),
|
||||
array('{$.cookie.one}', 'cookie1'),
|
||||
array('{$.server.one}', 'server1'),
|
||||
array('{$.const.PHP_EOL}', PHP_EOL),
|
||||
array('{$.const.MY}', ''),
|
||||
array('{$.version}', Fenom::VERSION),
|
||||
array('{"string"|append:"_":$.get.one}', 'string_get1'),
|
||||
array('{$.get.one?}', '1'),
|
||||
array('{$.get.one is set}', '1'),
|
||||
array('{$.get.two is empty}', '1'),
|
||||
array('{$.version}', Fenom::VERSION),
|
||||
array('{$.tpl?}', '1'),
|
||||
array('{$.tpl.name}', 'runtime.tpl'),
|
||||
array('{$.tpl.time}', '0'),
|
||||
array('{$.tpl.schema}', ''),
|
||||
);
|
||||
}
|
||||
|
||||
public static function providerAccessorInvalid()
|
||||
{
|
||||
return array(
|
||||
array('{$.nope.one}', 'Fenom\Error\CompileException', "Unexpected token 'nope'"),
|
||||
array('{$.get.one}', 'Fenom\Error\SecurityException', 'Accessor are disabled', Fenom::DENY_ACCESSOR),
|
||||
);
|
||||
}
|
||||
|
||||
public function providerStatic()
|
||||
{
|
||||
return array(
|
||||
@ -1622,19 +1580,19 @@ class TemplateTest extends TestCase
|
||||
* @group accessor
|
||||
* @dataProvider providerAccessor
|
||||
*/
|
||||
public function testAccessor($code, $result)
|
||||
{
|
||||
$this->exec($code, self::getVars(), $result);
|
||||
}
|
||||
// public function testAccessor($code, $result)
|
||||
// {
|
||||
// $this->exec($code, self::getVars(), $result);
|
||||
// }
|
||||
|
||||
/**
|
||||
* @group accessor
|
||||
* @dataProvider providerAccessorInvalid
|
||||
*/
|
||||
public function testAccessorInvalid($code, $exception, $message, $options = 0)
|
||||
{
|
||||
$this->execError($code, $exception, $message, $options);
|
||||
}
|
||||
// public function testAccessorInvalid($code, $exception, $message, $options = 0)
|
||||
// {
|
||||
// $this->execError($code, $exception, $message, $options);
|
||||
// }
|
||||
|
||||
/**
|
||||
* @group static
|
||||
|
Loading…
Reference in New Issue
Block a user