1<?php
2
3/**
4 * Runtime Extension updateScope
5 *
6 * @package    Smarty
7 * @subpackage PluginsInternal
8 * @author     Uwe Tews
9 **/
10class Smarty_Internal_Runtime_UpdateScope
11{
12    /**
13     * Update new assigned template or config variable in other effected scopes
14     *
15     * @param Smarty_Internal_Template $tpl      data object
16     * @param string|null              $varName  variable name
17     * @param int                      $tagScope tag scope to which bubble up variable value
18     */
19    public function _updateScope(Smarty_Internal_Template $tpl, $varName, $tagScope = 0)
20    {
21        if ($tagScope) {
22            $this->_updateVarStack($tpl, $varName);
23            $tagScope = $tagScope & ~Smarty::SCOPE_LOCAL;
24            if (!$tpl->scope && !$tagScope) {
25                return;
26            }
27        }
28        $mergedScope = $tagScope | $tpl->scope;
29        if ($mergedScope) {
30            if ($mergedScope & Smarty::SCOPE_GLOBAL && $varName) {
31                Smarty::$global_tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ];
32            }
33            // update scopes
34            foreach ($this->_getAffectedScopes($tpl, $mergedScope) as $ptr) {
35                $this->_updateVariableInOtherScope($ptr->tpl_vars, $tpl, $varName);
36                if ($tagScope && $ptr->_isTplObj() && isset($tpl->_cache[ 'varStack' ])) {
37                    $this->_updateVarStack($ptr, $varName);
38                }
39            }
40        }
41    }
42
43    /**
44     * Get array of objects which needs to be updated  by given scope value
45     *
46     * @param Smarty_Internal_Template $tpl
47     * @param int                      $mergedScope merged tag and template scope to which bubble up variable value
48     *
49     * @return array
50     */
51    public function _getAffectedScopes(Smarty_Internal_Template $tpl, $mergedScope)
52    {
53        $_stack = array();
54        $ptr = $tpl->parent;
55        if ($mergedScope && isset($ptr) && $ptr->_isTplObj()) {
56            $_stack[] = $ptr;
57            $mergedScope = $mergedScope & ~Smarty::SCOPE_PARENT;
58            if (!$mergedScope) {
59                // only parent was set, we are done
60                return $_stack;
61            }
62            $ptr = $ptr->parent;
63        }
64        while (isset($ptr) && $ptr->_isTplObj()) {
65            $_stack[] = $ptr;
66            $ptr = $ptr->parent;
67        }
68        if ($mergedScope & Smarty::SCOPE_SMARTY) {
69            if (isset($tpl->smarty)) {
70                $_stack[] = $tpl->smarty;
71            }
72        } elseif ($mergedScope & Smarty::SCOPE_ROOT) {
73            while (isset($ptr)) {
74                if (!$ptr->_isTplObj()) {
75                    $_stack[] = $ptr;
76                    break;
77                }
78                $ptr = $ptr->parent;
79            }
80        }
81        return $_stack;
82    }
83
84    /**
85     * Update variable in other scope
86     *
87     * @param array                     $tpl_vars template variable array
88     * @param \Smarty_Internal_Template $from
89     * @param string                    $varName  variable name
90     */
91    public function _updateVariableInOtherScope(&$tpl_vars, Smarty_Internal_Template $from, $varName)
92    {
93        if (!isset($tpl_vars[ $varName ])) {
94            $tpl_vars[ $varName ] = clone $from->tpl_vars[ $varName ];
95        } else {
96            $tpl_vars[ $varName ] = clone $tpl_vars[ $varName ];
97            $tpl_vars[ $varName ]->value = $from->tpl_vars[ $varName ]->value;
98        }
99    }
100
101    /**
102     * Update variable in template local variable stack
103     *
104     * @param \Smarty_Internal_Template $tpl
105     * @param string|null               $varName variable name or null for config variables
106     */
107    public function _updateVarStack(Smarty_Internal_Template $tpl, $varName)
108    {
109        $i = 0;
110        while (isset($tpl->_cache[ 'varStack' ][ $i ])) {
111            $this->_updateVariableInOtherScope($tpl->_cache[ 'varStack' ][ $i ][ 'tpl' ], $tpl, $varName);
112            $i++;
113        }
114    }
115}
116