1 <?php 2 3 /* 4 * This file is part of Mustache.php. 5 * 6 * (c) 2010-2017 Justin Hileman 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 /** 13 * Mustache Template rendering Context. 14 */ 15 class Mustache_Context 16 { 17 private $stack = array(); 18 private $blockStack = array(); 19 20 /** 21 * Mustache rendering Context constructor. 22 * 23 * @param mixed $context Default rendering context (default: null) 24 */ 25 public function __construct($context = null) 26 { 27 if ($context !== null) { 28 $this->stack = array($context); 29 } 30 } 31 32 /** 33 * Push a new Context frame onto the stack. 34 * 35 * @param mixed $value Object or array to use for context 36 */ 37 public function push($value) 38 { 39 array_push($this->stack, $value); 40 } 41 42 /** 43 * Push a new Context frame onto the block context stack. 44 * 45 * @param mixed $value Object or array to use for block context 46 */ 47 public function pushBlockContext($value) 48 { 49 array_push($this->blockStack, $value); 50 } 51 52 /** 53 * Pop the last Context frame from the stack. 54 * 55 * @return mixed Last Context frame (object or array) 56 */ 57 public function pop() 58 { 59 return array_pop($this->stack); 60 } 61 62 /** 63 * Pop the last block Context frame from the stack. 64 * 65 * @return mixed Last block Context frame (object or array) 66 */ 67 public function popBlockContext() 68 { 69 return array_pop($this->blockStack); 70 } 71 72 /** 73 * Get the last Context frame. 74 * 75 * @return mixed Last Context frame (object or array) 76 */ 77 public function last() 78 { 79 return end($this->stack); 80 } 81 82 /** 83 * Find a variable in the Context stack. 84 * 85 * Starting with the last Context frame (the context of the innermost section), and working back to the top-level 86 * rendering context, look for a variable with the given name: 87 * 88 * * If the Context frame is an associative array which contains the key $id, returns the value of that element. 89 * * If the Context frame is an object, this will check first for a public method, then a public property named 90 * $id. Failing both of these, it will try `__isset` and `__get` magic methods. 91 * * If a value named $id is not found in any Context frame, returns an empty string. 92 * 93 * @param string $id Variable name 94 * 95 * @return mixed Variable value, or '' if not found 96 */ 97 public function find($id) 98 { 99 return $this->findVariableInStack($id, $this->stack); 100 } 101 102 /** 103 * Find a 'dot notation' variable in the Context stack. 104 * 105 * Note that dot notation traversal bubbles through scope differently than the regular find method. After finding 106 * the initial chunk of the dotted name, each subsequent chunk is searched for only within the value of the previous 107 * result. For example, given the following context stack: 108 * 109 * $data = array( 110 * 'name' => 'Fred', 111 * 'child' => array( 112 * 'name' => 'Bob' 113 * ), 114 * ); 115 * 116 * ... and the Mustache following template: 117 * 118 * {{ child.name }} 119 * 120 * ... the `name` value is only searched for within the `child` value of the global Context, not within parent 121 * Context frames. 122 * 123 * @param string $id Dotted variable selector 124 * 125 * @return mixed Variable value, or '' if not found 126 */ 127 public function findDot($id) 128 { 129 $chunks = explode('.', $id); 130 $first = array_shift($chunks); 131 $value = $this->findVariableInStack($first, $this->stack); 132 133 foreach ($chunks as $chunk) { 134 if ($value === '') { 135 return $value; 136 } 137 138 $value = $this->findVariableInStack($chunk, array($value)); 139 } 140 141 return $value; 142 } 143 144 /** 145 * Find an 'anchored dot notation' variable in the Context stack. 146 * 147 * This is the same as findDot(), except it looks in the top of the context 148 * stack for the first value, rather than searching the whole context stack 149 * and starting from there. 150 * 151 * @see Mustache_Context::findDot 152 * 153 * @throws Mustache_Exception_InvalidArgumentException if given an invalid anchored dot $id 154 * 155 * @param string $id Dotted variable selector 156 * 157 * @return mixed Variable value, or '' if not found 158 */ 159 public function findAnchoredDot($id) 160 { 161 $chunks = explode('.', $id); 162 $first = array_shift($chunks); 163 if ($first !== '') { 164 throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected id for findAnchoredDot: %s', $id)); 165 } 166 167 $value = $this->last(); 168 169 foreach ($chunks as $chunk) { 170 if ($value === '') { 171 return $value; 172 } 173 174 $value = $this->findVariableInStack($chunk, array($value)); 175 } 176 177 return $value; 178 } 179 180 /** 181 * Find an argument in the block context stack. 182 * 183 * @param string $id 184 * 185 * @return mixed Variable value, or '' if not found 186 */ 187 public function findInBlock($id) 188 { 189 foreach ($this->blockStack as $context) { 190 if (array_key_exists($id, $context)) { 191 return $context[$id]; 192 } 193 } 194 195 return ''; 196 } 197 198 /** 199 * Helper function to find a variable in the Context stack. 200 * 201 * @see Mustache_Context::find 202 * 203 * @param string $id Variable name 204 * @param array $stack Context stack 205 * 206 * @return mixed Variable value, or '' if not found 207 */ 208 private function findVariableInStack($id, array $stack) 209 { 210 for ($i = count($stack) - 1; $i >= 0; $i--) { 211 $frame = &$stack[$i]; 212 213 switch (gettype($frame)) { 214 case 'object': 215 if (!($frame instanceof Closure)) { 216 // Note that is_callable() *will not work here* 217 // See https://github.com/bobthecow/mustache.php/wiki/Magic-Methods 218 if (method_exists($frame, $id)) { 219 return $frame->$id(); 220 } 221 222 if (isset($frame->$id)) { 223 return $frame->$id; 224 } 225 226 if ($frame instanceof ArrayAccess && isset($frame[$id])) { 227 return $frame[$id]; 228 } 229 } 230 break; 231 232 case 'array': 233 if (array_key_exists($id, $frame)) { 234 return $frame[$id]; 235 } 236 break; 237 } 238 } 239 240 return ''; 241 } 242 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body