2013-01-25 18:36:16 +04:00
|
|
|
<?php
|
2013-04-28 11:33:36 +04:00
|
|
|
/*
|
2013-06-28 11:53:53 +04:00
|
|
|
* This file is part of Fenom.
|
2013-04-28 11:33:36 +04:00
|
|
|
*
|
|
|
|
* (c) 2013 Ivan Shalganov
|
|
|
|
*
|
2013-04-28 18:08:57 +04:00
|
|
|
* For the full copyright and license information, please view the license.md
|
2013-04-28 11:33:36 +04:00
|
|
|
* file that was distributed with this source code.
|
|
|
|
*/
|
2013-06-28 11:53:53 +04:00
|
|
|
namespace Fenom;
|
|
|
|
use Fenom\Tokenizer;
|
|
|
|
use Fenom\Template;
|
|
|
|
use Fenom\Scope;
|
2013-01-25 18:36:16 +04:00
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* Compilers collection
|
2013-06-28 11:53:53 +04:00
|
|
|
* @package Fenom
|
2013-07-04 01:28:10 +04:00
|
|
|
* @author Ivan Shalganov <a.cobest@gmail.com>
|
2013-02-07 17:37:16 +04:00
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
class Compiler
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
/**
|
|
|
|
* Tag {include ...}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Template $tpl
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagInclude(Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
2013-04-28 11:33:36 +04:00
|
|
|
$cname = $tpl->parsePlainArg($tokens, $name);
|
2013-02-23 16:35:11 +04:00
|
|
|
$p = $tpl->parseParams($tokens);
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p) { // if we have additionally variables
|
|
|
|
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { // if FORCE_INCLUDE enabled and template name known
|
2013-02-20 19:51:06 +04:00
|
|
|
$inc = $tpl->getStorage()->compile($name, false);
|
|
|
|
$tpl->addDepend($inc);
|
2013-07-29 14:58:14 +04:00
|
|
|
return '$_tpl = (array)$tpl; $tpl->exchangeArray(' . self::toArray($p) . '+$_tpl); ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
2013-02-20 19:51:06 +04:00
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
return '$tpl->getStorage()->getTemplate(' . $cname . ')->display(' . self::toArray($p) . '+(array)$tpl);';
|
2013-02-20 19:51:06 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { // if FORCE_INCLUDE enabled and template name known
|
2013-02-20 19:51:06 +04:00
|
|
|
$inc = $tpl->getStorage()->compile($name, false);
|
|
|
|
$tpl->addDepend($inc);
|
2013-07-29 14:58:14 +04:00
|
|
|
return '$_tpl = (array)$tpl; ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
2013-02-20 19:51:06 +04:00
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
return '$tpl->getStorage()->getTemplate(' . $cname . ')->display((array)$tpl);';
|
2013-02-20 19:51:06 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-02-23 16:35:11 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open tag {if ...}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function ifOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$scope["else"] = false;
|
2013-07-29 14:58:14 +04:00
|
|
|
return 'if(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
2013-02-23 16:35:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {elseif ...}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-02-23 16:35:11 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagElseIf(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if ($scope["else"]) {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException('Incorrect use of the tag {elseif}');
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
return '} elseif(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
2013-02-23 16:35:11 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {else}
|
|
|
|
*
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @internal param $
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagElse(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$scope["else"] = true;
|
2013-02-23 16:35:11 +04:00
|
|
|
return '} else {';
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Open tag {foreach ...}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-03-15 00:12:02 +04:00
|
|
|
* @throws UnexpectedTokenException
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function foreachOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$p = array("index" => false, "first" => false, "last" => false);
|
|
|
|
$key = null;
|
|
|
|
$before = $body = array();
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is(T_VARIABLE)) {
|
2013-03-17 14:37:23 +04:00
|
|
|
$from = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
2013-01-25 18:36:16 +04:00
|
|
|
$prepend = "";
|
2013-07-29 14:58:14 +04:00
|
|
|
} elseif ($tokens->is('[')) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$from = $scope->tpl->parseArray($tokens);
|
2013-07-29 14:58:14 +04:00
|
|
|
$uid = '$v' . $scope->tpl->i++;
|
|
|
|
$prepend = $uid . ' = ' . $from . ';';
|
2013-01-25 18:36:16 +04:00
|
|
|
$from = $uid;
|
|
|
|
} else {
|
2013-03-15 00:12:02 +04:00
|
|
|
throw new UnexpectedTokenException($tokens, null, "tag {foreach}");
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
$tokens->get(T_AS);
|
|
|
|
$tokens->next();
|
2013-03-17 14:37:23 +04:00
|
|
|
$value = $scope->tpl->parseVariable($tokens, Template::DENY_MODS | Template::DENY_ARRAY);
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is(T_DOUBLE_ARROW)) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$tokens->next();
|
|
|
|
$key = $value;
|
2013-03-17 14:37:23 +04:00
|
|
|
$value = $scope->tpl->parseVariable($tokens, Template::DENY_MODS | Template::DENY_ARRAY);
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
$scope["after"] = array();
|
|
|
|
$scope["else"] = false;
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
while ($token = $tokens->key()) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$param = $tokens->get(T_STRING);
|
2013-07-29 14:58:14 +04:00
|
|
|
if (!isset($p[$param])) {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Unknown parameter '$param' in {foreach}");
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
$tokens->getNext("=");
|
|
|
|
$tokens->next();
|
2013-07-29 14:58:14 +04:00
|
|
|
$p[$param] = $scope->tpl->parseVariable($tokens, Template::DENY_MODS | Template::DENY_ARRAY);
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["index"]) {
|
|
|
|
$before[] = $p["index"] . ' = 0';
|
|
|
|
$scope["after"][] = $p["index"] . '++';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["first"]) {
|
|
|
|
$before[] = $p["first"] . ' = true';
|
|
|
|
$scope["after"][] = $p["first"] . ' && (' . $p["first"] . ' = false )';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["last"]) {
|
|
|
|
$before[] = $p["last"] . ' = false';
|
|
|
|
$scope["uid"] = "v" . $scope->tpl->i++;
|
|
|
|
$before[] = '$' . $scope["uid"] . " = count($from)";
|
|
|
|
$body[] = 'if(!--$' . $scope["uid"] . ') ' . $p["last"] . ' = true';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
$before = $before ? implode("; ", $before) . ";" : "";
|
|
|
|
$body = $body ? implode("; ", $body) . ";" : "";
|
|
|
|
$scope["after"] = $scope["after"] ? implode("; ", $scope["after"]) . ";" : "";
|
|
|
|
if ($key) {
|
2013-01-25 18:36:16 +04:00
|
|
|
return "$prepend if($from) { $before foreach($from as $key => $value) { $body";
|
|
|
|
} else {
|
|
|
|
return "$prepend if($from) { $before foreach($from as $value) { $body";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {foreachelse}
|
|
|
|
*
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function foreachElse($tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$scope["no-break"] = $scope["no-continue"] = $scope["else"] = true;
|
|
|
|
return " {$scope['after']} } } else {";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Close tag {/foreach}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function foreachClose($tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if ($scope["else"]) {
|
2013-01-25 18:36:16 +04:00
|
|
|
return '}';
|
|
|
|
} else {
|
|
|
|
return " {$scope['after']} } }";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-01-25 18:36:16 +04:00
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function forOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$p = array("index" => false, "first" => false, "last" => false, "step" => 1, "to" => false, "max" => false, "min" => false);
|
|
|
|
$scope["after"] = $before = $body = array();
|
|
|
|
$i = array('', '');
|
|
|
|
$c = "";
|
2013-03-17 14:37:23 +04:00
|
|
|
$var = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
2013-01-25 18:36:16 +04:00
|
|
|
$tokens->get("=");
|
|
|
|
$tokens->next();
|
|
|
|
$val = $scope->tpl->parseExp($tokens, true);
|
|
|
|
$p = $scope->tpl->parseParams($tokens, $p);
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
if (is_numeric($p["step"])) {
|
|
|
|
if ($p["step"] > 0) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$condition = "$var <= {$p['to']}";
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["last"]) $c = "($var + {$p['step']}) > {$p['to']}";
|
|
|
|
} elseif ($p["step"] < 0) {
|
2013-01-25 18:36:16 +04:00
|
|
|
$condition = "$var >= {$p['to']}";
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["last"]) $c = "($var + {$p['step']}) < {$p['to']}";
|
2013-01-25 18:36:16 +04:00
|
|
|
} else {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Invalid step value if {for}");
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$condition = "({$p['step']} > 0 && $var <= {$p['to']} || {$p['step']} < 0 && $var >= {$p['to']})";
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["last"]) $c = "({$p['step']} > 0 && ($var + {$p['step']}) <= {$p['to']} || {$p['step']} < 0 && ($var + {$p['step']}) >= {$p['to']})";
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["first"]) {
|
|
|
|
$before[] = $p["first"] . ' = true';
|
|
|
|
$scope["after"][] = $p["first"] . ' && (' . $p["first"] . ' = false )';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["last"]) {
|
|
|
|
$before[] = $p["last"] . ' = false';
|
2013-01-25 18:36:16 +04:00
|
|
|
$body[] = "if($c) {$p['last']} = true";
|
|
|
|
}
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($p["index"]) {
|
|
|
|
$i[0] .= $p["index"] . ' = 0,';
|
|
|
|
$i[1] .= $p["index"] . '++,';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
$scope["else"] = false;
|
|
|
|
$scope["else_cond"] = "$var==$val";
|
2013-07-29 14:58:14 +04:00
|
|
|
$before = $before ? implode("; ", $before) . ";" : "";
|
|
|
|
$body = $body ? implode("; ", $body) . ";" : "";
|
|
|
|
$scope["after"] = $scope["after"] ? implode("; ", $scope["after"]) . ";" : "";
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
return "$before for({$i[0]} $var=$val; $condition;{$i[1]} $var+={$p['step']}) { $body";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function forElse(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$scope["no-break"] = $scope["no-continue"] = true;
|
|
|
|
$scope["else"] = true;
|
|
|
|
return " } if({$scope['else_cond']}) {";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function forClose($tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if ($scope["else"]) {
|
2013-01-25 18:36:16 +04:00
|
|
|
return '}';
|
|
|
|
} else {
|
|
|
|
return " {$scope['after']} }";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function whileOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
return 'while(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open tag {switch}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function switchOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$scope["no-break"] = $scope["no-continue"] = true;
|
2013-07-29 14:58:14 +04:00
|
|
|
$scope["switch"] = 'switch(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
2013-02-20 19:51:06 +04:00
|
|
|
// lazy init
|
2013-01-25 18:36:16 +04:00
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {case ...}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagCase(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
$code = 'case ' . $scope->tpl->parseExp($tokens, true) . ': ';
|
|
|
|
if ($scope["switch"]) {
|
2013-01-25 18:36:16 +04:00
|
|
|
unset($scope["no-break"], $scope["no-continue"]);
|
2013-07-29 14:58:14 +04:00
|
|
|
$code = $scope["switch"] . "\n" . $code;
|
2013-01-25 18:36:16 +04:00
|
|
|
$scope["switch"] = "";
|
|
|
|
}
|
|
|
|
return $code;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {continue}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagContinue($tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if (empty($scope["no-continue"])) {
|
2013-02-23 16:35:11 +04:00
|
|
|
return 'continue;';
|
2013-01-25 18:36:16 +04:00
|
|
|
} else {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Improper usage of the tag {continue}");
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-02-23 16:35:11 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {default}
|
|
|
|
*
|
|
|
|
* @static
|
2013-02-20 19:51:06 +04:00
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagDefault($tokens, Scope $scope)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$code = 'default: ';
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($scope["switch"]) {
|
2013-01-25 18:36:16 +04:00
|
|
|
unset($scope["no-break"], $scope["no-continue"]);
|
2013-07-29 14:58:14 +04:00
|
|
|
$code = $scope["switch"] . "\n" . $code;
|
2013-01-25 18:36:16 +04:00
|
|
|
$scope["switch"] = "";
|
|
|
|
}
|
2013-02-23 16:35:11 +04:00
|
|
|
return $code;
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {break}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagBreak($tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if (empty($scope["no-break"])) {
|
2013-01-25 18:36:16 +04:00
|
|
|
return 'break;';
|
|
|
|
} else {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Improper usage of the tag {break}");
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-02-23 16:35:11 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
2013-02-23 16:35:11 +04:00
|
|
|
/**
|
|
|
|
* Dispatch {extends} tag
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Template $tpl
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-02-23 16:35:11 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagExtends(Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
|
|
|
if (!empty($tpl->_extends)) {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Only one {extends} allowed");
|
2013-07-29 14:58:14 +04:00
|
|
|
} elseif ($tpl->getStackSize()) {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Tags {extends} can not be nested");
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
2013-04-28 11:33:36 +04:00
|
|
|
$tpl_name = $tpl->parsePlainArg($tokens, $name);
|
2013-07-29 14:58:14 +04:00
|
|
|
if (empty($tpl->_extended)) {
|
|
|
|
$tpl->addPostCompile(__CLASS__ . "::extendBody");
|
2013-03-04 12:40:32 +04:00
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tpl->getOptions() & Template::DYNAMIC_EXTEND) {
|
2013-04-04 10:56:44 +04:00
|
|
|
$tpl->_compatible = true;
|
2013-05-19 02:04:52 +04:00
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($name) { // static extends
|
2013-02-23 16:35:11 +04:00
|
|
|
$tpl->_extends = $tpl->getStorage()->getRawTemplate()->load($name, false);
|
2013-07-29 14:58:14 +04:00
|
|
|
if (!isset($tpl->_compatible)) {
|
|
|
|
$tpl->_compatible = & $tpl->_extends->_compatible;
|
2013-05-17 22:20:29 +04:00
|
|
|
}
|
2013-04-04 10:56:44 +04:00
|
|
|
$tpl->addDepend($tpl->_extends);
|
2013-02-23 16:35:11 +04:00
|
|
|
return "";
|
2013-02-07 17:37:16 +04:00
|
|
|
} else { // dynamic extends
|
2013-07-29 14:58:14 +04:00
|
|
|
if (!isset($tpl->_compatible)) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$tpl->_compatible = true;
|
2013-05-19 02:04:52 +04:00
|
|
|
}
|
2013-07-03 12:10:50 +04:00
|
|
|
$tpl->_extends = $tpl_name;
|
2013-07-29 14:58:14 +04:00
|
|
|
return '$parent = $tpl->getStorage()->getTemplate(' . $tpl_name . ', \Fenom\Template::EXTENDED);';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
2013-03-04 12:40:32 +04:00
|
|
|
* Post compile action for {extends ...} tag
|
2013-06-08 00:08:00 +04:00
|
|
|
* @param string $body
|
2013-02-07 17:37:16 +04:00
|
|
|
* @param Template $tpl
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function extendBody(&$body, $tpl)
|
|
|
|
{
|
2013-07-03 12:10:50 +04:00
|
|
|
$t = $tpl;
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tpl->uses) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$tpl->blocks += $tpl->uses;
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
while (isset($t->_extends)) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$t = $t->_extends;
|
2013-07-29 14:58:14 +04:00
|
|
|
if (is_object($t)) {
|
2013-07-03 12:10:50 +04:00
|
|
|
/* @var \Fenom\Template $t */
|
|
|
|
$t->_extended = true;
|
|
|
|
$tpl->addDepend($t);
|
2013-07-29 14:58:14 +04:00
|
|
|
$t->_compatible = & $tpl->_compatible;
|
|
|
|
$t->blocks = & $tpl->blocks;
|
2013-07-03 12:10:50 +04:00
|
|
|
$t->compile();
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($t->uses) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$tpl->blocks += $t->uses;
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if (!isset($t->_extends)) { // last item => parent
|
|
|
|
if (empty($tpl->_compatible)) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$body = $t->getBody();
|
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
$body = '<?php ob_start(); ?>' . $body . '<?php ob_end_clean(); ?>' . $t->getBody();
|
2013-07-03 12:10:50 +04:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
$body .= $t->getBody();
|
|
|
|
}
|
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
$body = '<?php ob_start(); ?>' . $body . '<?php ob_end_clean(); $parent->b = &$tpl->b; $parent->display((array)$tpl); unset($tpl->b, $parent->b); ?>';
|
2013-07-03 12:10:50 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-20 19:51:06 +04:00
|
|
|
/**
|
2013-04-28 11:33:36 +04:00
|
|
|
* Tag {use ...}
|
2013-02-20 19:51:06 +04:00
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Template $tpl
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-03-04 12:40:32 +04:00
|
|
|
* @return string
|
2013-02-20 19:51:06 +04:00
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagUse(Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
|
|
|
if ($tpl->getStackSize()) {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Tags {use} can not be nested");
|
|
|
|
}
|
2013-06-08 00:08:00 +04:00
|
|
|
$cname = $tpl->parsePlainArg($tokens, $name);
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($name) {
|
2013-03-04 12:40:32 +04:00
|
|
|
$donor = $tpl->getStorage()->getRawTemplate()->load($name, false);
|
|
|
|
$donor->_extended = true;
|
2013-07-03 12:10:50 +04:00
|
|
|
$donor->_extends = $tpl;
|
2013-07-29 14:58:14 +04:00
|
|
|
$donor->_compatible = & $tpl->_compatible;
|
2013-07-03 12:10:50 +04:00
|
|
|
//$donor->blocks = &$tpl->blocks;
|
|
|
|
$donor->compile();
|
|
|
|
$blocks = $donor->blocks;
|
2013-07-29 14:58:14 +04:00
|
|
|
foreach ($blocks as $name => $code) {
|
|
|
|
if (isset($tpl->blocks[$name])) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$tpl->blocks[$name] = $code;
|
|
|
|
unset($blocks[$name]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$tpl->uses = $blocks + $tpl->uses;
|
|
|
|
$tpl->addDepend($donor);
|
2013-07-29 14:58:14 +04:00
|
|
|
return '?>' . $donor->getBody() . '<?php ';
|
2013-03-04 12:40:32 +04:00
|
|
|
} else {
|
2013-07-02 11:07:33 +04:00
|
|
|
// throw new InvalidUsageException('template name must be given explicitly yet');
|
|
|
|
// under construction
|
|
|
|
$tpl->_compatible = true;
|
2013-07-29 14:58:14 +04:00
|
|
|
return '$donor = $tpl->getStorage()->getTemplate(' . $cname . ', \Fenom\Template::EXTENDED);' . PHP_EOL .
|
|
|
|
'$donor->fetch((array)$tpl);' . PHP_EOL .
|
2013-07-03 12:10:50 +04:00
|
|
|
'$tpl->b += (array)$donor->b';
|
2013-02-20 19:51:06 +04:00
|
|
|
}
|
2013-02-23 16:35:11 +04:00
|
|
|
}
|
2013-02-07 17:37:16 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag {block ...}
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
|
|
|
* @return string
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-02-07 17:37:16 +04:00
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagBlockOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if ($scope->level > 0) {
|
2013-07-02 11:07:33 +04:00
|
|
|
$scope->tpl->_compatible = true;
|
|
|
|
}
|
2013-07-03 12:10:50 +04:00
|
|
|
$scope["cname"] = $scope->tpl->parsePlainArg($tokens, $name);
|
2013-07-29 14:58:14 +04:00
|
|
|
$scope["name"] = $name;
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* Close tag {/block}
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagBlockClose($tokens, Scope $scope)
|
|
|
|
{
|
2013-06-08 00:08:00 +04:00
|
|
|
|
2013-07-03 12:10:50 +04:00
|
|
|
$tpl = $scope->tpl;
|
2013-07-29 14:58:14 +04:00
|
|
|
if (isset($tpl->_extends)) { // is child
|
|
|
|
if ($scope["name"]) { // is scalar name
|
|
|
|
if ($tpl->_compatible) { // is compatible mode
|
2013-07-03 12:10:50 +04:00
|
|
|
$scope->replaceContent(
|
2013-07-29 14:58:14 +04:00
|
|
|
'<?php /* 1) Block ' . $tpl . ': ' . $scope["cname"] . ' */' . PHP_EOL . ' if(empty($tpl->b[' . $scope["cname"] . '])) { ' .
|
|
|
|
'$tpl->b[' . $scope["cname"] . '] = function($tpl) { ?>' . PHP_EOL .
|
|
|
|
$scope->getContent() .
|
|
|
|
"<?php };" .
|
|
|
|
"} ?>" . PHP_EOL
|
2013-07-03 12:10:50 +04:00
|
|
|
);
|
2013-07-29 14:58:14 +04:00
|
|
|
} elseif (!isset($tpl->blocks[$scope["name"]])) { // is block not registered
|
|
|
|
$tpl->blocks[$scope["name"]] = $scope->getContent();
|
2013-07-03 12:10:50 +04:00
|
|
|
$scope->replaceContent(
|
2013-07-29 14:58:14 +04:00
|
|
|
'<?php /* 2) Block ' . $tpl . ': ' . $scope["cname"] . ' ' . $tpl->_compatible . ' */' . PHP_EOL . ' $tpl->b[' . $scope["cname"] . '] = function($tpl) { ?>' . PHP_EOL .
|
|
|
|
$scope->getContent() .
|
|
|
|
"<?php }; ?>" . PHP_EOL
|
2013-07-03 12:10:50 +04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
} else { // dynamic name
|
|
|
|
$tpl->_compatible = true; // enable compatible mode
|
|
|
|
$scope->replaceContent(
|
2013-07-29 14:58:14 +04:00
|
|
|
'<?php /* 3) Block ' . $tpl . ': ' . $scope["cname"] . ' */' . PHP_EOL . ' if(empty($tpl->b[' . $scope["cname"] . '])) { ' .
|
|
|
|
'$tpl->b[' . $scope["cname"] . '] = function($tpl) { ?>' . PHP_EOL .
|
|
|
|
$scope->getContent() .
|
|
|
|
"<?php };" .
|
|
|
|
"} ?>" . PHP_EOL
|
2013-07-03 12:10:50 +04:00
|
|
|
);
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
} else { // is parent
|
|
|
|
if (isset($tpl->blocks[$scope["name"]])) { // has block
|
|
|
|
if ($tpl->_compatible) { // compatible mode enabled
|
2013-07-03 12:10:50 +04:00
|
|
|
$scope->replaceContent(
|
2013-07-29 14:58:14 +04:00
|
|
|
'<?php /* 4) Block ' . $tpl . ': ' . $scope["cname"] . ' */' . PHP_EOL . ' if(isset($tpl->b[' . $scope["cname"] . '])) { echo $tpl->b[' . $scope["cname"] . ']->__invoke($tpl); } else {?>' . PHP_EOL .
|
|
|
|
$tpl->blocks[$scope["name"]] .
|
|
|
|
'<?php } ?>' . PHP_EOL
|
2013-07-03 12:10:50 +04:00
|
|
|
);
|
|
|
|
|
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
$scope->replaceContent($tpl->blocks[$scope["name"]]);
|
2013-07-03 12:10:50 +04:00
|
|
|
}
|
2013-05-30 19:00:00 +04:00
|
|
|
// } elseif(isset($tpl->_extended) || !empty($tpl->_compatible)) {
|
2013-07-29 14:58:14 +04:00
|
|
|
} elseif (isset($tpl->_extended) && $tpl->_compatible || empty($tpl->_extended)) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$scope->replaceContent(
|
2013-07-29 14:58:14 +04:00
|
|
|
'<?php /* 5) Block ' . $tpl . ': ' . $scope["cname"] . ' */' . PHP_EOL . ' if(isset($tpl->b[' . $scope["cname"] . '])) { echo $tpl->b[' . $scope["cname"] . ']->__invoke($tpl); } else {?>' . PHP_EOL .
|
|
|
|
$scope->getContent() .
|
|
|
|
'<?php } ?>' . PHP_EOL
|
2013-07-03 12:10:50 +04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return '';
|
2013-06-08 00:08:00 +04:00
|
|
|
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagParent($tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if (empty($scope->tpl->_extends)) {
|
2013-07-05 00:02:24 +04:00
|
|
|
throw new InvalidUsageException("Tag {parent} may be declared in children");
|
2013-02-20 19:51:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-25 18:36:16 +04:00
|
|
|
/**
|
|
|
|
* Standard close tag {/...}
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function stdClose()
|
|
|
|
{
|
2013-02-23 16:35:11 +04:00
|
|
|
return '}';
|
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
|
|
|
|
/**
|
2013-02-07 17:37:16 +04:00
|
|
|
* Standard function parser
|
2013-01-25 18:36:16 +04:00
|
|
|
*
|
|
|
|
* @static
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param mixed $function
|
2013-01-25 18:36:16 +04:00
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Template $tpl
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function stdFuncParser($function, Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
|
|
|
return "$function(" . self::toArray($tpl->parseParams($tokens)) . ', $tpl)';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* Smart function parser
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param $function
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Template $tpl
|
2013-02-07 17:37:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function smartFuncParser($function, Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
|
|
|
if (strpos($function, "::")) {
|
2013-03-14 21:45:00 +04:00
|
|
|
list($class, $method) = explode("::", $function, 2);
|
|
|
|
$ref = new \ReflectionMethod($class, $method);
|
2013-02-07 17:37:16 +04:00
|
|
|
} else {
|
|
|
|
$ref = new \ReflectionFunction($function);
|
|
|
|
}
|
|
|
|
$args = array();
|
|
|
|
$params = $tpl->parseParams($tokens);
|
2013-07-29 14:58:14 +04:00
|
|
|
foreach ($ref->getParameters() as $param) {
|
|
|
|
if (isset($params[$param->getName()])) {
|
|
|
|
$args[] = $params[$param->getName()];
|
|
|
|
} elseif (isset($params[$param->getPosition()])) {
|
|
|
|
$args[] = $params[$param->getPosition()];
|
|
|
|
} elseif ($param->isOptional()) {
|
2013-07-11 14:13:40 +04:00
|
|
|
$args[] = var_export($param->getDefaultValue(), true);
|
2013-02-07 17:37:16 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
return "$function(" . implode(", ", $args) . ')';
|
2013-02-07 17:37:16 +04:00
|
|
|
}
|
|
|
|
|
2013-01-25 18:36:16 +04:00
|
|
|
/**
|
|
|
|
* Standard function open tag parser
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function stdFuncOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-02-23 02:03:05 +04:00
|
|
|
$scope["params"] = self::toArray($scope->tpl->parseParams($tokens));
|
2013-01-25 18:36:16 +04:00
|
|
|
return 'ob_start();';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Standard function close tag parser
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @param Tokenizer $tokens
|
2013-07-29 14:58:14 +04:00
|
|
|
* @param Scope $scope
|
2013-01-25 18:36:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function stdFuncClose($tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
return $scope["function"] . '(' . $scope["params"] . ', ob_get_clean(), $tpl)';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-02-23 02:03:05 +04:00
|
|
|
/**
|
|
|
|
* Convert array of code to string array
|
|
|
|
* @param $params
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function toArray($params)
|
|
|
|
{
|
2013-01-25 18:36:16 +04:00
|
|
|
$_code = array();
|
2013-07-29 14:58:14 +04:00
|
|
|
foreach ($params as $k => $v) {
|
|
|
|
$_code[] = '"' . $k . '" => ' . $v;
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-07-29 14:58:14 +04:00
|
|
|
return 'array(' . implode(",", $_code) . ')';
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2013-07-03 12:10:50 +04:00
|
|
|
/**
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function varOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-07-03 12:10:50 +04:00
|
|
|
$var = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is('=')) { // inline tag {var ...}
|
2013-07-03 12:10:50 +04:00
|
|
|
$scope->is_closed = true;
|
|
|
|
$tokens->next();
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is("[")) {
|
|
|
|
return $var . '=' . $scope->tpl->parseArray($tokens);
|
2013-07-03 12:10:50 +04:00
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
return $var . '=' . $scope->tpl->parseExp($tokens, true);
|
2013-07-03 12:10:50 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$scope["name"] = $var;
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is('|')) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$scope["value"] = $scope->tpl->parseModifier($tokens, "ob_get_clean()");
|
|
|
|
} else {
|
|
|
|
$scope["value"] = "ob_get_clean()";
|
|
|
|
}
|
|
|
|
return 'ob_start();';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function varClose(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
return $scope["name"] . '=' . $scope["value"] . ';';
|
2013-03-17 14:37:23 +04:00
|
|
|
}
|
|
|
|
|
2013-01-25 18:36:16 +04:00
|
|
|
|
2013-02-07 17:37:16 +04:00
|
|
|
/**
|
|
|
|
* @param Tokenizer $tokens
|
2013-05-30 19:00:00 +04:00
|
|
|
* @param Scope $scope
|
2013-02-07 17:37:16 +04:00
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function filterOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-02-23 16:35:11 +04:00
|
|
|
$scope["filter"] = $scope->tpl->parseModifier($tokens, "ob_get_clean()");
|
|
|
|
return "ob_start();";
|
|
|
|
}
|
2013-02-07 17:37:16 +04:00
|
|
|
|
2013-02-23 16:35:11 +04:00
|
|
|
/**
|
2013-05-30 19:00:00 +04:00
|
|
|
* @param $tokens
|
2013-02-23 16:35:11 +04:00
|
|
|
* @param Scope $scope
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function filterClose($tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
return "echo " . $scope["filter"] . ";";
|
2013-02-20 19:51:06 +04:00
|
|
|
}
|
|
|
|
|
2013-02-23 16:35:11 +04:00
|
|
|
/**
|
|
|
|
* Tag {cycle}
|
|
|
|
*
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Template $tpl
|
|
|
|
* @return string
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-02-23 16:35:11 +04:00
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagCycle(Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
|
|
|
if ($tokens->is("[")) {
|
2013-07-03 12:10:50 +04:00
|
|
|
$exp = $tpl->parseArray($tokens);
|
|
|
|
} else {
|
|
|
|
$exp = $tpl->parseExp($tokens, true);
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->valid()) {
|
2013-02-20 19:51:06 +04:00
|
|
|
$p = $tpl->parseParams($tokens);
|
2013-07-29 14:58:14 +04:00
|
|
|
if (empty($p["index"])) {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Cycle may contain only index attribute");
|
2013-02-20 19:51:06 +04:00
|
|
|
} else {
|
2013-07-29 14:58:14 +04:00
|
|
|
return 'echo ' . __CLASS__ . '::cycle(' . $exp . ', ' . $p["index"] . ')';
|
2013-02-20 19:51:06 +04:00
|
|
|
}
|
|
|
|
} else {
|
2013-03-15 00:57:28 +04:00
|
|
|
$var = $tpl->tmpVar();
|
2013-07-29 14:58:14 +04:00
|
|
|
return 'echo ' . __CLASS__ . '::cycle(' . $exp . ", isset($var) ? ++$var : ($var = 0) )";
|
2013-02-20 19:51:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-03 12:10:50 +04:00
|
|
|
/**
|
|
|
|
* Runtime cycle callback
|
|
|
|
* @param mixed $vals
|
|
|
|
* @param $index
|
|
|
|
* @return mixed
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function cycle($vals, $index)
|
|
|
|
{
|
2013-03-15 00:57:28 +04:00
|
|
|
return $vals[$index % count($vals)];
|
|
|
|
}
|
|
|
|
|
2013-02-21 22:51:24 +04:00
|
|
|
/**
|
|
|
|
* Import macros from templates
|
|
|
|
*
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Template $tpl
|
2013-03-15 00:12:02 +04:00
|
|
|
* @throws UnexpectedTokenException
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-03-15 00:12:02 +04:00
|
|
|
* @return string
|
2013-02-21 22:51:24 +04:00
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagImport(Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
2013-03-14 21:45:00 +04:00
|
|
|
$import = array();
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is('[')) {
|
2013-03-14 21:45:00 +04:00
|
|
|
$tokens->next();
|
2013-07-29 14:58:14 +04:00
|
|
|
while ($tokens->valid()) {
|
|
|
|
if ($tokens->is(Tokenizer::MACRO_STRING)) {
|
|
|
|
$import[$tokens->current()] = true;
|
2013-03-14 21:45:00 +04:00
|
|
|
$tokens->next();
|
2013-07-29 14:58:14 +04:00
|
|
|
} elseif ($tokens->is(']')) {
|
2013-03-14 21:45:00 +04:00
|
|
|
$tokens->next();
|
|
|
|
break;
|
2013-07-29 14:58:14 +04:00
|
|
|
} elseif ($tokens->is(',')) {
|
2013-03-15 00:12:02 +04:00
|
|
|
$tokens->next();
|
|
|
|
} else {
|
|
|
|
break;
|
2013-03-14 21:45:00 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->current() != "from") {
|
2013-03-15 00:12:02 +04:00
|
|
|
throw new UnexpectedTokenException($tokens);
|
2013-03-14 21:45:00 +04:00
|
|
|
}
|
|
|
|
$tokens->next();
|
|
|
|
}
|
|
|
|
|
2013-04-28 11:33:36 +04:00
|
|
|
$tpl->parsePlainArg($tokens, $name);
|
2013-07-29 14:58:14 +04:00
|
|
|
if (!$name) {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Invalid usage tag {import}");
|
2013-02-21 22:51:24 +04:00
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is(T_AS)) {
|
2013-02-23 13:29:20 +04:00
|
|
|
$alias = $tokens->next()->get(Tokenizer::MACRO_STRING);
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($alias === "macro") {
|
2013-02-23 16:35:11 +04:00
|
|
|
$alias = "";
|
|
|
|
}
|
2013-02-23 13:29:20 +04:00
|
|
|
$tokens->next();
|
|
|
|
} else {
|
|
|
|
$alias = "";
|
|
|
|
}
|
2013-02-21 22:51:24 +04:00
|
|
|
$donor = $tpl->getStorage()->getRawTemplate()->load($name, true);
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($donor->macros) {
|
|
|
|
foreach ($donor->macros as $name => $macro) {
|
|
|
|
if ($p = strpos($name, ".")) {
|
2013-02-23 13:29:20 +04:00
|
|
|
$name = substr($name, $p);
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($import && !isset($import[$name])) {
|
2013-03-15 00:12:02 +04:00
|
|
|
continue;
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($alias) {
|
|
|
|
$name = $alias . '.' . $name;
|
2013-02-23 13:29:20 +04:00
|
|
|
}
|
|
|
|
$tpl->macros[$name] = $macro;
|
|
|
|
}
|
2013-02-21 22:51:24 +04:00
|
|
|
$tpl->addDepend($donor);
|
|
|
|
}
|
|
|
|
return '';
|
2013-02-23 16:35:11 +04:00
|
|
|
|
2013-02-21 22:51:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-02-23 16:35:11 +04:00
|
|
|
* Define macro
|
2013-02-21 22:51:24 +04:00
|
|
|
*
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
2013-07-02 11:07:33 +04:00
|
|
|
* @throws InvalidUsageException
|
2013-02-21 22:51:24 +04:00
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function macroOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-02-23 02:03:05 +04:00
|
|
|
$scope["name"] = $tokens->get(Tokenizer::MACRO_STRING);
|
2013-07-29 14:53:21 +04:00
|
|
|
$scope["recursive"] = array();
|
|
|
|
$args = array();
|
|
|
|
$defaults = array();
|
2013-07-29 14:58:14 +04:00
|
|
|
if (!$tokens->valid()) {
|
2013-02-23 02:03:05 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
$tokens->next()->need('(')->next();
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is(')')) {
|
2013-02-23 02:03:05 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
while ($tokens->is(Tokenizer::MACRO_STRING, T_VARIABLE)) {
|
2013-07-29 14:53:21 +04:00
|
|
|
$args[] = $param = $tokens->getAndNext();
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is('=')) {
|
2013-02-23 13:29:20 +04:00
|
|
|
$tokens->next();
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is(T_CONSTANT_ENCAPSED_STRING, T_LNUMBER, T_DNUMBER) || $tokens->isSpecialVal()) {
|
|
|
|
$defaults[$param] = $tokens->getAndNext();
|
2013-02-23 02:03:05 +04:00
|
|
|
} else {
|
2013-07-02 11:07:33 +04:00
|
|
|
throw new InvalidUsageException("Macro parameters may have only scalar defaults");
|
2013-02-23 02:03:05 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
$tokens->skipIf(',');
|
2013-02-21 22:51:24 +04:00
|
|
|
}
|
2013-02-23 02:03:05 +04:00
|
|
|
$tokens->skipIf(')');
|
2013-07-29 14:53:21 +04:00
|
|
|
$scope["macro"] = array(
|
|
|
|
"id" => $scope->tpl->i++,
|
|
|
|
"args" => $args,
|
|
|
|
"defaults" => $defaults,
|
|
|
|
"body" => ""
|
|
|
|
);
|
2013-02-23 02:03:05 +04:00
|
|
|
return;
|
2013-02-21 22:51:24 +04:00
|
|
|
}
|
|
|
|
|
2013-02-23 02:03:05 +04:00
|
|
|
/**
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function macroClose(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
|
|
|
if ($scope["recursive"]) {
|
2013-07-29 14:53:21 +04:00
|
|
|
$switch = "switch(\$call['mark']) {\n";
|
2013-07-29 14:58:14 +04:00
|
|
|
foreach ($scope["recursive"] as $mark) {
|
2013-07-29 14:53:21 +04:00
|
|
|
$switch .= "case $mark: goto macro_$mark;\n";
|
|
|
|
}
|
|
|
|
$switch .= "}";
|
2013-07-29 14:58:14 +04:00
|
|
|
$stack = '$stack_' . $scope["macro"]['id'];
|
|
|
|
$scope["macro"]["body"] = '<?php ' . $stack . ' = array(); macro_' . $scope["macro"]['id'] . ': ?>' . $scope->cutContent() . '<?php if(' . $stack . ') {' . PHP_EOL .
|
|
|
|
'$call = array_pop(' . $stack . ');' . PHP_EOL .
|
|
|
|
'$tpl = $call["tpl"];' . PHP_EOL .
|
|
|
|
$switch . PHP_EOL .
|
|
|
|
'unset($call, ' . $stack . ');' . PHP_EOL .
|
|
|
|
'} ?>';
|
2013-07-29 14:53:21 +04:00
|
|
|
} else {
|
|
|
|
$scope["macro"]["body"] = $scope->cutContent();
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
$scope->tpl->macros[$scope["name"]] = $scope["macro"];
|
2013-02-21 22:51:24 +04:00
|
|
|
}
|
|
|
|
|
2013-07-07 01:29:33 +04:00
|
|
|
/**
|
|
|
|
* Output value as is, without escaping
|
|
|
|
*
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Template $tpl
|
|
|
|
* @throws InvalidUsageException
|
|
|
|
* @return string
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagRaw(Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
2013-07-22 18:03:43 +04:00
|
|
|
$escape = (bool)$tpl->escape;
|
2013-07-07 01:29:33 +04:00
|
|
|
$tpl->escape = false;
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tokens->is(':')) {
|
2013-07-07 01:29:33 +04:00
|
|
|
$func = $tokens->getNext(Tokenizer::MACRO_STRING);
|
2013-07-24 19:37:07 +04:00
|
|
|
$tag = $tpl->getStorage()->getTag($func, $tpl);
|
2013-07-29 14:58:14 +04:00
|
|
|
if ($tag["type"] == \Fenom::INLINE_FUNCTION) {
|
2013-07-07 11:29:26 +04:00
|
|
|
$code = $tpl->parseAct($tokens);
|
2013-07-07 01:29:33 +04:00
|
|
|
} elseif ($tag["type"] == \Fenom::BLOCK_FUNCTION) {
|
|
|
|
$code = $tpl->parseAct($tokens);
|
|
|
|
$tpl->getLastScope()->escape = false;
|
2013-07-22 18:03:43 +04:00
|
|
|
return $code;
|
2013-07-07 11:29:26 +04:00
|
|
|
} else {
|
|
|
|
throw new InvalidUsageException("Raw mode allow for expressions or functions");
|
2013-07-07 01:29:33 +04:00
|
|
|
}
|
|
|
|
} else {
|
2013-07-22 18:03:43 +04:00
|
|
|
$code = $tpl->out($tpl->parseExp($tokens, true));
|
2013-07-07 01:29:33 +04:00
|
|
|
}
|
2013-07-07 11:29:26 +04:00
|
|
|
$tpl->escape = $escape;
|
|
|
|
return $code;
|
2013-07-07 01:29:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function autoescapeOpen(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-07-07 01:29:33 +04:00
|
|
|
$boolean = ($tokens->get(T_STRING) == "true" ? true : false);
|
|
|
|
$scope["escape"] = $scope->tpl->escape;
|
|
|
|
$scope->tpl->escape = $boolean;
|
|
|
|
$tokens->next();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Scope $scope
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function autoescapeClose(Tokenizer $tokens, Scope $scope)
|
|
|
|
{
|
2013-07-07 01:29:33 +04:00
|
|
|
$scope->tpl->escape = $scope["escape"];
|
|
|
|
}
|
2013-07-24 16:16:20 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Unset present variables
|
|
|
|
*
|
|
|
|
* @param Tokenizer $tokens
|
|
|
|
* @param Template $tpl
|
|
|
|
* @return string
|
|
|
|
* @throws InvalidUsageException
|
|
|
|
*/
|
2013-07-29 14:58:14 +04:00
|
|
|
public static function tagUnset(Tokenizer $tokens, Template $tpl)
|
|
|
|
{
|
2013-07-24 16:16:20 +04:00
|
|
|
$vars = array();
|
2013-07-29 14:58:14 +04:00
|
|
|
while ($tokens->valid()) {
|
2013-07-24 16:16:20 +04:00
|
|
|
$vars[] = $tpl->parseVar($tokens);
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
if (!$vars) {
|
2013-07-24 16:16:20 +04:00
|
|
|
throw new InvalidUsageException("Unset must accept variable(s)");
|
|
|
|
}
|
2013-07-29 14:58:14 +04:00
|
|
|
return 'unset(' . implode(', ', $vars) . ')';
|
2013-07-24 16:16:20 +04:00
|
|
|
}
|
2013-01-25 18:36:16 +04:00
|
|
|
}
|