1: <?php
2: /**
3: * Smarty Internal Plugin Compile ForeachSection
4: * Shared methods for {foreach} {section} tags
5: *
6: * @package Smarty
7: * @subpackage Compiler
8: * @author Uwe Tews
9: */
10:
11: /**
12: * Smarty Internal Plugin Compile ForeachSection Class
13: *
14: * @package Smarty
15: * @subpackage Compiler
16: */
17: class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_CompileBase
18: {
19: /**
20: * Name of this tag
21: *
22: * @var string
23: */
24: public $tagName = '';
25:
26: /**
27: * Valid properties of $smarty.xxx variable
28: *
29: * @var array
30: */
31: public $nameProperties = array();
32:
33: /**
34: * {section} tag has no item properties
35: *
36: * @var array
37: */
38: public $itemProperties = null;
39:
40: /**
41: * {section} tag has always name attribute
42: *
43: * @var bool
44: */
45: public $isNamed = true;
46:
47: /**
48: * @var array
49: */
50: public $matchResults = array();
51:
52: /**
53: * Preg search pattern
54: *
55: * @var string
56: */
57: private $propertyPreg = '';
58:
59: /**
60: * Offsets in preg match result
61: *
62: * @var array
63: */
64: private $resultOffsets = array();
65:
66: /**
67: * Start offset
68: *
69: * @var int
70: */
71: private $startOffset = 0;
72:
73: /**
74: * Scan sources for used tag attributes
75: *
76: * @param array $attributes
77: * @param \Smarty_Internal_TemplateCompilerBase $compiler
78: *
79: * @throws \SmartyException
80: */
81: public function scanForProperties($attributes, Smarty_Internal_TemplateCompilerBase $compiler)
82: {
83: $this->propertyPreg = '~(';
84: $this->startOffset = 1;
85: $this->resultOffsets = array();
86: $this->matchResults = array('named' => array(), 'item' => array());
87: if (isset($attributes[ 'name' ])) {
88: $this->buildPropertyPreg(true, $attributes);
89: }
90: if (isset($this->itemProperties)) {
91: if ($this->isNamed) {
92: $this->propertyPreg .= '|';
93: }
94: $this->buildPropertyPreg(false, $attributes);
95: }
96: $this->propertyPreg .= ')\W~i';
97: // Template source
98: $this->matchTemplateSource($compiler);
99: // Parent template source
100: $this->matchParentTemplateSource($compiler);
101: // {block} source
102: $this->matchBlockSource($compiler);
103: }
104:
105: /**
106: * Build property preg string
107: *
108: * @param bool $named
109: * @param array $attributes
110: */
111: public function buildPropertyPreg($named, $attributes)
112: {
113: if ($named) {
114: $this->resultOffsets[ 'named' ] = $this->startOffset = $this->startOffset + 3;
115: $this->propertyPreg .= "(([\$]smarty[.]{$this->tagName}[.]" .
116: ($this->tagName === 'section' ? "|[\[]\s*" : '') .
117: "){$attributes['name']}[.](";
118: $properties = $this->nameProperties;
119: } else {
120: $this->resultOffsets[ 'item' ] = $this->startOffset = $this->startOffset + 2;
121: $this->propertyPreg .= "([\$]{$attributes['item']}[@](";
122: $properties = $this->itemProperties;
123: }
124: $propName = reset($properties);
125: while ($propName) {
126: $this->propertyPreg .= "{$propName}";
127: $propName = next($properties);
128: if ($propName) {
129: $this->propertyPreg .= '|';
130: }
131: }
132: $this->propertyPreg .= '))';
133: }
134:
135: /**
136: * Find matches in source string
137: *
138: * @param string $source
139: */
140: public function matchProperty($source)
141: {
142: preg_match_all($this->propertyPreg, $source, $match);
143: foreach ($this->resultOffsets as $key => $offset) {
144: foreach ($match[ $offset ] as $m) {
145: if (!empty($m)) {
146: $this->matchResults[ $key ][ strtolower($m) ] = true;
147: }
148: }
149: }
150: }
151:
152: /**
153: * Find matches in template source
154: *
155: * @param \Smarty_Internal_TemplateCompilerBase $compiler
156: */
157: public function matchTemplateSource(Smarty_Internal_TemplateCompilerBase $compiler)
158: {
159: $this->matchProperty($compiler->parser->lex->data);
160: }
161:
162: /**
163: * Find matches in all parent template source
164: *
165: * @param \Smarty_Internal_TemplateCompilerBase $compiler
166: *
167: * @throws \SmartyException
168: */
169: public function matchParentTemplateSource(Smarty_Internal_TemplateCompilerBase $compiler)
170: {
171: // search parent compiler template source
172: $nextCompiler = $compiler;
173: while ($nextCompiler !== $nextCompiler->parent_compiler) {
174: $nextCompiler = $nextCompiler->parent_compiler;
175: if ($compiler !== $nextCompiler) {
176: // get template source
177: $_content = $nextCompiler->template->source->getContent();
178: if ($_content !== '') {
179: // run pre filter if required
180: if ((isset($nextCompiler->smarty->autoload_filters[ 'pre' ]) ||
181: isset($nextCompiler->smarty->registered_filters[ 'pre' ]))
182: ) {
183: $_content = $nextCompiler->smarty->ext->_filterHandler->runFilter(
184: 'pre',
185: $_content,
186: $nextCompiler->template
187: );
188: }
189: $this->matchProperty($_content);
190: }
191: }
192: }
193: }
194:
195: /**
196: * Find matches in {block} tag source
197: *
198: * @param \Smarty_Internal_TemplateCompilerBase $compiler
199: */
200: public function matchBlockSource(Smarty_Internal_TemplateCompilerBase $compiler)
201: {
202: }
203:
204: /**
205: * Compiles code for the {$smarty.foreach.xxx} or {$smarty.section.xxx}tag
206: *
207: * @param array $args array with attributes from parser
208: * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
209: * @param array $parameter array with compilation parameter
210: *
211: * @return string compiled code
212: * @throws \SmartyCompilerException
213: */
214: public function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
215: {
216: $tag = strtolower(trim($parameter[ 0 ], '"\''));
217: $name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false;
218: if (!$name) {
219: $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true);
220: }
221: $property = isset($parameter[ 2 ]) ? strtolower($compiler->getId($parameter[ 2 ])) : false;
222: if (!$property || !in_array($property, $this->nameProperties)) {
223: $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} property attribute", null, true);
224: }
225: $tagVar = "'__smarty_{$tag}_{$name}'";
226: return "(isset(\$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}']) ? \$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}'] : null)";
227: }
228: }
229: