Done #66, dev dynamic extends

This commit is contained in:
Ivan Shalganov
2014-02-22 20:34:53 +04:00
parent 3adafb6fcc
commit a523d4a4aa
29 changed files with 174 additions and 92 deletions

View File

@@ -466,75 +466,46 @@ class Compiler
* Dispatch {extends} tag
* @param Tokenizer $tokens
* @param Template $tpl
* @throws InvalidUsageException
* @throws \RuntimeException
* @throws Error\InvalidUsageException
* @return string
*/
public static function tagExtends(Tokenizer $tokens, Template $tpl)
{
if (!empty($tpl->_extends)) {
if ($tpl->extends) {
throw new InvalidUsageException("Only one {extends} allowed");
} elseif ($tpl->getStackSize()) {
throw new InvalidUsageException("Tags {extends} can not be nested");
}
$tpl_name = $tpl->parsePlainArg($tokens, $name);
if (empty($tpl->_extended)) {
$cname = $tpl->parsePlainArg($tokens, $name);
if($name) {
$tpl->extends = $name;
} else {
$tpl->dynamic_extends = $cname;
}
if(!$tpl->extended) {
$tpl->addPostCompile(__CLASS__ . "::extendBody");
}
if ($tpl->getOptions() & Template::DYNAMIC_EXTEND) {
$tpl->_compatible = true;
}
if ($name) { // static extends
$tpl->_extends = $tpl->getStorage()->getRawTemplate()->load($name, false);
if (!isset($tpl->_compatible)) {
$tpl->_compatible = & $tpl->_extends->_compatible;
}
$tpl->addDepend($tpl->_extends);
return "";
} else { // dynamic extends
if (!isset($tpl->_compatible)) {
$tpl->_compatible = true;
}
$tpl->_extends = $tpl_name;
return '$parent = $tpl->getStorage()->getTemplate(' . $tpl_name . ', \Fenom\Template::EXTENDED);';
}
}
/**
* Post compile action for {extends ...} tag
* @param string $body
* @param Template $tpl
* @param string $body
*/
public static function extendBody(&$body, $tpl)
public static function extendBody($tpl, &$body)
{
$t = $tpl;
if ($tpl->uses) {
$tpl->blocks += $tpl->uses;
}
while (isset($t->_extends)) {
$t = $t->_extends;
if (is_object($t)) {
/* @var \Fenom\Template $t */
$t->_extended = true;
$tpl->addDepend($t);
$t->_compatible = & $tpl->_compatible;
$t->blocks = & $tpl->blocks;
$t->compile();
if ($t->uses) {
$tpl->blocks += $t->uses;
}
if (!isset($t->_extends)) { // last item => parent
if (empty($tpl->_compatible)) {
$body = $t->getBody();
} else {
$body = '<?php ob_start(); ?>' . $body . '<?php ob_end_clean(); ?>' . $t->getBody();
}
return;
} else {
$body .= $t->getBody();
}
} else {
$body = '<?php ob_start(); ?>' . $body . '<?php ob_end_clean(); $parent->b = &$tpl->b; $parent->display((array)$tpl); unset($tpl->b, $parent->b); ?>';
return;
if($tpl->dynamic_extends) {
$body = "";
foreach($tpl->blocks as $name => $block) {
$body .= '<?php $tpl->blocks["'.$name.'"] = function ($var, $tpl) { ?>'.PHP_EOL.$block['block'].'<?php } ?>'.PHP_EOL.PHP_EOL;
}
$body .= '<?php $tpl->getStorage()->getTemplate('.$tpl->dynamic_extends.', \Fenom\Template::DYNAMIC_EXTEND)->display($var); ?>';
} else {
$child = $tpl;
while($child && $child->extends) {
$parent = $tpl->extend($child->extends);
$child = $parent->extends ? $parent : false;
}
}
}
@@ -587,6 +558,7 @@ class Compiler
{
$tpl = $scope->tpl;
$name = $scope["name"];
if(isset($tpl->blocks[$name])) { // block defined
$block = &$tpl->blocks[$name];
if($block['use_parent']) {
@@ -602,6 +574,7 @@ class Compiler
$scope->replaceContent($block["block"]);
}
}
$tpl->blocks[$scope["name"]] = [
"from" => $tpl->getName(),
"import" => false,

View File

@@ -27,6 +27,7 @@ class Scope extends \ArrayObject
public $is_compiler = true;
public $is_closed = false;
public $escape = false;
public $options = [];
private $_action;
private $_body;
private $_offset;

View File

@@ -55,9 +55,9 @@ class Template extends Render
*/
public $blocks = array();
public $uses = array();
// public $uses = array();
public $parents = array();
// public $parents = array();
/**
* Escape outputs value
@@ -65,9 +65,16 @@ class Template extends Render
*/
public $escape = false;
public $_extends;
public $_extended = false;
public $_compatible;
/**
* @var string|null
*/
public $extends;
/**
* @var string|null
*/
public $extended;
// public $_compatible;
/**
* Template PHP code
@@ -221,7 +228,7 @@ class Template extends Render
$end = $pos = 0;
$this->escape = $this->_options & Fenom::AUTO_ESCAPE;
foreach ($this->_fenom->getPreFilters() as $filter) {
$this->_src = call_user_func($filter, $this->_src, $this);
$this->_src = call_user_func($filter, $this, $this->_src);
}
while (($start = strpos($this->_src, '{', $pos)) !== false) { // search open-symbol of tags
@@ -303,12 +310,12 @@ class Template extends Render
$this->_src = ""; // cleanup
if ($this->_post) {
foreach ($this->_post as $cb) {
call_user_func_array($cb, array(&$this->_body, $this));
call_user_func_array($cb, array($this, &$this->_body));
}
}
$this->addDepend($this); // for 'verify' performance
foreach ($this->_fenom->getPostFilters() as $filter) {
$this->_body = call_user_func($filter, $this->_body, $this);
$this->_body = call_user_func($filter, $this, $this->_body);
}
}
@@ -342,7 +349,7 @@ class Template extends Render
if ($this->_filters) {
if (strpos($text, "<?") === false) {
foreach ($this->_filters as $filter) {
$text = call_user_func($filter, $text, $this);
$text = call_user_func($filter, $this, $text);
}
$this->_body .= $text;
} else {
@@ -350,7 +357,7 @@ class Template extends Render
foreach ($fragments as &$fragment) {
if ($fragment) {
foreach ($this->_filters as $filter) {
$fragment = call_user_func($filter, $fragment, $this);
$fragment = call_user_func($filter, $this, $fragment);
}
}
}
@@ -508,16 +515,21 @@ class Template extends Render
/**
* Extends the template
* @param string $tpl
* @return \Fenom\Template parent
*/
public function extend($tpl) {
$this->compile();
if(!$this->_body) {
$this->compile();
}
$parent = $this->_fenom->getRawTemplate()->load($tpl, false);
$parent->blocks = &$this->blocks;
$parent->extended = $this->getName();
$parent->_options = $this->_options;
$parent->compile();
$this->_body = $parent->_body;
$this->_src = $parent->_src;
$this->addDepend($parent);
return $parent;
}
/**

View File

@@ -84,6 +84,7 @@ class Tokenizer
public $tokens;
public $p = 0;
public $quotes = 0;
public $options;
private $_max = 0;
private $_last_no = 0;