You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

smarty_internal_compilebase.php 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. /**
  3. * Smarty Internal Plugin CompileBase
  4. *
  5. * @package Smarty
  6. * @subpackage Compiler
  7. * @author Uwe Tews
  8. */
  9. /**
  10. * This class does extend all internal compile plugins
  11. *
  12. * @package Smarty
  13. * @subpackage Compiler
  14. */
  15. abstract class Smarty_Internal_CompileBase
  16. {
  17. /**
  18. * Array of names of required attribute required by tag
  19. *
  20. * @var array
  21. */
  22. public $required_attributes = array();
  23. /**
  24. * Array of names of optional attribute required by tag
  25. * use array('_any') if there is no restriction of attributes names
  26. *
  27. * @var array
  28. */
  29. public $optional_attributes = array();
  30. /**
  31. * Shorttag attribute order defined by its names
  32. *
  33. * @var array
  34. */
  35. public $shorttag_order = array();
  36. /**
  37. * Array of names of valid option flags
  38. *
  39. * @var array
  40. */
  41. public $option_flags = array('nocache');
  42. /**
  43. * Mapping array for boolean option value
  44. *
  45. * @var array
  46. */
  47. public $optionMap = array(1 => true, 0 => false, 'true' => true, 'false' => false);
  48. /**
  49. * Mapping array with attributes as key
  50. *
  51. * @var array
  52. */
  53. public $mapCache = array();
  54. /**
  55. * This function checks if the attributes passed are valid
  56. * The attributes passed for the tag to compile are checked against the list of required and
  57. * optional attributes. Required attributes must be present. Optional attributes are check against
  58. * the corresponding list. The keyword '_any' specifies that any attribute will be accepted
  59. * as valid
  60. *
  61. * @param object $compiler compiler object
  62. * @param array $attributes attributes applied to the tag
  63. *
  64. * @return array of mapped attributes for further processing
  65. */
  66. public function getAttributes($compiler, $attributes)
  67. {
  68. $_indexed_attr = array();
  69. if (!isset($this->mapCache[ 'option' ])) {
  70. $this->mapCache[ 'option' ] = array_fill_keys($this->option_flags, true);
  71. }
  72. foreach ($attributes as $key => $mixed) {
  73. // shorthand ?
  74. if (!is_array($mixed)) {
  75. // option flag ?
  76. if (isset($this->mapCache[ 'option' ][ trim($mixed, '\'"') ])) {
  77. $_indexed_attr[ trim($mixed, '\'"') ] = true;
  78. // shorthand attribute ?
  79. } elseif (isset($this->shorttag_order[ $key ])) {
  80. $_indexed_attr[ $this->shorttag_order[ $key ] ] = $mixed;
  81. } else {
  82. // too many shorthands
  83. $compiler->trigger_template_error('too many shorthand attributes', null, true);
  84. }
  85. // named attribute
  86. } else {
  87. foreach ($mixed as $k => $v) {
  88. // option flag?
  89. if (isset($this->mapCache[ 'option' ][ $k ])) {
  90. if (is_bool($v)) {
  91. $_indexed_attr[ $k ] = $v;
  92. } else {
  93. if (is_string($v)) {
  94. $v = trim($v, '\'" ');
  95. }
  96. if (isset($this->optionMap[ $v ])) {
  97. $_indexed_attr[ $k ] = $this->optionMap[ $v ];
  98. } else {
  99. $compiler->trigger_template_error("illegal value '" . var_export($v, true) .
  100. "' for option flag '{$k}'", null, true);
  101. }
  102. }
  103. // must be named attribute
  104. } else {
  105. $_indexed_attr[ $k ] = $v;
  106. }
  107. }
  108. }
  109. }
  110. // check if all required attributes present
  111. foreach ($this->required_attributes as $attr) {
  112. if (!isset($_indexed_attr[ $attr ])) {
  113. $compiler->trigger_template_error("missing '{$attr}' attribute", null, true);
  114. }
  115. }
  116. // check for not allowed attributes
  117. if ($this->optional_attributes !== array('_any')) {
  118. if (!isset($this->mapCache[ 'all' ])) {
  119. $this->mapCache[ 'all' ] =
  120. array_fill_keys(array_merge($this->required_attributes, $this->optional_attributes,
  121. $this->option_flags), true);
  122. }
  123. foreach ($_indexed_attr as $key => $dummy) {
  124. if (!isset($this->mapCache[ 'all' ][ $key ]) && $key !== 0) {
  125. $compiler->trigger_template_error("unexpected '{$key}' attribute", null, true);
  126. }
  127. }
  128. }
  129. // default 'false' for all option flags not set
  130. foreach ($this->option_flags as $flag) {
  131. if (!isset($_indexed_attr[ $flag ])) {
  132. $_indexed_attr[ $flag ] = false;
  133. }
  134. }
  135. if (isset($_indexed_attr[ 'nocache' ]) && $_indexed_attr[ 'nocache' ]) {
  136. $compiler->tag_nocache = true;
  137. }
  138. return $_indexed_attr;
  139. }
  140. /**
  141. * Push opening tag name on stack
  142. * Optionally additional data can be saved on stack
  143. *
  144. * @param object $compiler compiler object
  145. * @param string $openTag the opening tag's name
  146. * @param mixed $data optional data saved
  147. */
  148. public function openTag($compiler, $openTag, $data = null)
  149. {
  150. array_push($compiler->_tag_stack, array($openTag, $data));
  151. }
  152. /**
  153. * Pop closing tag
  154. * Raise an error if this stack-top doesn't match with expected opening tags
  155. *
  156. * @param object $compiler compiler object
  157. * @param array|string $expectedTag the expected opening tag names
  158. *
  159. * @return mixed any type the opening tag's name or saved data
  160. */
  161. public function closeTag($compiler, $expectedTag)
  162. {
  163. if (count($compiler->_tag_stack) > 0) {
  164. // get stacked info
  165. list($_openTag, $_data) = array_pop($compiler->_tag_stack);
  166. // open tag must match with the expected ones
  167. if (in_array($_openTag, (array) $expectedTag)) {
  168. if (is_null($_data)) {
  169. // return opening tag
  170. return $_openTag;
  171. } else {
  172. // return restored data
  173. return $_data;
  174. }
  175. }
  176. // wrong nesting of tags
  177. $compiler->trigger_template_error("unclosed '{$compiler->smarty->left_delimiter}{$_openTag}{$compiler->smarty->right_delimiter}' tag");
  178. return;
  179. }
  180. // wrong nesting of tags
  181. $compiler->trigger_template_error('unexpected closing tag', null, true);
  182. return;
  183. }
  184. }