
Comparing changes: https://github.com/smarty-php/smarty/compare/v4.3.1...v4.4.1 It is noticeable that Smarty 4.3.1 does not officially support PHP 8.3. Is only supported with 4.4.0. Remark: During tests with Smarty 4.5.1, it was noticed that the following warning occurs: Deprecated: Using the unregistered function "function_exists" in a template is deprecated and will be removed in a future version. Use Smarty::registerPlugin to explicitly register a custom modifier. As of Smarty 5.X.X, templates must be revised again. The Smarty release 5.0.2 is already officially available. However, integration into FlatPress is not entirely trivial.
344 lines
12 KiB
PHP
344 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Smarty Internal Plugin Compile Foreach
|
|
* Compiles the {foreach} {foreachelse} {/foreach} tags
|
|
*
|
|
* @package Smarty
|
|
* @subpackage Compiler
|
|
* @author Uwe Tews
|
|
*/
|
|
|
|
/**
|
|
* Smarty Internal Plugin Compile Foreach Class
|
|
*
|
|
* @package Smarty
|
|
* @subpackage Compiler
|
|
*/
|
|
class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_ForeachSection
|
|
{
|
|
/**
|
|
* Attribute definition: Overwrites base class.
|
|
*
|
|
* @var array
|
|
* @see Smarty_Internal_CompileBase
|
|
*/
|
|
public $required_attributes = array('from', 'item');
|
|
|
|
/**
|
|
* Attribute definition: Overwrites base class.
|
|
*
|
|
* @var array
|
|
* @see Smarty_Internal_CompileBase
|
|
*/
|
|
public $optional_attributes = array('name', 'key', 'properties');
|
|
|
|
/**
|
|
* Attribute definition: Overwrites base class.
|
|
*
|
|
* @var array
|
|
* @see Smarty_Internal_CompileBase
|
|
*/
|
|
public $shorttag_order = array('from', 'item', 'key', 'name');
|
|
|
|
/**
|
|
* counter
|
|
*
|
|
* @var int
|
|
*/
|
|
public $counter = 0;
|
|
|
|
/**
|
|
* Name of this tag
|
|
*
|
|
* @var string
|
|
*/
|
|
public $tagName = 'foreach';
|
|
|
|
/**
|
|
* Valid properties of $smarty.foreach.name.xxx variable
|
|
*
|
|
* @var array
|
|
*/
|
|
public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total');
|
|
|
|
/**
|
|
* Valid properties of $item@xxx variable
|
|
*
|
|
* @var array
|
|
*/
|
|
public $itemProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'key');
|
|
|
|
/**
|
|
* Flag if tag had name attribute
|
|
*
|
|
* @var bool
|
|
*/
|
|
public $isNamed = false;
|
|
|
|
/**
|
|
* Compiles code for the {foreach} tag
|
|
*
|
|
* @param array $args array with attributes from parser
|
|
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
|
|
*
|
|
* @return string compiled code
|
|
* @throws \SmartyCompilerException
|
|
* @throws \SmartyException
|
|
*/
|
|
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
|
|
{
|
|
$compiler->loopNesting++;
|
|
// init
|
|
$this->isNamed = false;
|
|
// check and get attributes
|
|
$_attr = $this->getAttributes($compiler, $args);
|
|
$from = $_attr[ 'from' ];
|
|
$item = $compiler->getId($_attr[ 'item' ]);
|
|
if ($item === false) {
|
|
$item = $compiler->getVariableName($_attr[ 'item' ]);
|
|
}
|
|
$key = $name = null;
|
|
$attributes = array('item' => $item);
|
|
if (isset($_attr[ 'key' ])) {
|
|
$key = $compiler->getId($_attr[ 'key' ]);
|
|
if ($key === false) {
|
|
$key = $compiler->getVariableName($_attr[ 'key' ]);
|
|
}
|
|
$attributes[ 'key' ] = $key;
|
|
}
|
|
if (isset($_attr[ 'name' ])) {
|
|
$this->isNamed = true;
|
|
$name = $attributes[ 'name' ] = $compiler->getId($_attr[ 'name' ]);
|
|
}
|
|
foreach ($attributes as $a => $v) {
|
|
if ($v === false) {
|
|
$compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true);
|
|
}
|
|
}
|
|
$fromName = $compiler->getVariableName($_attr[ 'from' ]);
|
|
if ($fromName) {
|
|
foreach (array('item', 'key') as $a) {
|
|
if (isset($attributes[ $a ]) && $attributes[ $a ] === $fromName) {
|
|
$compiler->trigger_template_error(
|
|
"'{$a}' and 'from' may not have same variable name '{$fromName}'",
|
|
null,
|
|
true
|
|
);
|
|
}
|
|
}
|
|
}
|
|
$itemVar = "\$_smarty_tpl->tpl_vars['{$item}']";
|
|
$local = '$__foreach_' . $attributes[ 'item' ] . '_' . $this->counter++ . '_';
|
|
// search for used tag attributes
|
|
$itemAttr = array();
|
|
$namedAttr = array();
|
|
$this->scanForProperties($attributes, $compiler);
|
|
if (!empty($this->matchResults[ 'item' ])) {
|
|
$itemAttr = $this->matchResults[ 'item' ];
|
|
}
|
|
if (!empty($this->matchResults[ 'named' ])) {
|
|
$namedAttr = $this->matchResults[ 'named' ];
|
|
}
|
|
if (isset($_attr[ 'properties' ]) && preg_match_all('/[\'](.*?)[\']/', $_attr[ 'properties' ], $match)) {
|
|
foreach ($match[ 1 ] as $prop) {
|
|
if (in_array($prop, $this->itemProperties)) {
|
|
$itemAttr[ $prop ] = true;
|
|
} else {
|
|
$compiler->trigger_template_error("Invalid property '{$prop}'", null, true);
|
|
}
|
|
}
|
|
if ($this->isNamed) {
|
|
foreach ($match[ 1 ] as $prop) {
|
|
if (in_array($prop, $this->nameProperties)) {
|
|
$nameAttr[ $prop ] = true;
|
|
} else {
|
|
$compiler->trigger_template_error("Invalid property '{$prop}'", null, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (isset($itemAttr[ 'first' ])) {
|
|
$itemAttr[ 'index' ] = true;
|
|
}
|
|
if (isset($namedAttr[ 'first' ])) {
|
|
$namedAttr[ 'index' ] = true;
|
|
}
|
|
if (isset($namedAttr[ 'last' ])) {
|
|
$namedAttr[ 'iteration' ] = true;
|
|
$namedAttr[ 'total' ] = true;
|
|
}
|
|
if (isset($itemAttr[ 'last' ])) {
|
|
$itemAttr[ 'iteration' ] = true;
|
|
$itemAttr[ 'total' ] = true;
|
|
}
|
|
if (isset($namedAttr[ 'show' ])) {
|
|
$namedAttr[ 'total' ] = true;
|
|
}
|
|
if (isset($itemAttr[ 'show' ])) {
|
|
$itemAttr[ 'total' ] = true;
|
|
}
|
|
$keyTerm = '';
|
|
if (isset($attributes[ 'key' ])) {
|
|
$keyTerm = "\$_smarty_tpl->tpl_vars['{$key}']->value => ";
|
|
}
|
|
if (isset($itemAttr[ 'key' ])) {
|
|
$keyTerm = "{$itemVar}->key => ";
|
|
}
|
|
if ($this->isNamed) {
|
|
$foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']";
|
|
}
|
|
$needTotal = isset($itemAttr[ 'total' ]);
|
|
// Register tag
|
|
$this->openTag(
|
|
$compiler,
|
|
'foreach',
|
|
array('foreach', $compiler->nocache, $local, $itemVar, empty($itemAttr) ? 1 : 2)
|
|
);
|
|
// maybe nocache because of nocache variables
|
|
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
|
|
// generate output code
|
|
$output = "<?php\n";
|
|
$output .= "\$_from = \$_smarty_tpl->smarty->ext->_foreach->init(\$_smarty_tpl, $from, " .
|
|
var_export($item, true);
|
|
if ($name || $needTotal || $key) {
|
|
$output .= ', ' . var_export($needTotal, true);
|
|
}
|
|
if ($name || $key) {
|
|
$output .= ', ' . var_export($key, true);
|
|
}
|
|
if ($name) {
|
|
$output .= ', ' . var_export($name, true) . ', ' . var_export($namedAttr, true);
|
|
}
|
|
$output .= ");\n";
|
|
if (isset($itemAttr[ 'show' ])) {
|
|
$output .= "{$itemVar}->show = ({$itemVar}->total > 0);\n";
|
|
}
|
|
if (isset($itemAttr[ 'iteration' ])) {
|
|
$output .= "{$itemVar}->iteration = 0;\n";
|
|
}
|
|
if (isset($itemAttr[ 'index' ])) {
|
|
$output .= "{$itemVar}->index = -1;\n";
|
|
}
|
|
$output .= "{$itemVar}->do_else = true;\n";
|
|
$output .= "if (\$_from !== null) foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n";
|
|
$output .= "{$itemVar}->do_else = false;\n";
|
|
if (isset($attributes[ 'key' ]) && isset($itemAttr[ 'key' ])) {
|
|
$output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n";
|
|
}
|
|
if (isset($itemAttr[ 'iteration' ])) {
|
|
$output .= "{$itemVar}->iteration++;\n";
|
|
}
|
|
if (isset($itemAttr[ 'index' ])) {
|
|
$output .= "{$itemVar}->index++;\n";
|
|
}
|
|
if (isset($itemAttr[ 'first' ])) {
|
|
$output .= "{$itemVar}->first = !{$itemVar}->index;\n";
|
|
}
|
|
if (isset($itemAttr[ 'last' ])) {
|
|
$output .= "{$itemVar}->last = {$itemVar}->iteration === {$itemVar}->total;\n";
|
|
}
|
|
if (isset($foreachVar)) {
|
|
if (isset($namedAttr[ 'iteration' ])) {
|
|
$output .= "{$foreachVar}->value['iteration']++;\n";
|
|
}
|
|
if (isset($namedAttr[ 'index' ])) {
|
|
$output .= "{$foreachVar}->value['index']++;\n";
|
|
}
|
|
if (isset($namedAttr[ 'first' ])) {
|
|
$output .= "{$foreachVar}->value['first'] = !{$foreachVar}->value['index'];\n";
|
|
}
|
|
if (isset($namedAttr[ 'last' ])) {
|
|
$output .= "{$foreachVar}->value['last'] = {$foreachVar}->value['iteration'] === {$foreachVar}->value['total'];\n";
|
|
}
|
|
}
|
|
if (!empty($itemAttr)) {
|
|
$output .= "{$local}saved = {$itemVar};\n";
|
|
}
|
|
$output .= '?>';
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Compiles code for to restore saved template variables
|
|
*
|
|
* @param int $levels number of levels to restore
|
|
*
|
|
* @return string compiled code
|
|
*/
|
|
public function compileRestore($levels)
|
|
{
|
|
return "\$_smarty_tpl->smarty->ext->_foreach->restore(\$_smarty_tpl, {$levels});";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Smarty Internal Plugin Compile Foreachelse Class
|
|
*
|
|
* @package Smarty
|
|
* @subpackage Compiler
|
|
*/
|
|
class Smarty_Internal_Compile_Foreachelse extends Smarty_Internal_CompileBase
|
|
{
|
|
/**
|
|
* Compiles code for the {foreachelse} tag
|
|
*
|
|
* @param array $args array with attributes from parser
|
|
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
|
|
*
|
|
* @return string compiled code
|
|
*/
|
|
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
|
|
{
|
|
// check and get attributes
|
|
$_attr = $this->getAttributes($compiler, $args);
|
|
list($openTag, $nocache, $local, $itemVar, $restore) = $this->closeTag($compiler, array('foreach'));
|
|
$this->openTag($compiler, 'foreachelse', array('foreachelse', $nocache, $local, $itemVar, 0));
|
|
$output = "<?php\n";
|
|
if ($restore === 2) {
|
|
$output .= "{$itemVar} = {$local}saved;\n";
|
|
}
|
|
$output .= "}\nif ({$itemVar}->do_else) {\n?>";
|
|
return $output;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Smarty Internal Plugin Compile Foreachclose Class
|
|
*
|
|
* @package Smarty
|
|
* @subpackage Compiler
|
|
*/
|
|
class Smarty_Internal_Compile_Foreachclose extends Smarty_Internal_CompileBase
|
|
{
|
|
/**
|
|
* Compiles code for the {/foreach} tag
|
|
*
|
|
* @param array $args array with attributes from parser
|
|
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
|
|
*
|
|
* @return string compiled code
|
|
* @throws \SmartyCompilerException
|
|
*/
|
|
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
|
|
{
|
|
$compiler->loopNesting--;
|
|
// must endblock be nocache?
|
|
if ($compiler->nocache) {
|
|
$compiler->tag_nocache = true;
|
|
}
|
|
list(
|
|
$openTag, $compiler->nocache, $local, $itemVar, $restore
|
|
) = $this->closeTag($compiler, array('foreach', 'foreachelse'));
|
|
$output = "<?php\n";
|
|
if ($restore === 2) {
|
|
$output .= "{$itemVar} = {$local}saved;\n";
|
|
}
|
|
$output .= "}\n";
|
|
/* @var Smarty_Internal_Compile_Foreach $foreachCompiler */
|
|
$foreachCompiler = $compiler->getTagCompiler('foreach');
|
|
$output .= $foreachCompiler->compileRestore(1);
|
|
$output .= "?>";
|
|
return $output;
|
|
}
|
|
}
|