1<?php
2
3/**
4 * Smarty Extension handler
5 *
6 * Load extensions dynamically
7 *
8 *
9 * @package    Smarty
10 * @subpackage PluginsInternal
11 * @author     Uwe Tews
12 *
13 * Runtime extensions
14 * @property Smarty_Internal_Runtime_CacheModify       $_cacheModify
15 * @property Smarty_Internal_Runtime_CacheResourceFile $_cacheResourceFile
16 * @property Smarty_Internal_Runtime_Capture           $_capture
17 * @property Smarty_Internal_Runtime_CodeFrame         $_codeFrame
18 * @property Smarty_Internal_Runtime_FilterHandler     $_filterHandler
19 * @property Smarty_Internal_Runtime_Foreach           $_foreach
20 * @property Smarty_Internal_Runtime_GetIncludePath    $_getIncludePath
21 * @property Smarty_Internal_Runtime_Make_Nocache      $_make_nocache
22 * @property Smarty_Internal_Runtime_UpdateCache       $_updateCache
23 * @property Smarty_Internal_Runtime_UpdateScope       $_updateScope
24 * @property Smarty_Internal_Runtime_TplFunction       $_tplFunction
25 * @property Smarty_Internal_Runtime_WriteFile         $_writeFile
26 *
27 * Method extensions
28 * @property Smarty_Internal_Method_GetTemplateVars    $getTemplateVars
29 * @property Smarty_Internal_Method_Append             $append
30 * @property Smarty_Internal_Method_AppendByRef        $appendByRef
31 * @property Smarty_Internal_Method_AssignGlobal       $assignGlobal
32 * @property Smarty_Internal_Method_AssignByRef        $assignByRef
33 * @property Smarty_Internal_Method_LoadFilter         $loadFilter
34 * @property Smarty_Internal_Method_LoadPlugin         $loadPlugin
35 * @property Smarty_Internal_Method_RegisterFilter     $registerFilter
36 * @property Smarty_Internal_Method_RegisterObject     $registerObject
37 * @property Smarty_Internal_Method_RegisterPlugin     $registerPlugin
38 */
39class Smarty_Internal_Extension_Handler
40{
41
42    public $objType = null;
43
44    /**
45     * Cache for property information from generic getter/setter
46     * Preloaded with names which should not use with generic getter/setter
47     *
48     * @var array
49     */
50    private $_property_info = array('AutoloadFilters' => 0, 'DefaultModifiers' => 0, 'ConfigVars' => 0,
51                                    'DebugTemplate' => 0, 'RegisteredObject' => 0, 'StreamVariable' => 0,
52                                    'TemplateVars' => 0,);#
53
54    private $resolvedProperties = array();
55
56    /**
57     * Call external Method
58     *
59     * @param \Smarty_Internal_Data $data
60     * @param string                $name external method names
61     * @param array                 $args argument array
62     *
63     * @return mixed
64     * @throws SmartyException
65     */
66    public function _callExternalMethod(Smarty_Internal_Data $data, $name, $args)
67    {
68        /* @var Smarty $data ->smarty */
69        $smarty = isset($data->smarty) ? $data->smarty : $data;
70        if (!isset($smarty->ext->$name)) {
71            $class = 'Smarty_Internal_Method_' . $this->upperCase($name);
72            if (preg_match('/^(set|get)([A-Z].*)$/', $name, $match)) {
73                $pn = '';
74                if (!isset($this->_property_info[ $prop = $match[ 2 ] ])) {
75                    // convert camel case to underscored name
76                    $this->resolvedProperties[ $prop ] = $pn = strtolower(join('_',
77                                                                               preg_split('/([A-Z][^A-Z]*)/', $prop,
78                                                                                          - 1, PREG_SPLIT_NO_EMPTY |
79                                                                                               PREG_SPLIT_DELIM_CAPTURE)));
80                    $this->_property_info[ $prop ] =
81                        property_exists($data, $pn) ? 1 : ($data->_isTplObj() && property_exists($smarty, $pn) ? 2 : 0);
82                }
83                if ($this->_property_info[ $prop ]) {
84                    $pn = $this->resolvedProperties[ $prop ];
85                    if ($match[ 1 ] == 'get') {
86                        return $this->_property_info[ $prop ] == 1 ? $data->$pn : $data->smarty->$pn;
87                    } else {
88                        return $this->_property_info[ $prop ] == 1 ? $data->$pn = $args[ 0 ] :
89                            $data->smarty->$pn = $args[ 0 ];
90                    }
91                } elseif (!class_exists($class)) {
92                    throw new SmartyException("property '$pn' does not exist.");
93                }
94            }
95            if (class_exists($class)) {
96                $callback = array($smarty->ext->$name = new $class(), $name);
97            }
98        } else {
99            $callback = array($smarty->ext->$name, $name);
100        }
101        array_unshift($args, $data);
102        if (isset($callback) && $callback[ 0 ]->objMap | $data->_objType) {
103            return call_user_func_array($callback, $args);
104        }
105        return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args);
106    }
107
108    /**
109     * Make first character of name parts upper case
110     *
111     * @param string $name
112     *
113     * @return string
114     */
115    public function upperCase($name)
116    {
117        $_name = explode('_', $name);
118        $_name = array_map('ucfirst', $_name);
119        return implode('_', $_name);
120    }
121
122    /**
123     * set extension property
124     *
125     * @param string $property_name property name
126     * @param mixed  $value         value
127     *
128     * @throws SmartyException
129     */
130    public function __set($property_name, $value)
131    {
132        $this->$property_name = $value;
133    }
134
135    /**
136     * get extension object
137     *
138     * @param string $property_name property name
139     *
140     * @return mixed|Smarty_Template_Cached
141     * @throws SmartyException
142     */
143    public function __get($property_name)
144    {
145        // object properties of runtime template extensions will start with '_'
146        if ($property_name[ 0 ] == '_') {
147            $class = 'Smarty_Internal_Runtime' . $this->upperCase($property_name);
148        } else {
149            $class = 'Smarty_Internal_Method_' . $this->upperCase($property_name);
150        }
151        if (!class_exists($class)) {
152            return $this->$property_name = new Smarty_Internal_Undefined($class);
153        }
154        return $this->$property_name = new $class();
155    }
156
157    /**
158     * Call error handler for undefined method
159     *
160     * @param string $name unknown method-name
161     * @param array  $args argument array
162     *
163     * @return mixed
164     * @throws SmartyException
165     */
166    public function __call($name, $args)
167    {
168        return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), array($this));
169    }
170
171}