commit
a3a84ea606
|
@ -10,7 +10,7 @@ php:
|
||||||
- 7.0
|
- 7.0
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- composer install --dev
|
- composer update --dev
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- phpunit
|
- phpunit
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "*",
|
"phpunit/phpunit": "*",
|
||||||
"satooshi/php-coveralls": "dev-master"
|
"satooshi/php-coveralls": "*"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": { "Fenom\\": "src/" },
|
"psr-0": { "Fenom\\": "src/" },
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,6 +7,7 @@
|
||||||
* For the full copyright and license information, please view the license.md
|
* For the full copyright and license information, please view the license.md
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
use Fenom\Error\CompileException;
|
||||||
use Fenom\ProviderInterface;
|
use Fenom\ProviderInterface;
|
||||||
use Fenom\Template;
|
use Fenom\Template;
|
||||||
|
|
||||||
|
@ -844,16 +845,31 @@ class Fenom
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add global accessor ($.)
|
* Add global accessor as PHP code ($.)
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param mixed $accessor
|
* @param mixed $accessor
|
||||||
* @param string $parser
|
* @param string $parser
|
||||||
* @return Fenom
|
* @return Fenom
|
||||||
*/
|
*/
|
||||||
public function addAccessorSmart($name, $accessor, $parser) {
|
public function addAccessorSmart($name, $accessor, $parser = self::ACCESSOR_VAR)
|
||||||
|
{
|
||||||
$this->_accessors[$name] = array(
|
$this->_accessors[$name] = array(
|
||||||
"accessor" => $accessor,
|
"accessor" => $accessor,
|
||||||
"parser" => $parser
|
"parser" => $parser,
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add global accessor handler as callback ($.X)
|
||||||
|
* @param string $name
|
||||||
|
* @param callable $callback
|
||||||
|
* @return Fenom
|
||||||
|
*/
|
||||||
|
public function addAccessorCallback($name, $callback)
|
||||||
|
{
|
||||||
|
$this->_accessors[$name] = array(
|
||||||
|
"callback" => $callback
|
||||||
);
|
);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -872,11 +888,17 @@ class Fenom
|
||||||
/**
|
/**
|
||||||
* Get an accessor
|
* Get an accessor
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
* @param string $key
|
||||||
* @return callable
|
* @return callable
|
||||||
*/
|
*/
|
||||||
public function getAccessor($name) {
|
public function getAccessor($name, $key = null)
|
||||||
|
{
|
||||||
if(isset($this->_accessors[$name])) {
|
if(isset($this->_accessors[$name])) {
|
||||||
return $this->_accessors[$name];
|
if($key) {
|
||||||
|
return $this->_accessors[$name][$key];
|
||||||
|
} else {
|
||||||
|
return $this->_accessors[$name];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -888,7 +910,8 @@ class Fenom
|
||||||
* @param string $pattern
|
* @param string $pattern
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function addCallFilter($pattern) {
|
public function addCallFilter($pattern)
|
||||||
|
{
|
||||||
$this->call_filters[] = $pattern;
|
$this->call_filters[] = $pattern;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -975,12 +998,7 @@ class Fenom
|
||||||
{
|
{
|
||||||
$options |= $this->_options;
|
$options |= $this->_options;
|
||||||
if (is_array($template)) {
|
if (is_array($template)) {
|
||||||
if(count($template) === 1) {
|
$key = $options . "@" . implode(",", $template);
|
||||||
$template = current($template);
|
|
||||||
$key = $options . "@" . $template;
|
|
||||||
} else {
|
|
||||||
$key = $options . "@" . implode(",", $template);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$key = $options . "@" . $template;
|
$key = $options . "@" . $template;
|
||||||
}
|
}
|
||||||
|
@ -1029,13 +1047,15 @@ class Fenom
|
||||||
*/
|
*/
|
||||||
protected function _load($template, $opts)
|
protected function _load($template, $opts)
|
||||||
{
|
{
|
||||||
$file_name = $this->_getCacheName($template, $opts);
|
$file_name = $this->getCompileName($template, $opts);
|
||||||
if (is_file($this->_compile_dir . "/" . $file_name)) {
|
if (is_file($this->_compile_dir . "/" . $file_name)) {
|
||||||
$fenom = $this; // used in template
|
$fenom = $this; // used in template
|
||||||
$_tpl = include($this->_compile_dir . "/" . $file_name);
|
$_tpl = include($this->_compile_dir . "/" . $file_name);
|
||||||
/* @var Fenom\Render $_tpl */
|
/* @var Fenom\Render $_tpl */
|
||||||
|
|
||||||
if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD) && $_tpl->isValid()) {
|
if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD)
|
||||||
|
&& $_tpl instanceof Fenom\Render
|
||||||
|
&& $_tpl->isValid()) {
|
||||||
return $_tpl;
|
return $_tpl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1045,12 +1065,13 @@ class Fenom
|
||||||
/**
|
/**
|
||||||
* Generate unique name of compiled template
|
* Generate unique name of compiled template
|
||||||
*
|
*
|
||||||
* @param string $tpl
|
* @param string|string[] $tpl
|
||||||
* @param int $options
|
* @param int $options additional options
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function _getCacheName($tpl, $options)
|
public function getCompileName($tpl, $options = 0)
|
||||||
{
|
{
|
||||||
|
$options = $this->_options | $options;
|
||||||
if (is_array($tpl)) {
|
if (is_array($tpl)) {
|
||||||
$hash = implode(".", $tpl) . ":" . $options;
|
$hash = implode(".", $tpl) . ":" . $options;
|
||||||
foreach ($tpl as &$t) {
|
foreach ($tpl as &$t) {
|
||||||
|
@ -1069,12 +1090,11 @@ class Fenom
|
||||||
* @param string|array $tpl
|
* @param string|array $tpl
|
||||||
* @param bool $store store template on disk
|
* @param bool $store store template on disk
|
||||||
* @param int $options
|
* @param int $options
|
||||||
* @throws RuntimeException
|
* @throws CompileException
|
||||||
* @return \Fenom\Template
|
* @return \Fenom\Template
|
||||||
*/
|
*/
|
||||||
public function compile($tpl, $store = true, $options = 0)
|
public function compile($tpl, $store = true, $options = 0)
|
||||||
{
|
{
|
||||||
$options = $this->_options | $options;
|
|
||||||
if (is_string($tpl)) {
|
if (is_string($tpl)) {
|
||||||
$template = $this->getRawTemplate()->load($tpl);
|
$template = $this->getRawTemplate()->load($tpl);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1084,17 +1104,15 @@ class Fenom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($store) {
|
if ($store) {
|
||||||
$cache = $this->_getCacheName($tpl, $options);
|
$cache_name = $this->getCompileName($tpl, $options);
|
||||||
$tpl_tmp = tempnam($this->_compile_dir, $cache);
|
$compile_path = $this->_compile_dir . "/" . $cache_name . "." . mt_rand(0, 100000) . ".tmp";
|
||||||
$tpl_fp = fopen($tpl_tmp, "w");
|
if(!file_put_contents($compile_path, $template->getTemplateCode())) {
|
||||||
if (!$tpl_fp) {
|
throw new CompileException("Can't to write to the file $compile_path. Directory " . $this->_compile_dir . " is writable?");
|
||||||
throw new \RuntimeException("Can't to open temporary file $tpl_tmp. Directory " . $this->_compile_dir . " is writable?");
|
|
||||||
}
|
}
|
||||||
fwrite($tpl_fp, $template->getTemplateCode());
|
$cache_path = $this->_compile_dir . "/" . $cache_name;
|
||||||
fclose($tpl_fp);
|
if (!rename($compile_path, $cache_path)) {
|
||||||
$file_name = $this->_compile_dir . "/" . $cache;
|
unlink($compile_path);
|
||||||
if (!rename($tpl_tmp, $file_name)) {
|
throw new CompileException("Can't to move the file $compile_path -> $cache_path");
|
||||||
throw new \RuntimeException("Can't to move $tpl_tmp to $file_name");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $template;
|
return $template;
|
||||||
|
|
|
@ -964,7 +964,7 @@ class Compiler
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
if($tokens->is('(') || !$tokens->isNext(')')){
|
if ($tokens->is('(') || !$tokens->isNext(')')) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
while ($tokens->is(Tokenizer::MACRO_STRING, T_VARIABLE)) {
|
while ($tokens->is(Tokenizer::MACRO_STRING, T_VARIABLE)) {
|
||||||
$param = $tokens->current();
|
$param = $tokens->current();
|
||||||
|
|
|
@ -102,7 +102,7 @@ class Template extends Render
|
||||||
*/
|
*/
|
||||||
private $_ignore = false;
|
private $_ignore = false;
|
||||||
|
|
||||||
private $_before;
|
private $_before = array();
|
||||||
|
|
||||||
private $_filters = array();
|
private $_filters = array();
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ class Template extends Render
|
||||||
*/
|
*/
|
||||||
public function before($code)
|
public function before($code)
|
||||||
{
|
{
|
||||||
$this->_before .= $code;
|
$this->_before[] = $code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -405,7 +405,7 @@ class Template extends Render
|
||||||
*/
|
*/
|
||||||
public function getTemplateCode()
|
public function getTemplateCode()
|
||||||
{
|
{
|
||||||
$before = $this->_before ? $this->_before . "\n" : "";
|
$before = $this->_before ? implode("\n", $this->_before) . "\n" : "";
|
||||||
return "<?php \n" .
|
return "<?php \n" .
|
||||||
"/** Fenom template '" . $this->_name . "' compiled at " . date('Y-m-d H:i:s') . " */\n" .
|
"/** Fenom template '" . $this->_name . "' compiled at " . date('Y-m-d H:i:s') . " */\n" .
|
||||||
$before . // some code 'before' template
|
$before . // some code 'before' template
|
||||||
|
@ -525,7 +525,7 @@ class Template extends Render
|
||||||
$parent = $this->_fenom->getRawTemplate()->load($tpl, false);
|
$parent = $this->_fenom->getRawTemplate()->load($tpl, false);
|
||||||
$parent->blocks = & $this->blocks;
|
$parent->blocks = & $this->blocks;
|
||||||
$parent->macros = & $this->macros;
|
$parent->macros = & $this->macros;
|
||||||
$parent->_before = & $this->_before;
|
$parent->_before = & $this->_before;
|
||||||
$parent->extended = $this->getName();
|
$parent->extended = $this->getName();
|
||||||
if (!$this->ext_stack) {
|
if (!$this->ext_stack) {
|
||||||
$this->ext_stack[] = $this->getName();
|
$this->ext_stack[] = $this->getName();
|
||||||
|
@ -798,12 +798,14 @@ class Template extends Render
|
||||||
}
|
}
|
||||||
$code = $this->parseScalar($tokens);
|
$code = $this->parseScalar($tokens);
|
||||||
break;
|
break;
|
||||||
|
/** @noinspection PhpMissingBreakStatementInspection */
|
||||||
case '$':
|
case '$':
|
||||||
$code = $this->parseAccessor($tokens, $is_var);
|
$code = $this->parseAccessor($tokens, $is_var);
|
||||||
if(!$is_var) {
|
if(!$is_var) {
|
||||||
$code = $unary . $code;
|
$code = $unary . $code;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* no break */
|
||||||
case T_VARIABLE:
|
case T_VARIABLE:
|
||||||
if(!isset($code)) {
|
if(!isset($code)) {
|
||||||
$code = $this->parseVariable($tokens);
|
$code = $this->parseVariable($tokens);
|
||||||
|
@ -1003,12 +1005,18 @@ class Template extends Render
|
||||||
$is_var = false;
|
$is_var = false;
|
||||||
if($parser) {
|
if($parser) {
|
||||||
if(is_array($parser)) {
|
if(is_array($parser)) {
|
||||||
return call_user_func_array($parser['parser'], array($parser['accessor'], $tokens->next(), $this, &$is_var));
|
if(isset($parser['callback'])) {
|
||||||
|
$tokens->next();
|
||||||
|
return 'call_user_func($tpl->getStorage()->getAccessor('.var_export($accessor, true).
|
||||||
|
', "callback"), '.var_export($accessor, true).', $tpl, $var)';
|
||||||
|
} else {
|
||||||
|
return call_user_func_array($parser['parser'], array($parser['accessor'], $tokens->next(), $this, &$is_var));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return call_user_func_array($parser, array($tokens->next(), $this, &$is_var));
|
return call_user_func_array($parser, array($tokens->next(), $this, &$is_var));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new \RuntimeException("Unknown accessor '$accessor'");
|
throw new \RuntimeException("Unknown accessor '\$.$accessor'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,7 +1033,7 @@ class Template extends Render
|
||||||
{
|
{
|
||||||
$empty = $tokens->is('?');
|
$empty = $tokens->is('?');
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
if ($tokens->is(":")) {
|
if ($tokens->is(":", "?")) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
if ($empty) {
|
if ($empty) {
|
||||||
if ($is_var) {
|
if ($is_var) {
|
||||||
|
|
|
@ -48,15 +48,20 @@ class TestCase extends \PHPUnit_Framework_TestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCompilePath()
|
||||||
|
{
|
||||||
|
return FENOM_RESOURCES . '/compile';
|
||||||
|
}
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
if (!file_exists(FENOM_RESOURCES . '/compile')) {
|
if (!file_exists($this->getCompilePath())) {
|
||||||
mkdir(FENOM_RESOURCES . '/compile', 0777, true);
|
mkdir($this->getCompilePath(), 0777, true);
|
||||||
} else {
|
} else {
|
||||||
FS::clean(FENOM_RESOURCES . '/compile/');
|
FS::clean($this->getCompilePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->fenom = Fenom::factory(FENOM_RESOURCES . '/' . $this->template_path, FENOM_RESOURCES . '/compile');
|
$this->fenom = Fenom::factory(FENOM_RESOURCES . '/' . $this->template_path, $this->getCompilePath());
|
||||||
$this->fenom->addProvider('persist', new Provider(FENOM_RESOURCES . '/provider'));
|
$this->fenom->addProvider('persist', new Provider(FENOM_RESOURCES . '/provider'));
|
||||||
$this->fenom->addModifier('dots', __CLASS__ . '::dots');
|
$this->fenom->addModifier('dots', __CLASS__ . '::dots');
|
||||||
$this->fenom->addModifier('concat', __CLASS__ . '::concat');
|
$this->fenom->addModifier('concat', __CLASS__ . '::concat');
|
||||||
|
|
|
@ -256,4 +256,21 @@ class AccessorTest extends TestCase
|
||||||
$this->fenom->addAccessorSmart($name, $accessor, $type);
|
$this->fenom->addAccessorSmart($name, $accessor, $type);
|
||||||
$this->assertRender($code, $result, $this->getVars());
|
$this->assertRender($code, $result, $this->getVars());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group dev
|
||||||
|
*/
|
||||||
|
public function testCallbackAccessor() {
|
||||||
|
$index = 1;
|
||||||
|
$test = $this;
|
||||||
|
$this->fenom->addAccessorCallback('index', function($name, $template, $vars) use (&$index, $test) {
|
||||||
|
$test->assertInstanceOf('Fenom\Render', $template);
|
||||||
|
$test->assertSame(1, $vars['one']);
|
||||||
|
$test->assertSame('index', $name);
|
||||||
|
|
||||||
|
return $index++;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertRender('{$.index}, {$.index}, {$.index}', '1, 2, 3', $this->getVars());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -116,6 +116,19 @@ class FenomTest extends \Fenom\TestCase
|
||||||
$this->assertSame("Custom template (new)", $this->fenom->fetch('custom.tpl', array()));
|
$this->assertSame("Custom template (new)", $this->fenom->fetch('custom.tpl', array()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group dev
|
||||||
|
*/
|
||||||
|
public function testCompileIdAndName()
|
||||||
|
{
|
||||||
|
$this->fenom->setCompileId("iddqd.");
|
||||||
|
$this->tpl('custom.tpl', 'Custom template');
|
||||||
|
$this->assertSame("Custom template", $this->fenom->fetch('custom.tpl', array()));
|
||||||
|
$compile_name = $this->fenom->getCompileName('custom.tpl');
|
||||||
|
$this->assertFileExists($this->getCompilePath().'/'.$compile_name);
|
||||||
|
$this->assertStringStartsWith('iddqd.', $compile_name);
|
||||||
|
}
|
||||||
|
|
||||||
public function testSetModifier()
|
public function testSetModifier()
|
||||||
{
|
{
|
||||||
$this->fenom->addModifier("mymod", "myMod");
|
$this->fenom->addModifier("mymod", "myMod");
|
||||||
|
|
Loading…
Reference in New Issue