1 <?php
3 /**
4 * Smarty Internal Plugin CompileBase
5 *
6 * @package Smarty
7 * @subpackage Compiler
8 * @author Uwe Tews
9 */
11 /**
12 * This class does extend all internal compile plugins
13 */
14 // abstract class Smarty_Internal_CompileBase implements TagCompilerInterface
15 class Smarty_Internal_CompileBase {
16 public $required_attributes = array();
17 public $optional_attributes = array();
18 public $shorttag_order = array();
19 public $option_flags = array('nocache');
22 /**
23 * This function checks if the attributes passed are valid
24 *
25 * The attributes passed for the tag to compile are checked against the list of required and
26 * optional attributes. Required attributes must be present. Optional attributes are check against
27 * against the corresponding list. The keyword '_any' specifies that any attribute will be accepted
28 * as valid
29 *
30 * @param array $attributes attributes applied to the tag
31 * @return array of mapped attributes for further processing
32 */
33 function _get_attributes ($attributes)
34 {
35 $_indexed_attr = array();
36 // loop over attributes
37 foreach ($attributes as $key => $mixed) {
38 // shorthand ?
39 if (!is_array($mixed)) {
40 // option flag ?
41 if (in_array(trim($mixed, '\'"'), $this->option_flags)) {
42 $_indexed_attr[trim($mixed, '\'"')] = true;
43 // shorthand attribute ?
44 } else if (isset($this->shorttag_order[$key])) {
45 $_indexed_attr[$this->shorttag_order[$key]] = $mixed;
46 } else {
47 // too many shorthands
48 $this->compiler->trigger_template_error('too many shorthand attributes', $this->compiler->lex->taglineno);
49 }
50 // named attribute
51 } else {
52 $kv = each($mixed);
53 // option flag?
54 if (in_array($kv['key'], $this->option_flags)) {
55 if (is_bool($kv['value'])) {
56 $_indexed_attr[$kv['key']] = $kv['value'];
57 } else if (is_string($kv['value']) && in_array(trim($kv['value'], '\'"'), array('true', 'false'))) {
58 if (trim($kv['value']) == 'true') {
59 $_indexed_attr[$kv['key']] = true;
60 } else {
61 $_indexed_attr[$kv['key']] = false;
62 }
63 } else if (is_numeric($kv['value']) && in_array($kv['value'], array(0, 1))) {
64 if ($kv['value'] == 1) {
65 $_indexed_attr[$kv['key']] = true;
66 } else {
67 $_indexed_attr[$kv['key']] = false;
68 }
69 } else {
70 $this->compiler->trigger_template_error("illegal value of option flag \"{$kv['key']}\"", $this->compiler->lex->taglineno);
71 }
72 // must be named attribute
73 } else {
74 reset($mixed);
75 $_indexed_attr[key($mixed)] = $mixed[key($mixed)];
76 }
77 }
78 }
79 // check if all required attributes present
80 foreach ($this->required_attributes as $attr) {
81 if (!array_key_exists($attr, $_indexed_attr)) {
82 $this->compiler->trigger_template_error("missing \"" . $attr . "\" attribute", $this->compiler->lex->taglineno);
83 }
84 }
85 // check for unallowed attributes
86 if ($this->optional_attributes != array('_any')) {
87 $tmp_array = array_merge($this->required_attributes, $this->optional_attributes, $this->option_flags);
88 foreach ($_indexed_attr as $key => $dummy) {
89 if (!in_array($key, $tmp_array) && $key !== 0) {
90 $this->compiler->trigger_template_error("unexpected \"" . $key . "\" attribute", $this->compiler->lex->taglineno);
91 }
92 }
93 }
94 // default 'false' for all option flags not set
95 foreach ($this->option_flags as $flag) {
96 if (!isset($_indexed_attr[$flag])) {
97 $_indexed_attr[$flag] = false;
98 }
99 }
101 return $_indexed_attr;
102 }
104 /**
105 * Push opening tag name on stack
106 *
107 * Optionally additional data can be saved on stack
108 *
109 * @param string $open_tag the opening tag's name
110 * @param anytype $data optional data which shall be saved on stack
111 */
112 function _open_tag($open_tag, $data = null)
113 {
114 array_push($this->compiler->_tag_stack, array($open_tag, $data));
115 }
117 /**
118 * Pop closing tag
119 *
120 * Raise an error if this stack-top doesn't match with expected opening tags
121 *
122 * @param array $ |string $expected_tag the expected opening tag names
123 * @return anytype the opening tag's name or saved data
124 */
125 function _close_tag($expected_tag)
126 {
127 if (count($this->compiler->_tag_stack) > 0) {
128 // get stacked info
129 list($_open_tag, $_data) = array_pop($this->compiler->_tag_stack);
130 // open tag must match with the expected ones
131 if (in_array($_open_tag, (array)$expected_tag)) {
132 if (is_null($_data)) {
133 // return opening tag
134 return $_open_tag;
135 } else {
136 // return restored data
137 return $_data;
138 }
139 }
140 // wrong nesting of tags
141 $this->compiler->trigger_template_error("unclosed {" . $_open_tag . "} tag");
142 return;
143 }
144 // wrong nesting of tags
145 $this->compiler->trigger_template_error("unexpected closing tag", $this->compiler->lex->taglineno);
146 return;
147 }
148 }
150 ?>