library/smarty/libs/sysplugins/smarty_internal_compilebase.php
changeset 46 f11c31f7fa3e
parent 45 a56e7f9a0463
child 47 03388ec805b4
equal deleted inserted replaced
45:a56e7f9a0463 46:f11c31f7fa3e
     1 <?php
       
     2 /**
       
     3  * Smarty Internal Plugin CompileBase
       
     4  *
       
     5  * @package    Smarty
       
     6  * @subpackage Compiler
       
     7  * @author     Uwe Tews
       
     8  */
       
     9 
       
    10 /**
       
    11  * This class does extend all internal compile plugins
       
    12  *
       
    13  * @package    Smarty
       
    14  * @subpackage Compiler
       
    15  */
       
    16 abstract class Smarty_Internal_CompileBase {
       
    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     /**
       
    44      * This function checks if the attributes passed are valid
       
    45      * The attributes passed for the tag to compile are checked against the list of required and
       
    46      * optional attributes. Required attributes must be present. Optional attributes are check against
       
    47      * the corresponding list. The keyword '_any' specifies that any attribute will be accepted
       
    48      * as valid
       
    49      *
       
    50      * @param  object $compiler compiler object
       
    51      * @param  array $attributes attributes applied to the tag
       
    52      *
       
    53      * @return array  of mapped attributes for further processing
       
    54      */
       
    55     public function getAttributes($compiler, $attributes) {
       
    56         $_indexed_attr = array();
       
    57         // loop over attributes
       
    58         foreach ($attributes as $key => $mixed) {
       
    59             // shorthand ?
       
    60             if (!is_array($mixed)) {
       
    61                 // option flag ?
       
    62                 if (in_array(trim($mixed, '\'"'), $this->option_flags)) {
       
    63                     $_indexed_attr[trim($mixed, '\'"')] = true;
       
    64                     // shorthand attribute ?
       
    65                 } elseif (isset($this->shorttag_order[$key])) {
       
    66                     $_indexed_attr[$this->shorttag_order[$key]] = $mixed;
       
    67                 } else {
       
    68                     // too many shorthands
       
    69                     $compiler->trigger_template_error('too many shorthand attributes', $compiler->lex->taglineno);
       
    70                 }
       
    71                 // named attribute
       
    72             } else {
       
    73                 $kv = each($mixed);
       
    74                 // option flag?
       
    75                 if (in_array($kv['key'], $this->option_flags)) {
       
    76                     if (is_bool($kv['value'])) {
       
    77                         $_indexed_attr[$kv['key']] = $kv['value'];
       
    78                     } elseif (is_string($kv['value']) && in_array(trim($kv['value'], '\'"'), array('true', 'false'))) {
       
    79                         if (trim($kv['value']) == 'true') {
       
    80                             $_indexed_attr[$kv['key']] = true;
       
    81                         } else {
       
    82                             $_indexed_attr[$kv['key']] = false;
       
    83                         }
       
    84                     } elseif (is_numeric($kv['value']) && in_array($kv['value'], array(0, 1))) {
       
    85                         if ($kv['value'] == 1) {
       
    86                             $_indexed_attr[$kv['key']] = true;
       
    87                         } else {
       
    88                             $_indexed_attr[$kv['key']] = false;
       
    89                         }
       
    90                     } else {
       
    91                         $compiler->trigger_template_error("illegal value of option flag \"{$kv['key']}\"", $compiler->lex->taglineno);
       
    92                     }
       
    93                     // must be named attribute
       
    94                 } else {
       
    95                     reset($mixed);
       
    96                     $_indexed_attr[key($mixed)] = $mixed[key($mixed)];
       
    97                 }
       
    98             }
       
    99         }
       
   100         // check if all required attributes present
       
   101         foreach ($this->required_attributes as $attr) {
       
   102             if (!array_key_exists($attr, $_indexed_attr)) {
       
   103                 $compiler->trigger_template_error("missing \"" . $attr . "\" attribute", $compiler->lex->taglineno);
       
   104             }
       
   105         }
       
   106         // check for not allowed attributes
       
   107         if ($this->optional_attributes != array('_any')) {
       
   108             $tmp_array = array_merge($this->required_attributes, $this->optional_attributes, $this->option_flags);
       
   109             foreach ($_indexed_attr as $key => $dummy) {
       
   110                 if (!in_array($key, $tmp_array) && $key !== 0) {
       
   111                     $compiler->trigger_template_error("unexpected \"" . $key . "\" attribute", $compiler->lex->taglineno);
       
   112                 }
       
   113             }
       
   114         }
       
   115         // default 'false' for all option flags not set
       
   116         foreach ($this->option_flags as $flag) {
       
   117             if (!isset($_indexed_attr[$flag])) {
       
   118                 $_indexed_attr[$flag] = false;
       
   119             }
       
   120         }
       
   121 
       
   122         return $_indexed_attr;
       
   123     }
       
   124 
       
   125     /**
       
   126      * Push opening tag name on stack
       
   127      * Optionally additional data can be saved on stack
       
   128      *
       
   129      * @param object $compiler compiler object
       
   130      * @param string $openTag the opening tag's name
       
   131      * @param mixed $data optional data saved
       
   132      */
       
   133     public function openTag($compiler, $openTag, $data = null) {
       
   134         array_push($compiler->_tag_stack, array($openTag, $data));
       
   135     }
       
   136 
       
   137     /**
       
   138      * Pop closing tag
       
   139      * Raise an error if this stack-top doesn't match with expected opening tags
       
   140      *
       
   141      * @param  object $compiler compiler object
       
   142      * @param  array|string $expectedTag the expected opening tag names
       
   143      *
       
   144      * @return mixed        any type the opening tag's name or saved data
       
   145      */
       
   146     public function closeTag($compiler, $expectedTag) {
       
   147         if (count($compiler->_tag_stack) > 0) {
       
   148             // get stacked info
       
   149             list($_openTag, $_data) = array_pop($compiler->_tag_stack);
       
   150             // open tag must match with the expected ones
       
   151             if (in_array($_openTag, (array)$expectedTag)) {
       
   152                 if (is_null($_data)) {
       
   153                     // return opening tag
       
   154                     return $_openTag;
       
   155                 } else {
       
   156                     // return restored data
       
   157                     return $_data;
       
   158                 }
       
   159             }
       
   160             // wrong nesting of tags
       
   161             $compiler->trigger_template_error("unclosed {$compiler->smarty->left_delimiter}" . $_openTag . "{$compiler->smarty->right_delimiter} tag");
       
   162 
       
   163             return;
       
   164         }
       
   165         // wrong nesting of tags
       
   166         $compiler->trigger_template_error("unexpected closing tag", $compiler->lex->taglineno);
       
   167 
       
   168         return;
       
   169     }
       
   170 }