2013-01-25 18:36:16 +04:00
|
|
|
<?php
|
2013-02-07 17:37:16 +04:00
|
|
|
use Aspect\Template,
|
|
|
|
Aspect\ProviderInterface;
|
2013-01-25 18:36:16 +04:00
|
|
|
|
2013-01-25 19:18:09 +04:00
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* Aspect Template Engine
|
2013-01-25 19:18:09 +04:00
|
|
|
*/
|
2013-01-25 18:36:16 +04:00
|
|
|
class Aspect {
|
2013-02-07 17:37:16 +04:00
|
|
|
const VERSION = 1.0;
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
const INLINE_COMPILER = 1;
|
|
|
|
const BLOCK_COMPILER = 2;
|
|
|
|
const INLINE_FUNCTION = 3;
|
|
|
|
const BLOCK_FUNCTION = 4;
|
|
|
|
const MODIFIER = 5;
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
const DENY_METHODS = 0x10;
|
|
|
|
const DENY_INLINE_FUNCS = 0x20;
|
|
|
|
const FORCE_INCLUDE = 0x40;
|
2013-01-25 18:36:16 +04:00
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
const CHECK_MTIME = 0x80;
|
|
|
|
const FORCE_COMPILE = 0xF0;
|
2013-01-25 18:36:16 +04:00
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
const DEFAULT_CLOSE_COMPILER = 'Aspect\Compiler::stdClose';
|
|
|
|
const DEFAULT_FUNC_PARSER = 'Aspect\Compiler::stdFuncParser';
|
|
|
|
const DEFAULT_FUNC_OPEN = 'Aspect\Compiler::stdFuncOpen';
|
|
|
|
const DEFAULT_FUNC_CLOSE = 'Aspect\Compiler::stdFuncOpen';
|
|
|
|
const SMART_FUNC_PARSER = 'Aspect\Compiler::smartFuncParser';
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* @var array of possible options, as associative array
|
2013-01-25 18:36:16 +04:00
|
|
|
* @see setOptions, addOptions, delOptions
|
|
|
|
*/
|
|
|
|
private static $_option_list = array(
|
|
|
|
"disable_methods" => self::DENY_METHODS,
|
|
|
|
"disable_native_funcs" => self::DENY_INLINE_FUNCS,
|
|
|
|
"force_compile" => self::FORCE_COMPILE,
|
|
|
|
"compile_check" => self::CHECK_MTIME,
|
2013-02-07 17:37:16 +04:00
|
|
|
"force_include" => self::FORCE_INCLUDE,
|
2013-01-25 18:36:16 +04:00
|
|
|
);
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* Default options for functions
|
|
|
|
* @var array
|
|
|
|
*/
|
2013-01-25 18:36:16 +04:00
|
|
|
private static $_actions_defaults = array(
|
|
|
|
self::BLOCK_FUNCTION => array(
|
|
|
|
'type' => self::BLOCK_FUNCTION,
|
2013-02-07 17:37:16 +04:00
|
|
|
'open' => self::DEFAULT_FUNC_OPEN,
|
|
|
|
'close' => self::DEFAULT_FUNC_CLOSE,
|
2013-01-25 18:36:16 +04:00
|
|
|
'function' => null,
|
|
|
|
),
|
|
|
|
self::INLINE_FUNCTION => array(
|
|
|
|
'type' => self::INLINE_FUNCTION,
|
2013-02-07 17:37:16 +04:00
|
|
|
'parser' => self::DEFAULT_FUNC_PARSER,
|
2013-01-25 18:36:16 +04:00
|
|
|
'function' => null,
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
self::INLINE_COMPILER => array(
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::INLINE_COMPILER,
|
|
|
|
'open' => null,
|
2013-02-07 17:37:16 +04:00
|
|
|
'close' => self::DEFAULT_CLOSE_COMPILER,
|
2013-01-25 18:36:16 +04:00
|
|
|
'tags' => array(),
|
|
|
|
'float_tags' => array()
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
self::BLOCK_COMPILER => array(
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => null,
|
|
|
|
'close' => null,
|
|
|
|
'tags' => array(),
|
|
|
|
'float_tags' => array()
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2013-01-28 16:34:34 +04:00
|
|
|
/**
|
|
|
|
* @var array Templates storage
|
|
|
|
*/
|
|
|
|
protected $_storage = array();
|
2013-01-25 18:36:16 +04:00
|
|
|
/**
|
|
|
|
* @var array template directory
|
|
|
|
*/
|
|
|
|
protected $_tpl_path = array();
|
|
|
|
/**
|
|
|
|
* @var string compile directory
|
|
|
|
*/
|
|
|
|
protected $_compile_dir = "/tmp";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var int masked options
|
|
|
|
*/
|
|
|
|
protected $_options = 0;
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
protected $_on_pre_cmp = array();
|
|
|
|
protected $_on_cmp = array();
|
|
|
|
protected $_on_post_cmp = array();
|
|
|
|
|
|
|
|
/**
|
2013-02-13 20:51:27 +04:00
|
|
|
* @var ProviderInterface
|
2013-02-07 17:37:16 +04:00
|
|
|
*/
|
|
|
|
private $_provider;
|
|
|
|
/**
|
|
|
|
* @var array of Aspect\ProviderInterface
|
|
|
|
*/
|
|
|
|
protected $_providers = array();
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* @var array of modifiers [modifier_name => callable]
|
2013-01-25 18:36:16 +04:00
|
|
|
*/
|
|
|
|
protected $_modifiers = array(
|
|
|
|
"upper" => 'strtoupper',
|
2013-02-13 20:51:27 +04:00
|
|
|
"up" => 'strtoupper',
|
2013-01-25 18:36:16 +04:00
|
|
|
"lower" => 'strtolower',
|
2013-02-13 20:51:27 +04:00
|
|
|
"low" => 'strtolower',
|
2013-01-25 18:36:16 +04:00
|
|
|
"date_format" => 'Aspect\Modifier::dateFormat',
|
|
|
|
"date" => 'Aspect\Modifier::date',
|
|
|
|
"truncate" => 'Aspect\Modifier::truncate',
|
|
|
|
"escape" => 'Aspect\Modifier::escape',
|
|
|
|
"e" => 'Aspect\Modifier::escape', // alias of escape
|
2013-02-07 17:37:16 +04:00
|
|
|
"url" => 'urlencode', // alias of escape:"url"
|
2013-01-25 18:36:16 +04:00
|
|
|
"unescape" => 'Aspect\Modifier::unescape',
|
|
|
|
"strip" => 'Aspect\Modifier::strip',
|
2013-02-07 17:37:16 +04:00
|
|
|
"default" => 'Aspect\Modifier::defaultValue'
|
2013-01-25 18:36:16 +04:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* @var array of allowed PHP functions
|
2013-01-25 18:36:16 +04:00
|
|
|
*/
|
|
|
|
protected $_allowed_funcs = array(
|
2013-02-13 20:51:27 +04:00
|
|
|
"count" => 1, "is_string" => 1, "is_array" => 1, "is_numeric" => 1, "is_int" => 1,
|
2013-02-07 17:37:16 +04:00
|
|
|
"is_object" => 1, "strtotime" => 1, "gettype" => 1, "is_double" => 1, "json_encode" => 1, "json_decode" => 1,
|
2013-02-13 20:51:27 +04:00
|
|
|
"ip2long" => 1, "long2ip" => 1, "strip_tags" => 1, "nl2br" => 1, "explode" => 1, "implode" => 1
|
2013-01-25 18:36:16 +04:00
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* @var array of compilers and functions
|
2013-01-25 18:36:16 +04:00
|
|
|
*/
|
|
|
|
protected $_actions = array(
|
2013-02-07 17:37:16 +04:00
|
|
|
'foreach' => array( // {foreach ...} {break} {continue} {foreachelse} {/foreach}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::foreachOpen',
|
|
|
|
'close' => 'Aspect\Compiler::foreachClose',
|
|
|
|
'tags' => array(
|
|
|
|
'foreachelse' => 'Aspect\Compiler::foreachElse',
|
|
|
|
'break' => 'Aspect\Compiler::tagBreak',
|
|
|
|
'continue' => 'Aspect\Compiler::tagContinue',
|
|
|
|
),
|
|
|
|
'float_tags' => array('break' => 1, 'continue' => 1)
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'if' => array( // {if ...} {elseif ...} {else} {/if}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::ifOpen',
|
|
|
|
'close' => 'Aspect\Compiler::stdClose',
|
|
|
|
'tags' => array(
|
|
|
|
'elseif' => 'Aspect\Compiler::tagElseIf',
|
|
|
|
'else' => 'Aspect\Compiler::tagElse',
|
|
|
|
)
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'switch' => array( // {switch ...} {case ...} {break} {default} {/switch}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::switchOpen',
|
|
|
|
'close' => 'Aspect\Compiler::stdClose',
|
|
|
|
'tags' => array(
|
|
|
|
'case' => 'Aspect\Compiler::tagCase',
|
|
|
|
'default' => 'Aspect\Compiler::tagDefault',
|
|
|
|
'break' => 'Aspect\Compiler::tagBreak',
|
|
|
|
),
|
|
|
|
'float_tags' => array('break' => 1)
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'for' => array( // {for ...} {break} {continue} {/for}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::forOpen',
|
|
|
|
'close' => 'Aspect\Compiler::forClose',
|
|
|
|
'tags' => array(
|
|
|
|
'forelse' => 'Aspect\Compiler::forElse',
|
|
|
|
'break' => 'Aspect\Compiler::tagBreak',
|
|
|
|
'continue' => 'Aspect\Compiler::tagContinue',
|
|
|
|
),
|
|
|
|
'float_tags' => array('break' => 1, 'continue' => 1)
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'while' => array( // {while ...} {break} {continue} {/while}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::whileOpen',
|
|
|
|
'close' => 'Aspect\Compiler::stdClose',
|
|
|
|
'tags' => array(
|
|
|
|
'break' => 'Aspect\Compiler::tagBreak',
|
|
|
|
'continue' => 'Aspect\Compiler::tagContinue',
|
|
|
|
),
|
|
|
|
'float_tags' => array('break' => 1, 'continue' => 1)
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'include' => array( // {include ...}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::INLINE_COMPILER,
|
|
|
|
'parser' => 'Aspect\Compiler::tagInclude'
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'var' => array( // {var ...}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::INLINE_COMPILER,
|
|
|
|
'parser' => 'Aspect\Compiler::assign'
|
|
|
|
),
|
2013-02-20 18:09:24 +04:00
|
|
|
'block' => array( // {block ...} {parent} {/block}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::tagBlockOpen',
|
|
|
|
'close' => 'Aspect\Compiler::tagBlockClose',
|
2013-02-20 18:09:24 +04:00
|
|
|
'tags' => array(
|
|
|
|
'parent' => 'Aspect\Compiler::tagParent'
|
|
|
|
),
|
|
|
|
'float_tags' => array('parent' => 1)
|
2013-01-25 18:36:16 +04:00
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'extends' => array( // {extends ...}
|
2013-01-25 18:36:16 +04:00
|
|
|
'type' => self::INLINE_COMPILER,
|
|
|
|
'parser' => 'Aspect\Compiler::tagExtends'
|
|
|
|
),
|
2013-02-20 18:09:24 +04:00
|
|
|
'use' => array( // {use}
|
|
|
|
'type' => self::INLINE_COMPILER,
|
|
|
|
'parser' => 'Aspect\Compiler::tagUse'
|
|
|
|
),
|
2013-02-07 17:37:16 +04:00
|
|
|
'capture' => array( // {capture ...} {/capture}
|
2013-02-20 18:09:24 +04:00
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::captureOpen',
|
|
|
|
'close' => 'Aspect\Compiler::captureClose'
|
2013-01-25 18:36:16 +04:00
|
|
|
),
|
2013-02-20 18:09:24 +04:00
|
|
|
'filter' => array( // {filter} ... {/filter}
|
|
|
|
'type' => self::BLOCK_COMPILER,
|
|
|
|
'open' => 'Aspect\Compiler::filterOpen',
|
|
|
|
'close' => 'Aspect\Compiler::filterClose'
|
2013-01-25 18:36:16 +04:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2013-02-13 20:51:27 +04:00
|
|
|
/**
|
|
|
|
* Just factory
|
|
|
|
*
|
|
|
|
* @param string|Aspect\ProviderInterface $source path to templates or custom provider
|
|
|
|
* @param string $compile_dir path to compiled files
|
|
|
|
* @param int $options
|
|
|
|
* @throws InvalidArgumentException
|
|
|
|
* @return Aspect
|
|
|
|
*/
|
|
|
|
public static function factory($source, $compile_dir = '/tmp', $options = 0) {
|
|
|
|
if(is_string($source)) {
|
2013-02-21 22:51:24 +04:00
|
|
|
$provider = new \Aspect\FSProvider($source);
|
2013-02-13 20:51:27 +04:00
|
|
|
} elseif($source instanceof Aspect\ProviderInterface) {
|
|
|
|
$provider = $source;
|
|
|
|
} else {
|
|
|
|
throw new InvalidArgumentException("Source must be a valid path or provider object");
|
|
|
|
}
|
2013-02-07 17:37:16 +04:00
|
|
|
$aspect = new static($provider);
|
2013-01-25 18:36:16 +04:00
|
|
|
$aspect->setCompileDir($compile_dir);
|
|
|
|
if($options) {
|
|
|
|
$aspect->setOptions($options);
|
|
|
|
}
|
|
|
|
return $aspect;
|
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
2013-02-13 20:51:27 +04:00
|
|
|
* @param Aspect\ProviderInterface $provider
|
2013-02-07 17:37:16 +04:00
|
|
|
*/
|
2013-02-13 20:51:27 +04:00
|
|
|
public function __construct(Aspect\ProviderInterface $provider) {
|
|
|
|
$this->_provider = $provider;
|
2013-02-07 17:37:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set compile directory
|
|
|
|
* @param string $dir directory to store compiled templates in
|
|
|
|
* @return Aspect
|
|
|
|
*/
|
2013-01-25 18:36:16 +04:00
|
|
|
public function setCompileDir($dir) {
|
|
|
|
$this->_compile_dir = $dir;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param callable $cb
|
|
|
|
*/
|
|
|
|
public function addPreCompileFilter($cb) {
|
|
|
|
$this->_on_pre_cmp[] = $cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param callable $cb
|
|
|
|
*/
|
|
|
|
public function addPostCompileFilter($cb) {
|
|
|
|
$this->_on_post_cmp[] = $cb;
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* @param callable $cb
|
|
|
|
*/
|
2013-01-25 18:36:16 +04:00
|
|
|
public function addCompileFilter($cb) {
|
2013-02-07 17:37:16 +04:00
|
|
|
$this->_on_cmp[] = $cb;
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add modifier
|
|
|
|
*
|
|
|
|
* @param string $modifier
|
|
|
|
* @param string $callback
|
|
|
|
* @return Aspect
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function addModifier($modifier, $callback) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_modifiers[$modifier] = $callback;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-20 18:09:24 +04:00
|
|
|
* Add inline tag compiler
|
|
|
|
*
|
2013-02-07 17:37:16 +04:00
|
|
|
* @param string $compiler
|
2013-02-20 18:09:24 +04:00
|
|
|
* @param callable $parser
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return Aspect
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function addCompiler($compiler, $parser) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_actions[$compiler] = array(
|
|
|
|
'type' => self::INLINE_COMPILER,
|
|
|
|
'parser' => $parser
|
|
|
|
);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-20 18:09:24 +04:00
|
|
|
* Add block compiler
|
|
|
|
*
|
2013-02-07 17:37:16 +04:00
|
|
|
* @param string $compiler
|
2013-02-20 18:09:24 +04:00
|
|
|
* @param callable $open_parser
|
|
|
|
* @param callable $close_parser
|
2013-01-25 18:36:16 +04:00
|
|
|
* @param array $tags
|
|
|
|
* @return Aspect
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function addBlockCompiler($compiler, $open_parser, $close_parser = self::DEFAULT_CLOSE_COMPILER, array $tags = array()) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_actions[$compiler] = array(
|
|
|
|
'type' => self::BLOCK_COMPILER,
|
2013-02-07 17:37:16 +04:00
|
|
|
'open' => $open_parser,
|
|
|
|
'close' => $close_parser ?: self::DEFAULT_CLOSE_COMPILER,
|
2013-01-25 18:36:16 +04:00
|
|
|
'tags' => $tags,
|
|
|
|
);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* @param string $function
|
|
|
|
* @param callable $callback
|
2013-02-20 18:09:24 +04:00
|
|
|
* @param callable $parser
|
2013-02-07 17:37:16 +04:00
|
|
|
* @return Aspect
|
|
|
|
*/
|
|
|
|
public function addFunction($function, $callback, $parser = self::DEFAULT_FUNC_PARSER) {
|
|
|
|
$this->_actions[$function] = array(
|
|
|
|
'type' => self::INLINE_FUNCTION,
|
|
|
|
'parser' => $parser ?: self::DEFAULT_FUNC_PARSER,
|
|
|
|
'function' => $callback,
|
|
|
|
);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $function
|
|
|
|
* @param callable $callback
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return Aspect
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function addFunctionSmart($function, $callback) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_actions[$function] = array(
|
|
|
|
'type' => self::INLINE_FUNCTION,
|
2013-02-07 17:37:16 +04:00
|
|
|
'parser' => self::SMART_FUNC_PARSER,
|
2013-01-25 18:36:16 +04:00
|
|
|
'function' => $callback,
|
|
|
|
);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-20 18:09:24 +04:00
|
|
|
* @param string $function
|
|
|
|
* @param callable $callback
|
|
|
|
* @param callable $parser_open
|
|
|
|
* @param callable $parser_close
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return Aspect
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function addBlockFunction($function, $callback, $parser_open = null, $parser_close = null) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_actions[$function] = array(
|
|
|
|
'type' => self::BLOCK_FUNCTION,
|
|
|
|
'open' => $parser_open ?: 'Aspect\Compiler::stdFuncOpen',
|
|
|
|
'close' => $parser_close ?: 'Aspect\Compiler::stdFuncClose',
|
|
|
|
'function' => $callback,
|
|
|
|
);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param array $funcs
|
|
|
|
* @return Aspect
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function addAllowedFunctions(array $funcs) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_allowed_funcs = $this->_allowed_funcs + array_flip($funcs);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-20 18:09:24 +04:00
|
|
|
* Return modifier function
|
|
|
|
*
|
2013-01-25 18:36:16 +04:00
|
|
|
* @param $modifier
|
|
|
|
* @return mixed
|
|
|
|
* @throws \Exception
|
|
|
|
*/
|
|
|
|
public function getModifier($modifier) {
|
|
|
|
if(isset($this->_modifiers[$modifier])) {
|
|
|
|
return $this->_modifiers[$modifier];
|
|
|
|
} elseif($this->isAllowedFunction($modifier)) {
|
|
|
|
return $modifier;
|
|
|
|
} else {
|
|
|
|
throw new \Exception("Modifier $modifier not found");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-20 18:09:24 +04:00
|
|
|
* Return function
|
|
|
|
*
|
2013-01-25 18:36:16 +04:00
|
|
|
* @param string $function
|
|
|
|
* @return string|bool
|
|
|
|
*/
|
|
|
|
public function getFunction($function) {
|
|
|
|
if(isset($this->_actions[$function])) {
|
|
|
|
return $this->_actions[$function];
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-20 18:09:24 +04:00
|
|
|
/**
|
|
|
|
* @param string $function
|
|
|
|
* @return bool
|
|
|
|
*/
|
2013-01-25 18:36:16 +04:00
|
|
|
public function isAllowedFunction($function) {
|
|
|
|
if($this->_options & self::DENY_INLINE_FUNCS) {
|
|
|
|
return isset($this->_allowed_funcs[$function]);
|
|
|
|
} else {
|
|
|
|
return is_callable($function);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-20 18:09:24 +04:00
|
|
|
|
2013-01-25 18:36:16 +04:00
|
|
|
public function getTagOwners($tag) {
|
|
|
|
$tags = array();
|
|
|
|
foreach($this->_actions as $owner => $params) {
|
|
|
|
if(isset($params["tags"][$tag])) {
|
|
|
|
$tags[] = $owner;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $tags;
|
|
|
|
}
|
|
|
|
|
2013-02-20 18:09:24 +04:00
|
|
|
/**
|
|
|
|
* Add source template provider by scheme
|
|
|
|
*
|
|
|
|
* @param string $scm scheme name
|
|
|
|
* @param Aspect\ProviderInterface $provider provider object
|
|
|
|
*/
|
2013-02-13 20:51:27 +04:00
|
|
|
public function addProvider($scm, \Aspect\ProviderInterface $provider) {
|
2013-02-07 17:37:16 +04:00
|
|
|
$this->_providers[$scm] = $provider;
|
2013-01-28 16:34:34 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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:
|
2013-02-07 17:37:16 +04:00
|
|
|
* disable_methods - disable all calls method in template
|
2013-01-25 18:36:16 +04:00
|
|
|
* disable_native_funcs - disable all native PHP functions in template
|
|
|
|
* force_compile - recompile template every time (very slow!)
|
|
|
|
* compile_check - check template modifications (slow!)
|
|
|
|
* @param int|array $options
|
|
|
|
*/
|
|
|
|
public function setOptions($options) {
|
|
|
|
if(is_array($options)) {
|
2013-02-21 22:51:24 +04:00
|
|
|
$options = self::_makeMask($options, self::$_option_list);
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-02-20 18:09:24 +04:00
|
|
|
$this->_storage = array();
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_options = $options;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get options as bits
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getOptions() {
|
|
|
|
return $this->_options;
|
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* @param bool|string $scm
|
2013-02-13 20:51:27 +04:00
|
|
|
* @return Aspect\ProviderInterface
|
2013-02-07 17:37:16 +04:00
|
|
|
* @throws InvalidArgumentException
|
|
|
|
*/
|
|
|
|
public function getProvider($scm = false) {
|
|
|
|
if($scm) {
|
|
|
|
if(isset($this->_provider[$scm])) {
|
|
|
|
return $this->_provider[$scm];
|
|
|
|
} else {
|
|
|
|
throw new InvalidArgumentException("Provider for '$scm' not found");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return $this->_provider;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-20 18:09:24 +04:00
|
|
|
/**
|
|
|
|
* Return empty template
|
|
|
|
*
|
|
|
|
* @return Aspect\Template
|
|
|
|
*/
|
2013-02-13 20:51:27 +04:00
|
|
|
public function getRawTemplate() {
|
|
|
|
return new \Aspect\Template($this);
|
|
|
|
}
|
|
|
|
|
2013-01-25 18:36:16 +04:00
|
|
|
/**
|
|
|
|
* Execute template and write result into stdout
|
|
|
|
*
|
2013-02-20 18:09:24 +04:00
|
|
|
* @param string $template name of template
|
|
|
|
* @param array $vars array of data for template
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return Aspect\Render
|
|
|
|
*/
|
2013-01-28 16:34:34 +04:00
|
|
|
public function display($template, array $vars = array()) {
|
2013-01-25 18:36:16 +04:00
|
|
|
return $this->getTemplate($template)->display($vars);
|
2013-01-28 16:34:34 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2013-02-20 18:09:24 +04:00
|
|
|
* @param string $template name of template
|
|
|
|
* @param array $vars array of data for template
|
2013-01-25 18:36:16 +04:00
|
|
|
* @internal param int $options
|
|
|
|
* @return mixed
|
|
|
|
*/
|
2013-01-28 16:34:34 +04:00
|
|
|
public function fetch($template, array $vars = array()) {
|
|
|
|
return $this->getTemplate($template)->fetch($vars);
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return template by name
|
|
|
|
*
|
|
|
|
* @param string $template
|
|
|
|
* @return Aspect\Template
|
|
|
|
*/
|
2013-01-28 16:34:34 +04:00
|
|
|
public function getTemplate($template) {
|
2013-01-25 18:36:16 +04:00
|
|
|
if(isset($this->_storage[ $template ])) {
|
2013-02-07 17:37:16 +04:00
|
|
|
/** @var Aspect\Template $tpl */
|
|
|
|
$tpl = $this->_storage[ $template ];
|
|
|
|
if(($this->_options & self::CHECK_MTIME) && !$tpl->isValid()) {
|
2013-01-25 18:36:16 +04:00
|
|
|
return $this->_storage[ $template ] = $this->compile($template);
|
|
|
|
} else {
|
2013-01-28 16:34:34 +04:00
|
|
|
return $this->_storage[ $template ];
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-01-28 16:34:34 +04:00
|
|
|
} elseif($this->_options & self::FORCE_COMPILE) {
|
2013-02-20 18:09:24 +04:00
|
|
|
return $this->compile($template, false);
|
2013-01-25 18:36:16 +04:00
|
|
|
} else {
|
|
|
|
return $this->_storage[ $template ] = $this->_load($template);
|
|
|
|
}
|
2013-01-28 16:34:34 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add custom template into storage
|
|
|
|
* @param Aspect\Render $template
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function addTemplate(Aspect\Render $template) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$this->_storage[ $template->getName() ] = $template;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return template from storage or create if template doesn't exists.
|
|
|
|
*
|
|
|
|
* @param string $tpl
|
|
|
|
* @throws \RuntimeException
|
|
|
|
* @return Aspect\Template|mixed
|
|
|
|
*/
|
|
|
|
protected function _load($tpl) {
|
2013-01-28 16:34:34 +04:00
|
|
|
$file_name = $this->_getHash($tpl);
|
2013-02-07 17:37:16 +04:00
|
|
|
if(!is_file($this->_compile_dir."/".$file_name)) {
|
2013-01-25 18:36:16 +04:00
|
|
|
return $this->compile($tpl);
|
2013-01-28 16:34:34 +04:00
|
|
|
} else {
|
2013-02-15 01:49:26 +04:00
|
|
|
$aspect = $this;
|
2013-01-25 18:36:16 +04:00
|
|
|
/** @var Aspect\Render $tpl */
|
2013-02-13 20:51:27 +04:00
|
|
|
return include($this->_compile_dir."/".$file_name);
|
2013-01-28 16:34:34 +04:00
|
|
|
}
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate unique name of compiled template
|
|
|
|
*
|
|
|
|
* @param string $tpl
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
private function _getHash($tpl) {
|
|
|
|
$hash = $tpl.":".$this->_options;
|
2013-02-07 19:22:13 +04:00
|
|
|
return sprintf("%s.%u.%d.php", basename($tpl), crc32($hash), strlen($hash));
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* Compile and save template
|
|
|
|
*
|
|
|
|
* @param string $tpl
|
2013-02-13 20:51:27 +04:00
|
|
|
* @param bool $store store template on disk
|
2013-02-07 17:37:16 +04:00
|
|
|
* @throws RuntimeException
|
|
|
|
* @return \Aspect\Template
|
|
|
|
*/
|
|
|
|
public function compile($tpl, $store = true) {
|
2013-02-13 20:51:27 +04:00
|
|
|
$template = Template::factory($this)->load($tpl);
|
2013-02-07 17:37:16 +04:00
|
|
|
if($store) {
|
|
|
|
$tpl_tmp = tempnam($this->_compile_dir, basename($tpl));
|
|
|
|
$tpl_fp = fopen($tpl_tmp, "w");
|
|
|
|
if(!$tpl_fp) {
|
2013-02-13 20:51:27 +04:00
|
|
|
throw new \RuntimeException("Can't to open temporary file $tpl_tmp. Directory ".$this->_compile_dir." is writable?");
|
2013-02-07 17:37:16 +04:00
|
|
|
}
|
|
|
|
fwrite($tpl_fp, $template->getTemplateCode());
|
|
|
|
fclose($tpl_fp);
|
|
|
|
$file_name = $this->_compile_dir."/".$this->_getHash($tpl);
|
|
|
|
if(!rename($tpl_tmp, $file_name)) {
|
2013-02-13 20:51:27 +04:00
|
|
|
throw new \RuntimeException("Can't to move $tpl_tmp to $tpl");
|
2013-02-07 17:37:16 +04:00
|
|
|
}
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
return $template;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* Remove all compiled templates.
|
|
|
|
*
|
|
|
|
* @param string $scm
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return int
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function compileAll($scm = null) {
|
2013-01-25 18:36:16 +04:00
|
|
|
//return FS::rm($this->_compile_dir.'/*');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $tpl
|
|
|
|
* @return bool
|
|
|
|
*/
|
2013-02-07 17:37:16 +04:00
|
|
|
public function clearCompiledTemplate($tpl) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$file_name = $this->_compile_dir."/".$this->_getHash($tpl);
|
|
|
|
if(file_exists($file_name)) {
|
|
|
|
return unlink($file_name);
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function clearAllCompiles() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compile code to template
|
|
|
|
*
|
|
|
|
* @param string $code
|
|
|
|
* @param string $name
|
|
|
|
* @return Aspect\Template
|
|
|
|
*/
|
|
|
|
public function compileCode($code, $name = 'Runtime compile') {
|
2013-02-13 20:51:27 +04:00
|
|
|
return Template::factory($this)->source($name, $code);
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-21 22:51:24 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|