mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Merge cf6bae47cb
into a10808d1f3
This commit is contained in:
commit
c8f22e206e
560
src/Fenom.php
560
src/Fenom.php
@ -7,30 +7,31 @@
|
||||
* 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
|
||||
*
|
||||
* @author Ivan Shalganov <a.cobest@gmail.com>
|
||||
*/
|
||||
class Fenom {
|
||||
class Fenom
|
||||
{
|
||||
const VERSION = '1.0';
|
||||
|
||||
/* Compiler types */
|
||||
const INLINE_COMPILER = 1;
|
||||
const BLOCK_COMPILER = 2;
|
||||
const INLINE_FUNCTION = 3;
|
||||
const BLOCK_FUNCTION = 4;
|
||||
const MODIFIER = 5;
|
||||
const INLINE_COMPILER = 1;
|
||||
const BLOCK_COMPILER = 2;
|
||||
const INLINE_FUNCTION = 3;
|
||||
const BLOCK_FUNCTION = 4;
|
||||
const MODIFIER = 5;
|
||||
|
||||
/* Options */
|
||||
const DENY_METHODS = 0x10;
|
||||
const DENY_INLINE_FUNCS = 0x20;
|
||||
const FORCE_INCLUDE = 0x40;
|
||||
const AUTO_RELOAD = 0x80;
|
||||
const FORCE_COMPILE = 0xF0;
|
||||
const DENY_METHODS = 0x10;
|
||||
const DENY_INLINE_FUNCS = 0x20;
|
||||
const FORCE_INCLUDE = 0x40;
|
||||
const AUTO_RELOAD = 0x80;
|
||||
const FORCE_COMPILE = 0xF0;
|
||||
const DISABLE_CACHE = 0x1F0;
|
||||
const AUTO_ESCAPE = 0x200;
|
||||
|
||||
@ -40,20 +41,18 @@ class Fenom {
|
||||
const DEFAULT_FUNC_OPEN = 'Fenom\Compiler::stdFuncOpen';
|
||||
const DEFAULT_FUNC_CLOSE = 'Fenom\Compiler::stdFuncClose';
|
||||
const SMART_FUNC_PARSER = 'Fenom\Compiler::smartFuncParser';
|
||||
|
||||
/**
|
||||
* @var int[] of possible options, as associative array
|
||||
* @see setOptions, addOptions, delOptions
|
||||
*/
|
||||
private static $_option_list = array(
|
||||
"disable_methods" => self::DENY_METHODS,
|
||||
"disable_methods" => self::DENY_METHODS,
|
||||
"disable_native_funcs" => self::DENY_INLINE_FUNCS,
|
||||
"disable_cache" => self::DISABLE_CACHE,
|
||||
"force_compile" => self::FORCE_COMPILE,
|
||||
"auto_reload" => self::AUTO_RELOAD,
|
||||
"force_include" => self::FORCE_INCLUDE,
|
||||
"disable_cache" => self::DISABLE_CACHE,
|
||||
"force_compile" => self::FORCE_COMPILE,
|
||||
"auto_reload" => self::AUTO_RELOAD,
|
||||
"force_include" => self::FORCE_INCLUDE,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var Fenom\Render[] Templates storage
|
||||
*/
|
||||
@ -62,25 +61,17 @@ class Fenom {
|
||||
* @var string compile directory
|
||||
*/
|
||||
protected $_compile_dir = "/tmp";
|
||||
|
||||
/**
|
||||
* @var int masked options
|
||||
*/
|
||||
protected $_options = 0;
|
||||
|
||||
protected $_on_pre_cmp = array();
|
||||
protected $_on_cmp = array();
|
||||
protected $_on_post_cmp = array();
|
||||
|
||||
/**
|
||||
* @var ProviderInterface
|
||||
*/
|
||||
private $_provider;
|
||||
/**
|
||||
* @var Fenom\ProviderInterface[]
|
||||
*/
|
||||
protected $_providers = array();
|
||||
|
||||
/**
|
||||
* @var string[] list of modifiers [modifier_name => callable]
|
||||
*/
|
||||
@ -99,136 +90,147 @@ class Fenom {
|
||||
"length" => 'Fenom\Modifier::length',
|
||||
"default" => 'Fenom\Modifier::defaultValue'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array of allowed PHP functions
|
||||
*/
|
||||
protected $_allowed_funcs = array(
|
||||
"count" => 1, "is_string" => 1, "is_array" => 1, "is_numeric" => 1, "is_int" => 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
|
||||
"ip2long" => 1, "long2ip" => 1, "strip_tags" => 1, "nl2br" => 1, "explode" => 1, "implode" => 1
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array[] of compilers and functions
|
||||
*/
|
||||
protected $_actions = array(
|
||||
'foreach' => array( // {foreach ...} {break} {continue} {foreachelse} {/foreach}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::foreachOpen',
|
||||
'close' => 'Fenom\Compiler::foreachClose',
|
||||
'tags' => array(
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::foreachOpen',
|
||||
'close' => 'Fenom\Compiler::foreachClose',
|
||||
'tags' => array(
|
||||
'foreachelse' => 'Fenom\Compiler::foreachElse',
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'continue' => 'Fenom\Compiler::tagContinue',
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'continue' => 'Fenom\Compiler::tagContinue',
|
||||
),
|
||||
'float_tags' => array('break' => 1, 'continue' => 1)
|
||||
),
|
||||
'if' => array( // {if ...} {elseif ...} {else} {/if}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::ifOpen',
|
||||
'if' => array( // {if ...} {elseif ...} {else} {/if}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::ifOpen',
|
||||
'close' => 'Fenom\Compiler::stdClose',
|
||||
'tags' => array(
|
||||
'tags' => array(
|
||||
'elseif' => 'Fenom\Compiler::tagElseIf',
|
||||
'else' => 'Fenom\Compiler::tagElse',
|
||||
'else' => 'Fenom\Compiler::tagElse',
|
||||
)
|
||||
),
|
||||
'switch' => array( // {switch ...} {case ...} {break} {default} {/switch}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::switchOpen',
|
||||
'close' => 'Fenom\Compiler::stdClose',
|
||||
'tags' => array(
|
||||
'case' => 'Fenom\Compiler::tagCase',
|
||||
'switch' => array( // {switch ...} {case ...} {break} {default} {/switch}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::switchOpen',
|
||||
'close' => 'Fenom\Compiler::stdClose',
|
||||
'tags' => array(
|
||||
'case' => 'Fenom\Compiler::tagCase',
|
||||
'default' => 'Fenom\Compiler::tagDefault',
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
),
|
||||
'float_tags' => array('break' => 1)
|
||||
),
|
||||
'for' => array( // {for ...} {break} {continue} {/for}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::forOpen',
|
||||
'close' => 'Fenom\Compiler::forClose',
|
||||
'tags' => array(
|
||||
'forelse' => 'Fenom\Compiler::forElse',
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'for' => array( // {for ...} {break} {continue} {/for}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::forOpen',
|
||||
'close' => 'Fenom\Compiler::forClose',
|
||||
'tags' => array(
|
||||
'forelse' => 'Fenom\Compiler::forElse',
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'continue' => 'Fenom\Compiler::tagContinue',
|
||||
),
|
||||
'float_tags' => array('break' => 1, 'continue' => 1)
|
||||
),
|
||||
'while' => array( // {while ...} {break} {continue} {/while}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::whileOpen',
|
||||
'close' => 'Fenom\Compiler::stdClose',
|
||||
'tags' => array(
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'while' => array( // {while ...} {break} {continue} {/while}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::whileOpen',
|
||||
'close' => 'Fenom\Compiler::stdClose',
|
||||
'tags' => array(
|
||||
'break' => 'Fenom\Compiler::tagBreak',
|
||||
'continue' => 'Fenom\Compiler::tagContinue',
|
||||
),
|
||||
'float_tags' => array('break' => 1, 'continue' => 1)
|
||||
),
|
||||
'include' => array( // {include ...}
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => 'Fenom\Compiler::tagInclude'
|
||||
),
|
||||
'var' => array( // {var ...}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::varOpen',
|
||||
'var' => array( // {var ...}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::varOpen',
|
||||
'close' => 'Fenom\Compiler::varClose'
|
||||
),
|
||||
'block' => array( // {block ...} {parent} {/block}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::tagBlockOpen',
|
||||
'close' => 'Fenom\Compiler::tagBlockClose',
|
||||
'tags' => array(
|
||||
'block' => array( // {block ...} {parent} {/block}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::tagBlockOpen',
|
||||
'close' => 'Fenom\Compiler::tagBlockClose',
|
||||
'tags' => array(
|
||||
'parent' => 'Fenom\Compiler::tagParent'
|
||||
),
|
||||
'float_tags' => array('parent' => 1)
|
||||
),
|
||||
'extends' => array( // {extends ...}
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => 'Fenom\Compiler::tagExtends'
|
||||
),
|
||||
'use' => array( // {use}
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'use' => array( // {use}
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => 'Fenom\Compiler::tagUse'
|
||||
),
|
||||
'capture' => array( // {capture ...} {/capture}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::captureOpen',
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::captureOpen',
|
||||
'close' => 'Fenom\Compiler::captureClose'
|
||||
),
|
||||
'filter' => array( // {filter} ... {/filter}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::filterOpen',
|
||||
'filter' => array( // {filter} ... {/filter}
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::filterOpen',
|
||||
'close' => 'Fenom\Compiler::filterClose'
|
||||
),
|
||||
'macro' => array(
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::macroOpen',
|
||||
'macro' => array(
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => 'Fenom\Compiler::macroOpen',
|
||||
'close' => 'Fenom\Compiler::macroClose'
|
||||
),
|
||||
'import' => array(
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'import' => array(
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => 'Fenom\Compiler::tagImport'
|
||||
),
|
||||
'cycle' => array(
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'cycle' => array(
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => 'Fenom\Compiler::tagCycle'
|
||||
)
|
||||
);
|
||||
/**
|
||||
* @var ProviderInterface
|
||||
*/
|
||||
private $_provider;
|
||||
|
||||
/**
|
||||
* @param Fenom\ProviderInterface $provider
|
||||
*/
|
||||
public function __construct(Fenom\ProviderInterface $provider)
|
||||
{
|
||||
$this->_provider = $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just factory
|
||||
*
|
||||
* @param string|Fenom\ProviderInterface $source path to templates or custom provider
|
||||
* @param string $compile_dir path to compiled files
|
||||
* @param int $options
|
||||
* @param string|Fenom\ProviderInterface $source path to templates or custom provider
|
||||
* @param string $compile_dir path to compiled files
|
||||
* @param int $options
|
||||
* @throws InvalidArgumentException
|
||||
* @return Fenom
|
||||
*/
|
||||
public static function factory($source, $compile_dir = '/tmp', $options = 0) {
|
||||
if(is_string($source)) {
|
||||
public static function factory($source, $compile_dir = '/tmp', $options = 0)
|
||||
{
|
||||
if (is_string($source)) {
|
||||
$provider = new Fenom\Provider($source);
|
||||
} elseif($source instanceof ProviderInterface) {
|
||||
} elseif ($source instanceof ProviderInterface) {
|
||||
$provider = $source;
|
||||
} else {
|
||||
throw new InvalidArgumentException("Source must be a valid path or provider object");
|
||||
@ -236,17 +238,37 @@ class Fenom {
|
||||
$fenom = new static($provider);
|
||||
/* @var Fenom $fytro */
|
||||
$fenom->setCompileDir($compile_dir);
|
||||
if($options) {
|
||||
if ($options) {
|
||||
$fenom->setOptions($options);
|
||||
}
|
||||
|
||||
return $fenom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Fenom\ProviderInterface $provider
|
||||
* Create bit-mask from associative array use fully associative array possible keys with bit values
|
||||
* @static
|
||||
* @param array $values custom assoc array, ["a" => true, "b" => false]
|
||||
* @param array $options possible values, ["a" => 0b001, "b" => 0b010, "c" => 0b100]
|
||||
* @param int $mask the initial value of the mask
|
||||
* @return int result, ( $mask | a ) & ~b
|
||||
* @throws \RuntimeException if key from custom assoc doesn't exists into possible values
|
||||
*/
|
||||
public function __construct(Fenom\ProviderInterface $provider) {
|
||||
$this->_provider = $provider;
|
||||
private static function _makeMask(array $values, array $options, $mask = 0)
|
||||
{
|
||||
foreach ($values as $value) {
|
||||
if (isset($options[$value])) {
|
||||
if ($options[$value]) {
|
||||
$mask |= $options[$value];
|
||||
} else {
|
||||
$mask &= ~$options[$value];
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException("Undefined parameter $value");
|
||||
}
|
||||
}
|
||||
|
||||
return $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,8 +277,10 @@ class Fenom {
|
||||
* @param string $dir directory to store compiled templates in
|
||||
* @return Fenom
|
||||
*/
|
||||
public function setCompileDir($dir) {
|
||||
public function setCompileDir($dir)
|
||||
{
|
||||
$this->_compile_dir = $dir;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -264,7 +288,8 @@ class Fenom {
|
||||
*
|
||||
* @param callable $cb
|
||||
*/
|
||||
public function addPreCompileFilter($cb) {
|
||||
public function addPreCompileFilter($cb)
|
||||
{
|
||||
$this->_on_pre_cmp[] = $cb;
|
||||
}
|
||||
|
||||
@ -272,14 +297,16 @@ class Fenom {
|
||||
*
|
||||
* @param callable $cb
|
||||
*/
|
||||
public function addPostCompileFilter($cb) {
|
||||
public function addPostCompileFilter($cb)
|
||||
{
|
||||
$this->_on_post_cmp[] = $cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $cb
|
||||
*/
|
||||
public function addCompileFilter($cb) {
|
||||
public function addCompileFilter($cb)
|
||||
{
|
||||
$this->_on_cmp[] = $cb;
|
||||
}
|
||||
|
||||
@ -290,141 +317,157 @@ class Fenom {
|
||||
* @param string $callback the modifier callback
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addModifier($modifier, $callback) {
|
||||
public function addModifier($modifier, $callback)
|
||||
{
|
||||
$this->_modifiers[$modifier] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add inline tag compiler
|
||||
*
|
||||
* @param string $compiler
|
||||
* @param string $compiler
|
||||
* @param callable $parser
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addCompiler($compiler, $parser) {
|
||||
public function addCompiler($compiler, $parser)
|
||||
{
|
||||
$this->_actions[$compiler] = array(
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => $parser
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $compiler
|
||||
* @param string $compiler
|
||||
* @param string|object $storage
|
||||
* @return $this
|
||||
*/
|
||||
public function addCompilerSmart($compiler, $storage) {
|
||||
if(method_exists($storage, "tag".$compiler)) {
|
||||
public function addCompilerSmart($compiler, $storage)
|
||||
{
|
||||
if (method_exists($storage, "tag" . $compiler)) {
|
||||
$this->_actions[$compiler] = array(
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => array($storage, "tag".$compiler)
|
||||
'type' => self::INLINE_COMPILER,
|
||||
'parser' => array($storage, "tag" . $compiler)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add block compiler
|
||||
*
|
||||
* @param string $compiler
|
||||
* @param callable $open_parser
|
||||
* @param string $compiler
|
||||
* @param callable $open_parser
|
||||
* @param callable|string $close_parser
|
||||
* @param array $tags
|
||||
* @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,
|
||||
'close' => $close_parser ?: self::DEFAULT_CLOSE_COMPILER,
|
||||
'tags' => $tags,
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
'open' => $open_parser,
|
||||
'close' => $close_parser ? : self::DEFAULT_CLOSE_COMPILER,
|
||||
'tags' => $tags,
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $compiler
|
||||
* @param $storage
|
||||
* @param $compiler
|
||||
* @param $storage
|
||||
* @param array $tags
|
||||
* @param array $floats
|
||||
* @throws LogicException
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addBlockCompilerSmart($compiler, $storage, array $tags, array $floats = array()) {
|
||||
public function addBlockCompilerSmart($compiler, $storage, array $tags, array $floats = array())
|
||||
{
|
||||
$c = array(
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
"tags" => array(),
|
||||
'type' => self::BLOCK_COMPILER,
|
||||
"tags" => array(),
|
||||
"float_tags" => array()
|
||||
);
|
||||
if(method_exists($storage, $compiler."Open")) {
|
||||
$c["open"] = $compiler."Open";
|
||||
if (method_exists($storage, $compiler . "Open")) {
|
||||
$c["open"] = $compiler . "Open";
|
||||
} else {
|
||||
throw new \LogicException("Open compiler {$compiler}Open not found");
|
||||
}
|
||||
if(method_exists($storage, $compiler."Close")) {
|
||||
$c["close"] = $compiler."Close";
|
||||
if (method_exists($storage, $compiler . "Close")) {
|
||||
$c["close"] = $compiler . "Close";
|
||||
} else {
|
||||
throw new \LogicException("Close compiler {$compiler}Close not found");
|
||||
}
|
||||
foreach($tags as $tag) {
|
||||
if(method_exists($storage, "tag".$tag)) {
|
||||
$c["tags"][ $tag ] = "tag".$tag;
|
||||
if($floats && in_array($tag, $floats)) {
|
||||
$c['float_tags'][ $tag ] = 1;
|
||||
foreach ($tags as $tag) {
|
||||
if (method_exists($storage, "tag" . $tag)) {
|
||||
$c["tags"][$tag] = "tag" . $tag;
|
||||
if ($floats && in_array($tag, $floats)) {
|
||||
$c['float_tags'][$tag] = 1;
|
||||
}
|
||||
} else {
|
||||
throw new \LogicException("Tag compiler $tag (tag{$compiler}) not found");
|
||||
}
|
||||
}
|
||||
$this->_actions[$compiler] = $c;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $function
|
||||
* @param callable $callback
|
||||
* @param string $function
|
||||
* @param callable $callback
|
||||
* @param callable|string $parser
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addFunction($function, $callback, $parser = self::DEFAULT_FUNC_PARSER) {
|
||||
public function addFunction($function, $callback, $parser = self::DEFAULT_FUNC_PARSER)
|
||||
{
|
||||
$this->_actions[$function] = array(
|
||||
'type' => self::INLINE_FUNCTION,
|
||||
'parser' => $parser,
|
||||
'type' => self::INLINE_FUNCTION,
|
||||
'parser' => $parser,
|
||||
'function' => $callback,
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $function
|
||||
* @param string $function
|
||||
* @param callable $callback
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addFunctionSmart($function, $callback) {
|
||||
public function addFunctionSmart($function, $callback)
|
||||
{
|
||||
$this->_actions[$function] = array(
|
||||
'type' => self::INLINE_FUNCTION,
|
||||
'parser' => self::SMART_FUNC_PARSER,
|
||||
'type' => self::INLINE_FUNCTION,
|
||||
'parser' => self::SMART_FUNC_PARSER,
|
||||
'function' => $callback,
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $function
|
||||
* @param callable $callback
|
||||
* @param string $function
|
||||
* @param callable $callback
|
||||
* @param callable|string $parser_open
|
||||
* @param callable|string $parser_close
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addBlockFunction($function, $callback, $parser_open = self::DEFAULT_FUNC_OPEN, $parser_close = self::DEFAULT_FUNC_CLOSE) {
|
||||
public function addBlockFunction($function, $callback, $parser_open = self::DEFAULT_FUNC_OPEN, $parser_close = self::DEFAULT_FUNC_CLOSE)
|
||||
{
|
||||
$this->_actions[$function] = array(
|
||||
'type' => self::BLOCK_FUNCTION,
|
||||
'open' => $parser_open,
|
||||
'close' => $parser_close,
|
||||
'function' => $callback,
|
||||
'type' => self::BLOCK_FUNCTION,
|
||||
'open' => $parser_open,
|
||||
'close' => $parser_close,
|
||||
'function' => $callback,
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -432,8 +475,10 @@ class Fenom {
|
||||
* @param array $funcs
|
||||
* @return Fenom
|
||||
*/
|
||||
public function addAllowedFunctions(array $funcs) {
|
||||
public function addAllowedFunctions(array $funcs)
|
||||
{
|
||||
$this->_allowed_funcs = $this->_allowed_funcs + array_flip($funcs);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -444,10 +489,11 @@ class Fenom {
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getModifier($modifier) {
|
||||
if(isset($this->_modifiers[$modifier])) {
|
||||
public function getModifier($modifier)
|
||||
{
|
||||
if (isset($this->_modifiers[$modifier])) {
|
||||
return $this->_modifiers[$modifier];
|
||||
} elseif($this->isAllowedFunction($modifier)) {
|
||||
} elseif ($this->isAllowedFunction($modifier)) {
|
||||
return $modifier;
|
||||
} else {
|
||||
throw new \Exception("Modifier $modifier not found");
|
||||
@ -460,8 +506,9 @@ class Fenom {
|
||||
* @param string $function
|
||||
* @return string|bool
|
||||
*/
|
||||
public function getFunction($function) {
|
||||
if(isset($this->_actions[$function])) {
|
||||
public function getFunction($function)
|
||||
{
|
||||
if (isset($this->_actions[$function])) {
|
||||
return $this->_actions[$function];
|
||||
} else {
|
||||
return false;
|
||||
@ -472,8 +519,9 @@ class Fenom {
|
||||
* @param string $function
|
||||
* @return bool
|
||||
*/
|
||||
public function isAllowedFunction($function) {
|
||||
if($this->_options & self::DENY_INLINE_FUNCS) {
|
||||
public function isAllowedFunction($function)
|
||||
{
|
||||
if ($this->_options & self::DENY_INLINE_FUNCS) {
|
||||
return isset($this->_allowed_funcs[$function]);
|
||||
} else {
|
||||
return is_callable($function);
|
||||
@ -484,26 +532,38 @@ class Fenom {
|
||||
* @param string $tag
|
||||
* @return array
|
||||
*/
|
||||
public function getTagOwners($tag) {
|
||||
public function getTagOwners($tag)
|
||||
{
|
||||
$tags = array();
|
||||
foreach($this->_actions as $owner => $params) {
|
||||
if(isset($params["tags"][$tag])) {
|
||||
foreach ($this->_actions as $owner => $params) {
|
||||
if (isset($params["tags"][$tag])) {
|
||||
$tags[] = $owner;
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add source template provider by scheme
|
||||
*
|
||||
* @param string $scm scheme name
|
||||
* @param string $scm scheme name
|
||||
* @param Fenom\ProviderInterface $provider provider object
|
||||
*/
|
||||
public function addProvider($scm, \Fenom\ProviderInterface $provider) {
|
||||
public function addProvider($scm, \Fenom\ProviderInterface $provider)
|
||||
{
|
||||
$this->_providers[$scm] = $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options as bits
|
||||
* @return int
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options. May be bitwise mask of constants DENY_METHODS, DENY_INLINE_FUNCS, DENY_SET_VARS, INCLUDE_SOURCES,
|
||||
* FORCE_COMPILE, CHECK_MTIME, or associative array with boolean values:
|
||||
@ -513,30 +573,24 @@ class Fenom {
|
||||
* compile_check - check template modifications (slow!)
|
||||
* @param int|array $options
|
||||
*/
|
||||
public function setOptions($options) {
|
||||
if(is_array($options)) {
|
||||
public function setOptions($options)
|
||||
{
|
||||
if (is_array($options)) {
|
||||
$options = self::_makeMask($options, self::$_option_list);
|
||||
}
|
||||
$this->_storage = array();
|
||||
$this->_options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options as bits
|
||||
* @return int
|
||||
*/
|
||||
public function getOptions() {
|
||||
return $this->_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|string $scm
|
||||
* @return Fenom\ProviderInterface
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function getProvider($scm = false) {
|
||||
if($scm) {
|
||||
if(isset($this->_providers[$scm])) {
|
||||
public function getProvider($scm = false)
|
||||
{
|
||||
if ($scm) {
|
||||
if (isset($this->_providers[$scm])) {
|
||||
return $this->_providers[$scm];
|
||||
} else {
|
||||
throw new InvalidArgumentException("Provider for '$scm' not found");
|
||||
@ -551,7 +605,8 @@ class Fenom {
|
||||
*
|
||||
* @return Fenom\Template
|
||||
*/
|
||||
public function getRawTemplate() {
|
||||
public function getRawTemplate()
|
||||
{
|
||||
return new \Fenom\Template($this, $this->_options);
|
||||
}
|
||||
|
||||
@ -559,20 +614,22 @@ class Fenom {
|
||||
* Execute template and write result into stdout
|
||||
*
|
||||
* @param string $template name of template
|
||||
* @param array $vars array of data for template
|
||||
* @param array $vars array of data for template
|
||||
* @return Fenom\Render
|
||||
*/
|
||||
public function display($template, array $vars = array()) {
|
||||
public function display($template, array $vars = array())
|
||||
{
|
||||
return $this->getTemplate($template)->display($vars);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $template name of template
|
||||
* @param array $vars array of data for template
|
||||
* @param array $vars array of data for template
|
||||
* @return mixed
|
||||
*/
|
||||
public function fetch($template, array $vars = array()) {
|
||||
public function fetch($template, array $vars = array())
|
||||
{
|
||||
return $this->getTemplate($template)->fetch($vars);
|
||||
}
|
||||
|
||||
@ -580,13 +637,14 @@ class Fenom {
|
||||
*
|
||||
*
|
||||
* @param string $template name of template
|
||||
* @param array $vars
|
||||
* @param $callback
|
||||
* @param float $chunk
|
||||
* @param array $vars
|
||||
* @param $callback
|
||||
* @param float $chunk
|
||||
* @return \Fenom\Render
|
||||
* @example $fenom->pipe("products.yml.tpl", $iterators, [new SplFileObject("/tmp/products.yml"), "fwrite"], 512*1024)
|
||||
*/
|
||||
public function pipe($template, array $vars, $callback, $chunk = 1e6) {
|
||||
public function pipe($template, array $vars, $callback, $chunk = 1e6)
|
||||
{
|
||||
ob_start($callback, $chunk, true);
|
||||
$this->getTemplate($template)->display($vars);
|
||||
ob_end_flush();
|
||||
@ -597,23 +655,24 @@ class Fenom {
|
||||
* Get template by name
|
||||
*
|
||||
* @param string $template template name with schema
|
||||
* @param int $options additional options and flags
|
||||
* @param int $options additional options and flags
|
||||
* @return Fenom\Template
|
||||
*/
|
||||
public function getTemplate($template, $options = 0) {
|
||||
$key = dechex($this->_options | $options)."@".$template;
|
||||
if(isset($this->_storage[ $key ])) {
|
||||
/** @var Fenom\Template $tpl */
|
||||
$tpl = $this->_storage[ $key ];
|
||||
if(($this->_options & self::AUTO_RELOAD) && !$tpl->isValid()) {
|
||||
return $this->_storage[ $key ] = $this->compile($template, true, $options);
|
||||
public function getTemplate($template, $options = 0)
|
||||
{
|
||||
$key = dechex($this->_options | $options) . "@" . $template;
|
||||
if (isset($this->_storage[$key])) {
|
||||
/** @var Fenom\Template $tpl */
|
||||
$tpl = $this->_storage[$key];
|
||||
if (($this->_options & self::AUTO_RELOAD) && !$tpl->isValid()) {
|
||||
return $this->_storage[$key] = $this->compile($template, true, $options);
|
||||
} else {
|
||||
return $tpl;
|
||||
}
|
||||
} elseif($this->_options & self::FORCE_COMPILE) {
|
||||
} elseif ($this->_options & self::FORCE_COMPILE) {
|
||||
return $this->compile($template, $this->_options & self::DISABLE_CACHE & ~self::FORCE_COMPILE, $options);
|
||||
} else {
|
||||
return $this->_storage[ $key ] = $this->_load($template, $options);
|
||||
return $this->_storage[$key] = $this->_load($template, $options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,79 +681,55 @@ class Fenom {
|
||||
*
|
||||
* @param Fenom\Render $template
|
||||
*/
|
||||
public function addTemplate(Fenom\Render $template) {
|
||||
$this->_storage[dechex($template->getOptions()).'@'. $template->getName() ] = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load template from cache or create cache if it doesn't exists.
|
||||
*
|
||||
* @param string $tpl
|
||||
* @param int $opts
|
||||
* @return Fenom\Render
|
||||
*/
|
||||
protected function _load($tpl, $opts) {
|
||||
$file_name = $this->_getCacheName($tpl, $opts);
|
||||
if(!is_file($this->_compile_dir."/".$file_name)) {
|
||||
return $this->compile($tpl, true, $opts);
|
||||
} else {
|
||||
$fenom = $this;
|
||||
return include($this->_compile_dir."/".$file_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique name of compiled template
|
||||
*
|
||||
* @param string $tpl
|
||||
* @param int $options
|
||||
* @return string
|
||||
*/
|
||||
private function _getCacheName($tpl, $options) {
|
||||
$hash = $tpl.":".$options;
|
||||
return sprintf("%s.%x.%x.php", str_replace(":", "_", basename($tpl)), crc32($hash), strlen($hash));
|
||||
public function addTemplate(Fenom\Render $template)
|
||||
{
|
||||
$this->_storage[dechex($template->getOptions()) . '@' . $template->getName()] = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and save template
|
||||
*
|
||||
* @param string $tpl
|
||||
* @param bool $store store template on disk
|
||||
* @param int $options
|
||||
* @param bool $store store template on disk
|
||||
* @param int $options
|
||||
* @throws RuntimeException
|
||||
* @return \Fenom\Template
|
||||
*/
|
||||
public function compile($tpl, $store = true, $options = 0) {
|
||||
$options = $this->_options | $options;
|
||||
public function compile($tpl, $store = true, $options = 0)
|
||||
{
|
||||
$options = $this->_options | $options;
|
||||
$template = Template::factory($this, $options)->load($tpl);
|
||||
if($store) {
|
||||
$cache = $this->_getCacheName($tpl, $options);
|
||||
if ($store) {
|
||||
$cache = $this->_getCacheName($tpl, $options);
|
||||
$tpl_tmp = tempnam($this->_compile_dir, $cache);
|
||||
$tpl_fp = fopen($tpl_tmp, "w");
|
||||
if(!$tpl_fp) {
|
||||
throw new \RuntimeException("Can't to open temporary file $tpl_tmp. Directory ".$this->_compile_dir." is writable?");
|
||||
$tpl_fp = fopen($tpl_tmp, "w");
|
||||
if (!$tpl_fp) {
|
||||
throw new \RuntimeException("Can't to open temporary file $tpl_tmp. Directory " . $this->_compile_dir . " is writable?");
|
||||
}
|
||||
fwrite($tpl_fp, $template->getTemplateCode());
|
||||
fclose($tpl_fp);
|
||||
$file_name = $this->_compile_dir."/".$cache;
|
||||
if(!rename($tpl_tmp, $file_name)) {
|
||||
$file_name = $this->_compile_dir . "/" . $cache;
|
||||
if (!rename($tpl_tmp, $file_name)) {
|
||||
throw new \RuntimeException("Can't to move $tpl_tmp to $tpl");
|
||||
}
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush internal memory template cache
|
||||
*/
|
||||
public function flush() {
|
||||
public function flush()
|
||||
{
|
||||
$this->_storage = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all compiled templates
|
||||
*/
|
||||
public function clearAllCompiles() {
|
||||
public function clearAllCompiles()
|
||||
{
|
||||
\Fenom\Provider::clean($this->_compile_dir);
|
||||
}
|
||||
|
||||
@ -705,32 +740,41 @@ class Fenom {
|
||||
* @param string $name
|
||||
* @return Fenom\Template
|
||||
*/
|
||||
public function compileCode($code, $name = 'Runtime compile') {
|
||||
public function compileCode($code, $name = 'Runtime compile')
|
||||
{
|
||||
return Template::factory($this, $this->_options)->source($name, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load template from cache or create cache if it doesn't exists.
|
||||
*
|
||||
* @param string $tpl
|
||||
* @param int $opts
|
||||
* @return Fenom\Render
|
||||
*/
|
||||
protected function _load($tpl, $opts)
|
||||
{
|
||||
$file_name = $this->_getCacheName($tpl, $opts);
|
||||
if (!is_file($this->_compile_dir . "/" . $file_name)) {
|
||||
return $this->compile($tpl, true, $opts);
|
||||
} else {
|
||||
$fenom = $this;
|
||||
|
||||
return include($this->_compile_dir . "/" . $file_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create bit-mask from associative array use fully associative array possible keys with bit values
|
||||
* @static
|
||||
* @param array $values custom assoc array, ["a" => true, "b" => false]
|
||||
* @param array $options possible values, ["a" => 0b001, "b" => 0b010, "c" => 0b100]
|
||||
* @param int $mask the initial value of the mask
|
||||
* @return int result, ( $mask | a ) & ~b
|
||||
* @throws \RuntimeException if key from custom assoc doesn't exists into possible values
|
||||
* Generate unique name of compiled template
|
||||
*
|
||||
* @param string $tpl
|
||||
* @param int $options
|
||||
* @return string
|
||||
*/
|
||||
private static function _makeMask(array $values, array $options, $mask = 0) {
|
||||
foreach($values as $value) {
|
||||
if(isset($options[$value])) {
|
||||
if($options[$value]) {
|
||||
$mask |= $options[$value];
|
||||
} else {
|
||||
$mask &= ~$options[$value];
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException("Undefined parameter $value");
|
||||
}
|
||||
}
|
||||
return $mask;
|
||||
private function _getCacheName($tpl, $options)
|
||||
{
|
||||
$hash = $tpl . ":" . $options;
|
||||
|
||||
return sprintf("%s.%x.%x.php", str_replace(":", "_", basename($tpl)), crc32($hash), strlen($hash));
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,20 +13,24 @@ namespace Fenom;
|
||||
* Collection of modifiers
|
||||
* @author Ivan Shalganov <a.cobest@gmail.com>
|
||||
*/
|
||||
class Modifier {
|
||||
|
||||
class Modifier
|
||||
{
|
||||
/**
|
||||
* Date format
|
||||
*
|
||||
* @param string|int $date
|
||||
* @param string $format
|
||||
* @param string $format
|
||||
* @return string
|
||||
*/
|
||||
public static function dateFormat($date, $format = "%b %e, %Y") {
|
||||
if(is_string($date) && !is_numeric($date)) {
|
||||
public static function dateFormat($date, $format = "%b %e, %Y")
|
||||
{
|
||||
if (is_string($date) && !is_numeric($date)) {
|
||||
$date = strtotime($date);
|
||||
if(!$date) $date = time();
|
||||
if (!$date) {
|
||||
$date = time();
|
||||
}
|
||||
}
|
||||
|
||||
return strftime($format, $date);
|
||||
}
|
||||
|
||||
@ -35,11 +39,13 @@ class Modifier {
|
||||
* @param string $format
|
||||
* @return string
|
||||
*/
|
||||
public static function date($date, $format = "Y m d") {
|
||||
if(is_string($date) && !is_numeric($date)) {
|
||||
public static function date($date, $format = "Y m d")
|
||||
{
|
||||
if (is_string($date) && !is_numeric($date)) {
|
||||
$date = strtotime($date);
|
||||
if(!$date) $date = time();
|
||||
if (!$date) $date = time();
|
||||
}
|
||||
|
||||
return date($format, $date);
|
||||
}
|
||||
|
||||
@ -50,8 +56,9 @@ class Modifier {
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public static function escape($text, $type = 'html') {
|
||||
switch(strtolower($type)) {
|
||||
public static function escape($text, $type = 'html')
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
case "url":
|
||||
return urlencode($text);
|
||||
case "html";
|
||||
@ -68,8 +75,9 @@ class Modifier {
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public static function unescape($text, $type = 'html') {
|
||||
switch(strtolower($type)) {
|
||||
public static function unescape($text, $type = 'html')
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
case "url":
|
||||
return urldecode($text);
|
||||
case "html";
|
||||
@ -83,32 +91,34 @@ class Modifier {
|
||||
* Crop string to specific length (support unicode)
|
||||
*
|
||||
* @param string $string text witch will be truncate
|
||||
* @param int $length maximum symbols of result string
|
||||
* @param string $etc place holder truncated symbols
|
||||
* @param bool $by_words
|
||||
* @param bool $middle
|
||||
* @param int $length maximum symbols of result string
|
||||
* @param string $etc place holder truncated symbols
|
||||
* @param bool $by_words
|
||||
* @param bool $middle
|
||||
* @return string
|
||||
*/
|
||||
public static function truncate($string, $length = 80, $etc = '...', $by_words = false, $middle = false) {
|
||||
if($middle) {
|
||||
if(preg_match('#^(.{'.$length.'}).*?(.{'.$length.'})?$#usS', $string, $match)) {
|
||||
if(count($match) == 3) {
|
||||
if($by_words) {
|
||||
return preg_replace('#\s.*$#usS', "", $match[1]).$etc.preg_replace('#^.*\s#usS', "", $match[2]);
|
||||
public static function truncate($string, $length = 80, $etc = '...', $by_words = false, $middle = false)
|
||||
{
|
||||
if ($middle) {
|
||||
if (preg_match('#^(.{' . $length . '}).*?(.{' . $length . '})?$#usS', $string, $match)) {
|
||||
if (count($match) == 3) {
|
||||
if ($by_words) {
|
||||
return preg_replace('#\s.*$#usS', "", $match[1]) . $etc . preg_replace('#^.*\s#usS', "", $match[2]);
|
||||
} else {
|
||||
return $match[1].$etc.$match[2];
|
||||
return $match[1] . $etc . $match[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(preg_match('#^(.{'.$length.'})#usS', $string, $match)) {
|
||||
if($by_words) {
|
||||
return preg_replace('#\s.*$#usS', "", $match[1]).$etc;
|
||||
if (preg_match('#^(.{' . $length . '})#usS', $string, $match)) {
|
||||
if ($by_words) {
|
||||
return preg_replace('#\s.*$#usS', "", $match[1]) . $etc;
|
||||
} else {
|
||||
return $match[1].$etc;
|
||||
return $match[1] . $etc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
@ -116,12 +126,13 @@ class Modifier {
|
||||
* Strip spaces symbols on edge of string end multiple spaces in string
|
||||
*
|
||||
* @param string $str
|
||||
* @param bool $to_line strip line ends
|
||||
* @param bool $to_line strip line ends
|
||||
* @return string
|
||||
*/
|
||||
public static function strip($str, $to_line = false) {
|
||||
public static function strip($str, $to_line = false)
|
||||
{
|
||||
$str = trim($str);
|
||||
if($to_line) {
|
||||
if ($to_line) {
|
||||
return preg_replace('#[\s]+#ms', ' ', $str);
|
||||
} else {
|
||||
return preg_replace('#[ \t]{2,}#', ' ', $str);
|
||||
@ -133,12 +144,13 @@ class Modifier {
|
||||
* @param mixed $item
|
||||
* @return int
|
||||
*/
|
||||
public static function length($item) {
|
||||
if(is_string($item)) {
|
||||
public static function length($item)
|
||||
{
|
||||
if (is_string($item)) {
|
||||
return strlen(preg_replace('#[\x00-\x7F]|[\x80-\xDF][\x00-\xBF]|[\xE0-\xEF][\x00-\xBF]{2}#s', ' ', $item));
|
||||
} elseif (is_array($item)) {
|
||||
return count($item);
|
||||
} elseif($item instanceof \Countable) {
|
||||
} elseif ($item instanceof \Countable) {
|
||||
return count($item);
|
||||
} else {
|
||||
return 0;
|
||||
@ -146,15 +158,16 @@ class Modifier {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $value
|
||||
* @param $list
|
||||
* @return bool
|
||||
*/
|
||||
public static function in($value, $list) {
|
||||
if(is_array($list)) {
|
||||
public static function in($value, $list)
|
||||
{
|
||||
if (is_array($list)) {
|
||||
return in_array($value, $list);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -10,22 +10,38 @@
|
||||
namespace Fenom;
|
||||
|
||||
use Fenom\ProviderInterface;
|
||||
|
||||
/**
|
||||
* Base template provider
|
||||
* @author Ivan Shalganov
|
||||
*/
|
||||
class Provider implements ProviderInterface {
|
||||
class Provider implements ProviderInterface
|
||||
{
|
||||
private $_path;
|
||||
|
||||
/**
|
||||
* @param string $template_dir directory of templates
|
||||
* @throws \LogicException if directory doesn't exists
|
||||
*/
|
||||
public function __construct($template_dir)
|
||||
{
|
||||
if ($_dir = realpath($template_dir)) {
|
||||
$this->_path = $_dir;
|
||||
} else {
|
||||
throw new \LogicException("Template directory {$template_dir} doesn't exists");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean directory from files
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public static function clean($path) {
|
||||
if(is_file($path)) {
|
||||
public static function clean($path)
|
||||
{
|
||||
if (is_file($path)) {
|
||||
unlink($path);
|
||||
} elseif(is_dir($path)) {
|
||||
} elseif (is_dir($path)) {
|
||||
$iterator = iterator_to_array(
|
||||
new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path,
|
||||
@ -33,13 +49,13 @@ class Provider implements ProviderInterface {
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
)
|
||||
);
|
||||
foreach($iterator as $file) {
|
||||
/* @var \splFileInfo $file*/
|
||||
if($file->isFile()) {
|
||||
if(strpos($file->getBasename(), ".") !== 0) {
|
||||
foreach ($iterator as $file) {
|
||||
/* @var \splFileInfo $file */
|
||||
if ($file->isFile()) {
|
||||
if (strpos($file->getBasename(), ".") !== 0) {
|
||||
unlink($file->getRealPath());
|
||||
}
|
||||
} elseif($file->isDir()) {
|
||||
} elseif ($file->isDir()) {
|
||||
rmdir($file->getRealPath());
|
||||
}
|
||||
}
|
||||
@ -51,78 +67,61 @@ class Provider implements ProviderInterface {
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public static function rm($path) {
|
||||
public static function rm($path)
|
||||
{
|
||||
self::clean($path);
|
||||
if(is_dir($path)) {
|
||||
if (is_dir($path)) {
|
||||
rmdir($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $template_dir directory of templates
|
||||
* @throws \LogicException if directory doesn't exists
|
||||
*/
|
||||
public function __construct($template_dir) {
|
||||
if($_dir = realpath($template_dir)) {
|
||||
$this->_path = $_dir;
|
||||
} else {
|
||||
throw new \LogicException("Template directory {$template_dir} doesn't exists");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $tpl
|
||||
* @param int $time
|
||||
* @param int $time
|
||||
* @return string
|
||||
*/
|
||||
public function getSource($tpl, &$time) {
|
||||
public function getSource($tpl, &$time)
|
||||
{
|
||||
$tpl = $this->_getTemplatePath($tpl);
|
||||
clearstatcache(null, $tpl);
|
||||
$time = filemtime($tpl);
|
||||
|
||||
return file_get_contents($tpl);
|
||||
}
|
||||
|
||||
public function getLastModified($tpl) {
|
||||
public function getLastModified($tpl)
|
||||
{
|
||||
clearstatcache(null, $tpl = $this->_getTemplatePath($tpl));
|
||||
|
||||
return filemtime($tpl);
|
||||
}
|
||||
|
||||
public function getList() {
|
||||
public function getList()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template path
|
||||
* @param $tpl
|
||||
* @return string
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function _getTemplatePath($tpl) {
|
||||
if(($path = realpath($this->_path."/".$tpl)) && strpos($path, $this->_path) === 0) {
|
||||
return $path;
|
||||
} else {
|
||||
throw new \RuntimeException("Template $tpl not found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tpl
|
||||
* @return bool
|
||||
*/
|
||||
public function templateExists($tpl) {
|
||||
return file_exists($this->_path."/".$tpl);
|
||||
public function templateExists($tpl)
|
||||
{
|
||||
return file_exists($this->_path . "/" . $tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tpls
|
||||
* @return array
|
||||
*/
|
||||
public function getLastModifiedBatch($tpls) {
|
||||
public function getLastModifiedBatch($tpls)
|
||||
{
|
||||
$tpls = array_flip($tpls);
|
||||
foreach($tpls as $tpl => &$time) {
|
||||
foreach ($tpls as $tpl => &$time) {
|
||||
$time = $this->getLastModified($tpl);
|
||||
}
|
||||
|
||||
return $tpls;
|
||||
}
|
||||
|
||||
@ -132,14 +131,31 @@ class Provider implements ProviderInterface {
|
||||
* @param array $templates [template_name => modified, ...] By conversation, you may trust the template's name
|
||||
* @return bool
|
||||
*/
|
||||
public function verify(array $templates) {
|
||||
foreach($templates as $template => $mtime) {
|
||||
clearstatcache(null, $template = $this->_path.'/'.$template);
|
||||
if(@filemtime($template) !== $mtime) {
|
||||
public function verify(array $templates)
|
||||
{
|
||||
foreach ($templates as $template => $mtime) {
|
||||
clearstatcache(null, $template = $this->_path . '/' . $template);
|
||||
if (@filemtime($template) !== $mtime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template path
|
||||
* @param $tpl
|
||||
* @return string
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function _getTemplatePath($tpl)
|
||||
{
|
||||
if (($path = realpath($this->_path . "/" . $tpl)) && strpos($path, $this->_path) === 0) {
|
||||
return $path;
|
||||
} else {
|
||||
throw new \RuntimeException("Template $tpl not found");
|
||||
}
|
||||
}
|
||||
}
|
@ -11,18 +11,20 @@ namespace Fenom;
|
||||
|
||||
/**
|
||||
* Template provider interface
|
||||
* @package Fenom
|
||||
* @package Fenom
|
||||
* @author Ivan Shalganov <a.cobest@gmail.com>
|
||||
*/
|
||||
interface ProviderInterface {
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @param string $tpl
|
||||
* @return bool
|
||||
*/
|
||||
public function templateExists($tpl);
|
||||
|
||||
/**
|
||||
* @param string $tpl
|
||||
* @param int $time
|
||||
* @param int $time
|
||||
* @return string
|
||||
*/
|
||||
public function getSource($tpl, &$time);
|
||||
|
@ -8,19 +8,21 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace Fenom;
|
||||
|
||||
use Fenom;
|
||||
|
||||
/**
|
||||
* Primitive template
|
||||
* @author Ivan Shalganov <a.cobest@gmail.com>
|
||||
* @author Ivan Shalganov <a.cobest@gmail.com>
|
||||
*/
|
||||
class Render extends \ArrayObject {
|
||||
class Render extends \ArrayObject
|
||||
{
|
||||
private static $_props = array(
|
||||
"name" => "runtime",
|
||||
"name" => "runtime",
|
||||
"base_name" => "",
|
||||
"scm" => false,
|
||||
"time" => 0,
|
||||
"depends" => array()
|
||||
"scm" => false,
|
||||
"time" => 0,
|
||||
"depends" => array()
|
||||
);
|
||||
/**
|
||||
* @var \Closure
|
||||
@ -50,17 +52,14 @@ class Render extends \ArrayObject {
|
||||
* @var float
|
||||
*/
|
||||
protected $_time = 0.0;
|
||||
|
||||
/**
|
||||
* @var array depends list
|
||||
*/
|
||||
protected $_depends = array();
|
||||
|
||||
/**
|
||||
* @var int tempalte options (see Fenom options)
|
||||
*/
|
||||
protected $_options = 0;
|
||||
|
||||
/**
|
||||
* Template provider
|
||||
* @var ProviderInterface
|
||||
@ -68,53 +67,61 @@ class Render extends \ArrayObject {
|
||||
protected $_provider;
|
||||
|
||||
/**
|
||||
* @param Fenom $fenom
|
||||
* @param Fenom $fenom
|
||||
* @param callable $code template body
|
||||
* @param array $props
|
||||
* @param array $props
|
||||
*/
|
||||
public function __construct(Fenom $fenom, \Closure $code, $props = array()) {
|
||||
public function __construct(Fenom $fenom, \Closure $code, $props = array())
|
||||
{
|
||||
$this->_fenom = $fenom;
|
||||
$props += self::$_props;
|
||||
$this->_name = $props["name"];
|
||||
$this->_name = $props["name"];
|
||||
$this->_provider = $this->_fenom->getProvider($props["scm"]);
|
||||
$this->_scm = $props["scm"];
|
||||
$this->_time = $props["time"];
|
||||
$this->_depends = $props["depends"];
|
||||
$this->_code = $code;
|
||||
$this->_scm = $props["scm"];
|
||||
$this->_time = $props["time"];
|
||||
$this->_depends = $props["depends"];
|
||||
$this->_code = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template storage
|
||||
* @return Fenom
|
||||
*/
|
||||
public function getStorage() {
|
||||
public function getStorage()
|
||||
{
|
||||
return $this->_fenom;
|
||||
}
|
||||
|
||||
public function getDepends() {
|
||||
public function getDepends()
|
||||
{
|
||||
return $this->_depends;
|
||||
}
|
||||
|
||||
public function getScm() {
|
||||
public function getScm()
|
||||
{
|
||||
return $this->_scm;
|
||||
}
|
||||
|
||||
public function getProvider() {
|
||||
public function getProvider()
|
||||
{
|
||||
return $this->_provider;
|
||||
}
|
||||
|
||||
public function getBaseName() {
|
||||
public function getBaseName()
|
||||
{
|
||||
return $this->_base_name;
|
||||
}
|
||||
|
||||
public function getOptions() {
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
public function __toString()
|
||||
{
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
@ -122,29 +129,32 @@ class Render extends \ArrayObject {
|
||||
* Get template name
|
||||
* @return string
|
||||
*/
|
||||
public function getName() {
|
||||
public function getName()
|
||||
{
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
public function getTime() {
|
||||
public function getTime()
|
||||
{
|
||||
return $this->_time;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate template
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid() {
|
||||
public function isValid()
|
||||
{
|
||||
$provider = $this->_fenom->getProvider(strstr($this->_name, ":"), true);
|
||||
if($provider->getLastModified($this->_name) >= $this->_time) {
|
||||
if ($provider->getLastModified($this->_name) >= $this->_time) {
|
||||
return false;
|
||||
}
|
||||
foreach($this->_depends as $tpl => $time) {
|
||||
if($this->_fenom->getTemplate($tpl)->getTime() !== $time) {
|
||||
foreach ($this->_depends as $tpl => $time) {
|
||||
if ($this->_fenom->getTemplate($tpl)->getTime() !== $time) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -153,9 +163,11 @@ class Render extends \ArrayObject {
|
||||
* @param array $values for template
|
||||
* @return Render
|
||||
*/
|
||||
public function display(array $values) {
|
||||
public function display(array $values)
|
||||
{
|
||||
$this->exchangeArray($values);
|
||||
$this->_code->__invoke($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -165,10 +177,12 @@ class Render extends \ArrayObject {
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function fetch(array $values) {
|
||||
public function fetch(array $values)
|
||||
{
|
||||
ob_start();
|
||||
try {
|
||||
$this->display($values);
|
||||
|
||||
return ob_get_clean();
|
||||
} catch (\Exception $e) {
|
||||
ob_end_clean();
|
||||
@ -182,7 +196,8 @@ class Render extends \ArrayObject {
|
||||
* @param $args
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __call($method, $args) {
|
||||
throw new \BadMethodCallException("Unknown method ".$method);
|
||||
public function __call($method, $args)
|
||||
{
|
||||
throw new \BadMethodCallException("Unknown method " . $method);
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ namespace Fenom;
|
||||
*
|
||||
* @author Ivan Shalganov <a.cobest@gmail.com>
|
||||
*/
|
||||
class Scope extends \ArrayObject {
|
||||
|
||||
class Scope extends \ArrayObject
|
||||
{
|
||||
public $line = 0;
|
||||
public $name;
|
||||
public $level = 0;
|
||||
@ -37,15 +37,16 @@ class Scope extends \ArrayObject {
|
||||
* @param int $line
|
||||
* @param array $action
|
||||
* @param int $level
|
||||
* @param $body
|
||||
* @param $body
|
||||
*/
|
||||
public function __construct($name, $tpl, $line, $action, $level, &$body) {
|
||||
$this->line = $line;
|
||||
$this->name = $name;
|
||||
$this->tpl = $tpl;
|
||||
public function __construct($name, $tpl, $line, $action, $level, &$body)
|
||||
{
|
||||
$this->line = $line;
|
||||
$this->name = $name;
|
||||
$this->tpl = $tpl;
|
||||
$this->_action = $action;
|
||||
$this->level = $level;
|
||||
$this->_body = &$body;
|
||||
$this->level = $level;
|
||||
$this->_body = & $body;
|
||||
$this->_offset = strlen($body);
|
||||
}
|
||||
|
||||
@ -53,8 +54,9 @@ class Scope extends \ArrayObject {
|
||||
*
|
||||
* @param string $function
|
||||
*/
|
||||
public function setFuncName($function) {
|
||||
$this["function"] = $function;
|
||||
public function setFuncName($function)
|
||||
{
|
||||
$this["function"] = $function;
|
||||
$this->is_compiler = false;
|
||||
}
|
||||
|
||||
@ -64,7 +66,8 @@ class Scope extends \ArrayObject {
|
||||
* @param Tokenizer $tokenizer
|
||||
* @return mixed
|
||||
*/
|
||||
public function open($tokenizer) {
|
||||
public function open($tokenizer)
|
||||
{
|
||||
return call_user_func($this->_action["open"], $tokenizer, $this);
|
||||
}
|
||||
|
||||
@ -72,28 +75,31 @@ class Scope extends \ArrayObject {
|
||||
* Check, has the block this tag
|
||||
*
|
||||
* @param string $tag
|
||||
* @param int $level
|
||||
* @param int $level
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTag($tag, $level) {
|
||||
if(isset($this->_action["tags"][$tag])) {
|
||||
if($level) {
|
||||
public function hasTag($tag, $level)
|
||||
{
|
||||
if (isset($this->_action["tags"][$tag])) {
|
||||
if ($level) {
|
||||
return isset($this->_action["float_tags"][$tag]);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call tag callback
|
||||
*
|
||||
* @param string $tag
|
||||
* @param string $tag
|
||||
* @param Tokenizer $tokenizer
|
||||
* @return string
|
||||
*/
|
||||
public function tag($tag, $tokenizer) {
|
||||
public function tag($tag, $tokenizer)
|
||||
{
|
||||
return call_user_func($this->_action["tags"][$tag], $tokenizer, $this);
|
||||
}
|
||||
|
||||
@ -103,7 +109,8 @@ class Scope extends \ArrayObject {
|
||||
* @param Tokenizer $tokenizer
|
||||
* @return string
|
||||
*/
|
||||
public function close($tokenizer) {
|
||||
public function close($tokenizer)
|
||||
{
|
||||
return call_user_func($this->_action["close"], $tokenizer, $this);
|
||||
}
|
||||
|
||||
@ -113,7 +120,8 @@ class Scope extends \ArrayObject {
|
||||
* @throws \LogicException
|
||||
* @return string
|
||||
*/
|
||||
public function getContent() {
|
||||
public function getContent()
|
||||
{
|
||||
return substr($this->_body, $this->_offset);
|
||||
}
|
||||
|
||||
@ -123,9 +131,11 @@ class Scope extends \ArrayObject {
|
||||
* @return string
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function cutContent() {
|
||||
$content = substr($this->_body, $this->_offset + 1);
|
||||
public function cutContent()
|
||||
{
|
||||
$content = substr($this->_body, $this->_offset + 1);
|
||||
$this->_body = substr($this->_body, 0, $this->_offset);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
@ -134,7 +144,8 @@ class Scope extends \ArrayObject {
|
||||
*
|
||||
* @param $new_content
|
||||
*/
|
||||
public function replaceContent($new_content) {
|
||||
public function replaceContent($new_content)
|
||||
{
|
||||
$this->cutContent();
|
||||
$this->_body .= $new_content;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,13 +12,13 @@ namespace Fenom;
|
||||
/**
|
||||
* 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);
|
||||
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
|
||||
*/
|
||||
defined('T_YIELD') || define('T_YIELD', 370);
|
||||
defined('T_YIELD') || define('T_YIELD', 370);
|
||||
|
||||
/**
|
||||
* Each token have structure
|
||||
@ -27,7 +27,7 @@ defined('T_YIELD') || define('T_YIELD', 370);
|
||||
* - Whitespace (whitespace symbols after token)
|
||||
* - Line number of the token
|
||||
*
|
||||
* @see http://php.net/tokenizer
|
||||
* @see http://php.net/tokenizer
|
||||
* @property array $prev the previous token
|
||||
* @property array $curr the current token
|
||||
* @property array $next the next token
|
||||
@ -35,12 +35,12 @@ defined('T_YIELD') || define('T_YIELD', 370);
|
||||
* @package Fenom
|
||||
* @author Ivan Shalganov <a.cobest@gmail.com>
|
||||
*/
|
||||
class Tokenizer {
|
||||
const TOKEN = 0;
|
||||
const TEXT = 1;
|
||||
class Tokenizer
|
||||
{
|
||||
const TOKEN = 0;
|
||||
const TEXT = 1;
|
||||
const WHITESPACE = 2;
|
||||
const LINE = 3;
|
||||
|
||||
const LINE = 3;
|
||||
/**
|
||||
* Some text value: foo, bar, new, class ...
|
||||
*/
|
||||
@ -77,65 +77,57 @@ class Tokenizer {
|
||||
* Condition operation
|
||||
*/
|
||||
const MACRO_COND = 1008;
|
||||
|
||||
public $tokens;
|
||||
public $p = 0;
|
||||
public $quotes = 0;
|
||||
private $_max = 0;
|
||||
private $_last_no = 0;
|
||||
|
||||
/**
|
||||
* @see http://docs.php.net/manual/en/tokens.php
|
||||
* @var array groups of tokens
|
||||
*/
|
||||
private 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_UNSET => 1, \T_VAR => 1,
|
||||
\T_WHILE => 1, \T_YIELD => 1, \T_USE => 1
|
||||
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_UNSET => 1, \T_VAR => 1,
|
||||
\T_WHILE => 1, \T_YIELD => 1, \T_USE => 1
|
||||
),
|
||||
self::MACRO_INCDEC => array(
|
||||
self::MACRO_INCDEC => array(
|
||||
\T_INC => 1, \T_DEC => 1
|
||||
),
|
||||
self::MACRO_UNARY => array(
|
||||
self::MACRO_UNARY => array(
|
||||
"!" => 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, "&" => 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, "&" => 1
|
||||
),
|
||||
self::MACRO_BOOLEAN => array(
|
||||
\T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1, \T_LOGICAL_AND => 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(
|
||||
self::MACRO_MATH => array(
|
||||
"+" => 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,
|
||||
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,
|
||||
),
|
||||
self::MACRO_EQUALS => array(
|
||||
\T_AND_EQUAL => 1, \T_CONCAT_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_EQUALS => array(
|
||||
\T_AND_EQUAL => 1, \T_CONCAT_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, \T_DNUMBER => 1, \T_CONSTANT_ENCAPSED_STRING => 1
|
||||
self::MACRO_SCALAR => array(
|
||||
\T_LNUMBER => 1, \T_DNUMBER => 1, \T_CONSTANT_ENCAPSED_STRING => 1
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Special tokens
|
||||
* @var array
|
||||
@ -143,19 +135,25 @@ class Tokenizer {
|
||||
private static $spec = array(
|
||||
'true' => 1, 'false' => 1, 'null' => 1, 'TRUE' => 1, 'FALSE' => 1, 'NULL' => 1
|
||||
);
|
||||
public $tokens;
|
||||
public $p = 0;
|
||||
public $quotes = 0;
|
||||
private $_max = 0;
|
||||
private $_last_no = 0;
|
||||
|
||||
/**
|
||||
* @param $query
|
||||
*/
|
||||
public function __construct($query) {
|
||||
$tokens = array(-1 => array(\T_WHITESPACE, '', '', 1));
|
||||
$_tokens = token_get_all("<?php ".$query);
|
||||
$line = 1;
|
||||
public function __construct($query)
|
||||
{
|
||||
$tokens = array(-1 => array(\T_WHITESPACE, '', '', 1));
|
||||
$_tokens = token_get_all("<?php " . $query);
|
||||
$line = 1;
|
||||
array_shift($_tokens);
|
||||
$i = 0;
|
||||
foreach($_tokens as $token) {
|
||||
if(is_string($token)) {
|
||||
if($token === '"' || $token === "'" || $token === "`") {
|
||||
foreach ($_tokens as $token) {
|
||||
if (is_string($token)) {
|
||||
if ($token === '"' || $token === "'" || $token === "`") {
|
||||
$this->quotes++;
|
||||
}
|
||||
$tokens[] = array(
|
||||
@ -166,13 +164,13 @@ class Tokenizer {
|
||||
);
|
||||
$i++;
|
||||
} elseif ($token[0] === \T_WHITESPACE) {
|
||||
$tokens[$i-1][2] = $token[1];
|
||||
$tokens[$i - 1][2] = $token[1];
|
||||
} else {
|
||||
$tokens[] = array(
|
||||
$token[0],
|
||||
$token[1],
|
||||
"",
|
||||
$line = $token[2],
|
||||
$line = $token[2],
|
||||
token_name($token[0]) // debug
|
||||
);
|
||||
$i++;
|
||||
@ -180,17 +178,37 @@ class Tokenizer {
|
||||
|
||||
}
|
||||
unset($tokens[-1]);
|
||||
$this->tokens = $tokens;
|
||||
$this->_max = count($this->tokens) - 1;
|
||||
$this->tokens = $tokens;
|
||||
$this->_max = count($this->tokens) - 1;
|
||||
$this->_last_no = $this->tokens[$this->_max][3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token name
|
||||
* @static
|
||||
* @param int|string $token
|
||||
* @return string
|
||||
*/
|
||||
public static function getName($token)
|
||||
{
|
||||
if (is_string($token)) {
|
||||
return $token;
|
||||
} elseif (is_integer($token)) {
|
||||
return token_name($token);
|
||||
} elseif (is_array($token)) {
|
||||
return token_name($token[0]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is incomplete mean some string not closed
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function isIncomplete() {
|
||||
public function isIncomplete()
|
||||
{
|
||||
return ($this->quotes % 2) || ($this->tokens[$this->_max][0] === T_ENCAPSED_AND_WHITESPACE);
|
||||
}
|
||||
|
||||
@ -200,7 +218,8 @@ class Tokenizer {
|
||||
* @link http://php.net/manual/en/iterator.current.php
|
||||
* @return mixed Can return any type.
|
||||
*/
|
||||
public function current() {
|
||||
public function current()
|
||||
{
|
||||
return $this->curr[1];
|
||||
}
|
||||
|
||||
@ -210,51 +229,31 @@ class Tokenizer {
|
||||
* @link http://php.net/manual/en/iterator.next.php
|
||||
* @return Tokenizer
|
||||
*/
|
||||
public function next() {
|
||||
if($this->p > $this->_max) {
|
||||
public function next()
|
||||
{
|
||||
if ($this->p > $this->_max) {
|
||||
return $this;
|
||||
}
|
||||
$this->p++;
|
||||
unset($this->prev, $this->curr, $this->next);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check token type. If token type is one of expected types return true. Otherwise return false
|
||||
*
|
||||
* @param array $expects
|
||||
* @param string|int $token
|
||||
* @return bool
|
||||
*/
|
||||
private function _valid($expects, $token) {
|
||||
foreach($expects as $expect) {
|
||||
if(is_string($expect) || $expect < 1000) {
|
||||
if($expect === $token) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
if(isset(self::$_macros[ $expect ][ $token ])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the next token is a valid one, move the position of cursor one step forward. Otherwise throws an exception.
|
||||
* @param array $tokens
|
||||
* @throws UnexpectedTokenException
|
||||
* @return mixed
|
||||
*/
|
||||
public function _next($tokens) {
|
||||
public function _next($tokens)
|
||||
{
|
||||
$this->next();
|
||||
if(!$this->curr) {
|
||||
if (!$this->curr) {
|
||||
throw new UnexpectedTokenException($this, $tokens);
|
||||
}
|
||||
if($tokens) {
|
||||
if($this->_valid($tokens, $this->key())) {
|
||||
if ($tokens) {
|
||||
if ($this->_valid($tokens, $this->key())) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -267,28 +266,31 @@ class Tokenizer {
|
||||
* Fetch next specified token or throw an exception
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNext(/*int|string $token1, int|string $token2, ... */) {
|
||||
public function getNext( /*int|string $token1, int|string $token2, ... */)
|
||||
{
|
||||
$this->_next(func_get_args());
|
||||
|
||||
return $this->current();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return substring. This method doesn't move pointer.
|
||||
* @param int $offset
|
||||
* @param int $limit
|
||||
* @return string
|
||||
*/
|
||||
public function getSubstr($offset, $limit = 0) {
|
||||
public function getSubstr($offset, $limit = 0)
|
||||
{
|
||||
$str = '';
|
||||
if(!$limit) {
|
||||
if (!$limit) {
|
||||
$limit = $this->_max;
|
||||
} else {
|
||||
$limit += $offset;
|
||||
}
|
||||
for($i = $offset; $i <= $limit; $i++){
|
||||
$str .= $this->tokens[$i][1].$this->tokens[$i][2];
|
||||
for ($i = $offset; $i <= $limit; $i++) {
|
||||
$str .= $this->tokens[$i][1] . $this->tokens[$i][2];
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
@ -297,10 +299,12 @@ class Tokenizer {
|
||||
* @return mixed
|
||||
* @throws UnexpectedTokenException
|
||||
*/
|
||||
public function getAndNext() {
|
||||
if($this->curr) {
|
||||
public function getAndNext()
|
||||
{
|
||||
if ($this->curr) {
|
||||
$cur = $this->curr[1];
|
||||
$this->next();
|
||||
|
||||
return $cur;
|
||||
} else {
|
||||
throw new UnexpectedTokenException($this, func_get_args());
|
||||
@ -312,7 +316,8 @@ class Tokenizer {
|
||||
* @param $token1
|
||||
* @return bool
|
||||
*/
|
||||
public function isNext($token1/*, ...*/) {
|
||||
public function isNext($token1 /*, ...*/)
|
||||
{
|
||||
return $this->next && $this->_valid(func_get_args(), $this->next[0]);
|
||||
}
|
||||
|
||||
@ -321,7 +326,8 @@ class Tokenizer {
|
||||
* @param $token1
|
||||
* @return bool
|
||||
*/
|
||||
public function is($token1/*, ...*/) {
|
||||
public function is($token1 /*, ...*/)
|
||||
{
|
||||
return $this->curr && $this->_valid(func_get_args(), $this->curr[0]);
|
||||
}
|
||||
|
||||
@ -330,7 +336,8 @@ class Tokenizer {
|
||||
* @param $token1
|
||||
* @return bool
|
||||
*/
|
||||
public function isPrev($token1/*, ...*/) {
|
||||
public function isPrev($token1 /*, ...*/)
|
||||
{
|
||||
return $this->prev && $this->_valid(func_get_args(), $this->prev[0]);
|
||||
}
|
||||
|
||||
@ -341,8 +348,9 @@ class Tokenizer {
|
||||
* @throws UnexpectedTokenException
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($token1 /*, $token2 ...*/) {
|
||||
if($this->curr && $this->_valid(func_get_args(), $this->curr[0])) {
|
||||
public function get($token1 /*, $token2 ...*/)
|
||||
{
|
||||
if ($this->curr && $this->_valid(func_get_args(), $this->curr[0])) {
|
||||
return $this->curr[1];
|
||||
} else {
|
||||
throw new UnexpectedTokenException($this, func_get_args());
|
||||
@ -353,12 +361,14 @@ class Tokenizer {
|
||||
* Step back
|
||||
* @return Tokenizer
|
||||
*/
|
||||
public function back() {
|
||||
if($this->p === 0) {
|
||||
public function back()
|
||||
{
|
||||
if ($this->p === 0) {
|
||||
return $this;
|
||||
}
|
||||
$this->p--;
|
||||
unset($this->prev, $this->curr, $this->next);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -368,8 +378,9 @@ class Tokenizer {
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key) {
|
||||
switch($key) {
|
||||
public function __get($key)
|
||||
{
|
||||
switch ($key) {
|
||||
case 'curr':
|
||||
return $this->curr = ($this->p <= $this->_max) ? $this->tokens[$this->p] : null;
|
||||
case 'next':
|
||||
@ -381,7 +392,8 @@ class Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
public function count() {
|
||||
public function count()
|
||||
{
|
||||
return $this->_max;
|
||||
}
|
||||
|
||||
@ -389,7 +401,8 @@ class Tokenizer {
|
||||
* Return the key of the current element
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
public function key() {
|
||||
public function key()
|
||||
{
|
||||
return $this->curr ? $this->curr[0] : null;
|
||||
}
|
||||
|
||||
@ -398,44 +411,30 @@ class Tokenizer {
|
||||
* @return boolean The return value will be casted to boolean and then evaluated.
|
||||
* Returns true on success or false on failure.
|
||||
*/
|
||||
public function valid() {
|
||||
public function valid()
|
||||
{
|
||||
return (bool)$this->curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token name
|
||||
* @static
|
||||
* @param int|string $token
|
||||
* @return string
|
||||
*/
|
||||
public static function getName($token) {
|
||||
if(is_string($token)) {
|
||||
return $token;
|
||||
} elseif(is_integer($token)) {
|
||||
return token_name($token);
|
||||
} elseif(is_array($token)) {
|
||||
return token_name($token[0]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip specific token or throw an exception
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
* @return Tokenizer
|
||||
*/
|
||||
public function skip(/*$token1, $token2, ...*/) {
|
||||
if(func_num_args()) {
|
||||
if($this->_valid(func_get_args(), $this->curr[0])) {
|
||||
public function skip( /*$token1, $token2, ...*/)
|
||||
{
|
||||
if (func_num_args()) {
|
||||
if ($this->_valid(func_get_args(), $this->curr[0])) {
|
||||
$this->next();
|
||||
|
||||
return $this;
|
||||
} else {
|
||||
throw new UnexpectedTokenException($this, func_get_args());
|
||||
}
|
||||
} else {
|
||||
$this->next();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@ -446,10 +445,12 @@ class Tokenizer {
|
||||
* @param int|string $token1
|
||||
* @return Tokenizer
|
||||
*/
|
||||
public function skipIf($token1/*, $token2, ...*/) {
|
||||
if($this->_valid(func_get_args(), $this->curr[0])) {
|
||||
public function skipIf($token1 /*, $token2, ...*/)
|
||||
{
|
||||
if ($this->_valid(func_get_args(), $this->curr[0])) {
|
||||
$this->next();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -460,8 +461,9 @@ class Tokenizer {
|
||||
* @return Tokenizer
|
||||
* @throws UnexpectedTokenException
|
||||
*/
|
||||
public function need($token1/*, $token2, ...*/) {
|
||||
if($this->_valid(func_get_args(), $this->curr[0])) {
|
||||
public function need($token1 /*, $token2, ...*/)
|
||||
{
|
||||
if ($this->_valid(func_get_args(), $this->curr[0])) {
|
||||
return $this;
|
||||
} else {
|
||||
throw new UnexpectedTokenException($this, func_get_args());
|
||||
@ -471,40 +473,41 @@ class Tokenizer {
|
||||
/**
|
||||
* Get tokens near current position
|
||||
* @param int $before count tokens before current token
|
||||
* @param int $after count tokens after current token
|
||||
* @param int $after count tokens after current token
|
||||
* @return array
|
||||
*/
|
||||
public function getSnippet($before = 0, $after = 0) {
|
||||
public function getSnippet($before = 0, $after = 0)
|
||||
{
|
||||
$from = 0;
|
||||
$to = $this->p;
|
||||
if($before > 0) {
|
||||
if($before > $this->p) {
|
||||
$to = $this->p;
|
||||
if ($before > 0) {
|
||||
if ($before > $this->p) {
|
||||
$from = $this->p;
|
||||
} else {
|
||||
$from = $before;
|
||||
}
|
||||
} elseif($before < 0) {
|
||||
} elseif ($before < 0) {
|
||||
$from = $this->p + $before;
|
||||
if($from < 0) {
|
||||
if ($from < 0) {
|
||||
$from = 0;
|
||||
}
|
||||
}
|
||||
if($after > 0) {
|
||||
if ($after > 0) {
|
||||
$to = $this->p + $after;
|
||||
if($to > $this->_max) {
|
||||
if ($to > $this->_max) {
|
||||
$to = $this->_max;
|
||||
}
|
||||
} elseif($after < 0) {
|
||||
} elseif ($after < 0) {
|
||||
$to = $this->_max + $after;
|
||||
if($to < $this->p) {
|
||||
if ($to < $this->p) {
|
||||
$to = $this->p;
|
||||
}
|
||||
} elseif($this->p > $this->_max) {
|
||||
} elseif ($this->p > $this->_max) {
|
||||
$to = $this->_max;
|
||||
}
|
||||
$code = array();
|
||||
for($i=$from; $i<=$to; $i++) {
|
||||
$code[] = $this->tokens[ $i ];
|
||||
for ($i = $from; $i <= $to; $i++) {
|
||||
$code[] = $this->tokens[$i];
|
||||
}
|
||||
|
||||
return $code;
|
||||
@ -516,11 +519,13 @@ class Tokenizer {
|
||||
* @param int $after
|
||||
* @return string
|
||||
*/
|
||||
public function getSnippetAsString($before = 0, $after = 0) {
|
||||
public function getSnippetAsString($before = 0, $after = 0)
|
||||
{
|
||||
$str = "";
|
||||
foreach($this->getSnippet($before, $after) as $token) {
|
||||
$str .= $token[1].$token[2];
|
||||
foreach ($this->getSnippet($before, $after) as $token) {
|
||||
$str .= $token[1] . $token[2];
|
||||
}
|
||||
|
||||
return trim(str_replace("\n", '↵', $str));
|
||||
}
|
||||
|
||||
@ -528,7 +533,8 @@ class Tokenizer {
|
||||
* Check if current is special value: true, TRUE, false, FALSE, null, NULL
|
||||
* @return bool
|
||||
*/
|
||||
public function isSpecialVal() {
|
||||
public function isSpecialVal()
|
||||
{
|
||||
return isset(self::$spec[$this->current()]);
|
||||
}
|
||||
|
||||
@ -536,14 +542,16 @@ class Tokenizer {
|
||||
* Check if the token is last
|
||||
* @return bool
|
||||
*/
|
||||
public function isLast() {
|
||||
public function isLast()
|
||||
{
|
||||
return $this->p === $this->_max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move pointer to the end
|
||||
*/
|
||||
public function end() {
|
||||
public function end()
|
||||
{
|
||||
$this->p = $this->_max;
|
||||
}
|
||||
|
||||
@ -551,27 +559,57 @@ class Tokenizer {
|
||||
* Return line number of the current token
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLine() {
|
||||
public function getLine()
|
||||
{
|
||||
return $this->curr ? $this->curr[3] : $this->_last_no;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check token type. If token type is one of expected types return true. Otherwise return false
|
||||
*
|
||||
* @param array $expects
|
||||
* @param string|int $token
|
||||
* @return bool
|
||||
*/
|
||||
private function _valid($expects, $token)
|
||||
{
|
||||
foreach ($expects as $expect) {
|
||||
if (is_string($expect) || $expect < 1000) {
|
||||
if ($expect === $token) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (isset(self::$_macros[$expect][$token])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unexpected token
|
||||
*/
|
||||
class UnexpectedTokenException extends \RuntimeException {
|
||||
public function __construct(Tokenizer $tokens, $expect = null, $where = null) {
|
||||
if($expect && count($expect) == 1 && is_string($expect[0])) {
|
||||
$expect = ", expect '".$expect[0]."'";
|
||||
class UnexpectedTokenException extends \RuntimeException
|
||||
{
|
||||
public function __construct(Tokenizer $tokens, $expect = null, $where = null)
|
||||
{
|
||||
if ($expect && count($expect) == 1 && is_string($expect[0])) {
|
||||
$expect = ", expect '" . $expect[0] . "'";
|
||||
} else {
|
||||
$expect = "";
|
||||
}
|
||||
if(!$tokens->curr) {
|
||||
$this->message = "Unexpected end of ".($where?:"expression")."$expect";
|
||||
} elseif($tokens->curr[0] === T_WHITESPACE) {
|
||||
if (!$tokens->curr) {
|
||||
$this->message = "Unexpected end of " . ($where ? : "expression") . "$expect";
|
||||
} elseif ($tokens->curr[0] === T_WHITESPACE) {
|
||||
$this->message = "Unexpected whitespace$expect";
|
||||
} else {
|
||||
$this->message = "Unexpected token '".$tokens->current()."' in ".($where?:"expression")."$expect";
|
||||
$this->message = "Unexpected token '" . $tokens->current() . "' in " . ($where ? : "expression") . "$expect";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
;
|
||||
|
Loading…
Reference in New Issue
Block a user