streams/library/Smarty/libs/sysplugins/smarty_internal_runtime_inheritance.php
2015-12-06 23:12:37 +01:00

213 lines
6.6 KiB
PHP

<?php
/**
* Inheritance Runtime Methods processBlock, endChild, init
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_Inheritance
{
/**
* State machine
* - 0 idle next extends will create a new inheritance tree
* - 1 processing child template
* - 2 wait for next inheritance template
* - 3 assume parent template, if child will loaded goto state 1
* a call to a sub template resets the state to 0
*
* @var int
*/
public $state = 0;
/**
* Array of block parameter of known {block} tags
*
* @var array
*/
public $blockParameter = array();
/**
* inheritance template nesting level
*
* @var int
*/
public $inheritanceLevel = 0;
/**
* inheritance template index
*
* @var int
*/
public $tplIndex = - 1;
/**
* Array of compiled template file path
* - key template index
* only used when caching is enabled
*
* @var []string
*/
public $compiledFilePath = array();
/**
* Current {block} nesting level
*
* @var int
*/
public $blockNesting = 0;
/**
* Initialize inheritance
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param bool $initChild if true init for child template
* @param array $blockNames outer level block name
*
*/
public function init(Smarty_Internal_Template $tpl, $initChild, $blockNames = array())
{
// if template was from an inner block or template is a parent template create new inheritance root
if ($initChild && ($this->blockNesting || $this->state == 3)) {
$tpl->ext->_inheritance = new Smarty_Internal_Runtime_Inheritance();
$tpl->ext->_inheritance->init($tpl, $initChild, $blockNames);
return;
}
// start of child sub template(s)
if ($initChild) {
$this->state = 1;
if (!$this->inheritanceLevel) {
//grab any output of child templates
ob_start();
}
$this->inheritanceLevel ++;
}
// in parent state {include} will not increment template index
if ($this->state != 3) {
$this->tplIndex ++;
}
// if state was waiting for parent change state to parent
if ($this->state == 2) {
$this->state = 3;
}
}
/**
* End of child template(s)
* - if outer level is reached flush output buffer and switch to wait for parent template state
*
* @param \Smarty_Internal_Template $tpl template object of caller
*/
public function endChild(Smarty_Internal_Template $tpl)
{
$this->inheritanceLevel --;
if (!$this->inheritanceLevel) {
ob_end_clean();
$this->state = 2;
}
}
/**
* Process inheritance {block} tag
*
* $type 0 = {block}:
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise call current block
* - ignored for outer level blocks in child templates
*
* $type 1 = {block}:
* - nested {block}
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise call current block
*
* $type 2 = {$smarty.block.child}:
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise ignore
*
* $type 3 = {$smarty.block.parent}:
* - get block id from parent stack and call parent block
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param int $type call type see above
* @param string $name block name
* @param array $block block parameter
* @param array $callStack call stack with block parameters
*
* @throws \SmartyException
*/
public function processBlock(Smarty_Internal_Template $tpl, $type = 0, $name, $block, $callStack = array())
{
if (!isset($this->blockParameter[$name])) {
$this->blockParameter[$name] = array();
}
if ($this->state == 1) {
$block[2] = count($this->blockParameter[$name]);
$block[3] = $this->tplIndex;
$this->blockParameter[$name][] = $block;
return;
}
if ($type == 3) {
if (!empty($callStack)) {
array_shift($callStack);
if (empty($callStack)) {
throw new SmartyException("inheritance: tag {\$smarty.block.parent} used in parent template block '{$name}'");
}
$block = array_shift($callStack);
} else {
return;
}
} else {
$blockParameter = &$this->blockParameter[$name];
if ($type == 0) {
$index = $block[2] = count($blockParameter);
$block[3] = $this->tplIndex;
$callStack = array(&$block);
} elseif ($type == 1) {
$block[3] = $callStack[0][3];
$index = 0;
for ($i = 0; $i < count($blockParameter); $i ++) {
if ($blockParameter[$i][3] <= $block[3]) {
$index = $blockParameter[$i][2];
}
}
$block[2] = $index;
$callStack = array(&$block);
} else {
$index = $callStack[0][2];
if ($index == 0) {
return;
}
$callStack = $block = array(1 => false);
}
$index --;
// find lowest level child block
while ($index >= 0 && ($type || !$block[1])) {
$block = &$blockParameter[$index];
array_unshift($callStack, $block);
if ($block[1]) {
break;
}
$index --;
}
if (isset($block['hide']) && $index <= 0) {
return;
}
}
$this->blockNesting ++;
if (isset($block['append'])) {
$this->processBlock($tpl, 3, $name, null, $callStack);
}
if (isset($block[6])) {
$block[6]($tpl, $callStack);
} else {
$block[0]($tpl, $callStack);
}
if (isset($block['prepend'])) {
$this->processBlock($tpl, 3, $name, null, $callStack);
}
$this->blockNesting --;
}
}