* @author Kornel LesiĆski
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
* @version SVN: $Id: Define.php 605 2009-05-03 02:50:26Z kornel $
* @link http://phptal.org/
*/
/**
* TAL spec 1.4 for tal:define content
*
* argument ::= define_scope [';' define_scope]*
* define_scope ::= (['local'] | 'global') define_var
* define_var ::= variable_name expression
* variable_name ::= Name
*
* Note: If you want to include a semi-colon (;) in an expression, it must be escaped by doubling it (;;).*
*
* examples:
*
* tal:define="mytitle template/title; tlen python:len(mytitle)"
* tal:define="global company_name string:Digital Creations, Inc."
*
*
*
* @package PHPTAL
* @subpackage Php.attribute.tal
* @author Laurent Bedubourg
*/
class PHPTAL_Php_Attribute_TAL_Define
extends PHPTAL_Php_Attribute
implements PHPTAL_Php_TalesChainReader
{
private $tmp_content_var;
private $_buffered = false;
private $_defineScope = null;
private $_defineVar = null;
private $_pushedContext = false;
public function before(PHPTAL_Php_CodeWriter $codewriter)
{
$expressions = $codewriter->splitExpression($this->expression);
$definesAnyNonGlobalVars = false;
foreach ($expressions as $exp) {
list($defineScope, $defineVar, $expression) = $this->parseExpression($exp);
if (!$defineVar) {
continue;
}
$this->_defineScope = $defineScope;
if ($defineScope != 'global') $definesAnyNonGlobalVars = true; // should be invisible, but
not
if ($this->_defineScope != 'global' && !$this->_pushedContext) {
$codewriter->pushContext();
$this->_pushedContext = true;
}
$this->_defineVar = $defineVar;
if ($expression === null) {
// no expression give, use content of tag as value for newly defined
// var.
$this->bufferizeContent($codewriter);
continue;
}
$code = $codewriter->evaluateExpression($expression);
if (is_array($code)) {
$this->chainedDefine($codewriter, $code);
} elseif ( $code == PHPTAL_Php_TalesInternal::NOTHING_KEYWORD) {
$this->doDefineVarWith($codewriter, 'null');
} else {
$this->doDefineVarWith($codewriter, $code);
}
}
// if the content of the tag was buffered or the tag has nothing to tell, we hide it.
if ($this->_buffered || (!$definesAnyNonGlobalVars && !$this->phpelement->hasRealContent() && !$this->phpelement->hasRealAttributes())) {
$this->phpelement->hidden = true;
}
}
public function after(PHPTAL_Php_CodeWriter $codewriter)
{
if ($this->tmp_content_var) $codewriter->recycleTempVariable($this->tmp_content_var);
if ($this->_pushedContext) {
$codewriter->popContext();
}
}
private function chainedDefine(PHPTAL_Php_CodeWriter $codewriter, $parts)
{
$executor = new PHPTAL_Php_TalesChainExecutor(
$codewriter, $parts, $this
);
}
public function talesChainNothingKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$this->doDefineVarWith($executor->getCodeWriter(), 'null');
$executor->breakChain();
}
public function talesChainDefaultKeyword(PHPTAL_Php_TalesChainExecutor $executor)
{
$executor->doElse();
$this->bufferizeContent($executor->getCodeWriter());
$executor->breakChain();
}
public function talesChainPart(PHPTAL_Php_TalesChainExecutor $executor, $exp, $islast)
{
if ($this->_defineScope == 'global') {
$var = '$tpl->getGlobalContext()->'.$this->_defineVar;
} else {
$var = '$ctx->'.$this->_defineVar;
}
$cw = $executor->getCodeWriter();
if (!$islast) {
// must use temp variable, because expression could refer to itself
$tmp = $cw->createTempVariable();
$executor->doIf('('.$tmp.' = '.$exp.') !== null');
$cw->doSetVar($var, $tmp);
$cw->recycleTempVariable($tmp);
} else {
$executor->doIf('('.$var.' = '.$exp.') !== null');
}
}
/**
* Parse the define expression, already splitted in sub parts by ';'.
*/
public function parseExpression($exp)
{
$defineScope = false; // (local | global)
$defineVar = false; // var to define
// extract defineScope from expression
$exp = trim($exp);
if (preg_match('/^(local|global)\s+(.*?)$/ism', $exp, $m)) {
list(,$defineScope, $exp) = $m;
$exp = trim($exp);
}
// extract varname and expression from remaining of expression
list($defineVar, $exp) = $this->parseSetExpression($exp);
if ($exp !== null) $exp = trim($exp);
return array($defineScope, $defineVar, $exp);
}
private function bufferizeContent(PHPTAL_Php_CodeWriter $codewriter)
{
if (!$this->_buffered) {
$this->tmp_content_var = $codewriter->createTempVariable();
$codewriter->pushCode( 'ob_start()' );
$this->phpelement->generateContent($codewriter);
$codewriter->doSetVar($this->tmp_content_var, 'ob_get_clean()');
$this->_buffered = true;
}
$this->doDefineVarWith($codewriter, $this->tmp_content_var);
}
private function doDefineVarWith(PHPTAL_Php_CodeWriter $codewriter, $code)
{
if ($this->_defineScope == 'global') {
$codewriter->doSetVar('$tpl->getGlobalContext()->'.$this->_defineVar, $code);
} else {
$codewriter->doSetVar('$ctx->'.$this->_defineVar, $code);
}
}
}