PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/mustache/src/Mustache/Context.php

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