Template.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <?php
  2. /*
  3. * This file is part of Mustache.php.
  4. *
  5. * (c) 2012 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. * Abstract Mustache Template class.
  12. *
  13. * @abstract
  14. */
  15. abstract class Mustache_Template
  16. {
  17. /**
  18. * @var Mustache_Engine
  19. */
  20. protected $mustache;
  21. /**
  22. * @var boolean
  23. */
  24. protected $strictCallables = false;
  25. /**
  26. * Mustache Template constructor.
  27. *
  28. * @param Mustache_Engine $mustache
  29. */
  30. public function __construct(Mustache_Engine $mustache)
  31. {
  32. $this->mustache = $mustache;
  33. }
  34. /**
  35. * Mustache Template instances can be treated as a function and rendered by simply calling them:
  36. *
  37. * $m = new Mustache_Engine;
  38. * $tpl = $m->loadTemplate('Hello, {{ name }}!');
  39. * echo $tpl(array('name' => 'World')); // "Hello, World!"
  40. *
  41. * @see Mustache_Template::render
  42. *
  43. * @param mixed $context Array or object rendering context (default: array())
  44. *
  45. * @return string Rendered template
  46. */
  47. public function __invoke($context = array())
  48. {
  49. return $this->render($context);
  50. }
  51. /**
  52. * Render this template given the rendering context.
  53. *
  54. * @param mixed $context Array or object rendering context (default: array())
  55. *
  56. * @return string Rendered template
  57. */
  58. public function render($context = array())
  59. {
  60. return $this->renderInternal($this->prepareContextStack($context));
  61. }
  62. /**
  63. * Internal rendering method implemented by Mustache Template concrete subclasses.
  64. *
  65. * This is where the magic happens :)
  66. *
  67. * NOTE: This method is not part of the Mustache.php public API.
  68. *
  69. * @param Mustache_Context $context
  70. * @param string $indent (default: '')
  71. *
  72. * @return string Rendered template
  73. */
  74. abstract public function renderInternal(Mustache_Context $context, $indent = '');
  75. /**
  76. * Tests whether a value should be iterated over (e.g. in a section context).
  77. *
  78. * In most languages there are two distinct array types: list and hash (or whatever you want to call them). Lists
  79. * should be iterated, hashes should be treated as objects. Mustache follows this paradigm for Ruby, Javascript,
  80. * Java, Python, etc.
  81. *
  82. * PHP, however, treats lists and hashes as one primitive type: array. So Mustache.php needs a way to distinguish
  83. * between between a list of things (numeric, normalized array) and a set of variables to be used as section context
  84. * (associative array). In other words, this will be iterated over:
  85. *
  86. * $items = array(
  87. * array('name' => 'foo'),
  88. * array('name' => 'bar'),
  89. * array('name' => 'baz'),
  90. * );
  91. *
  92. * ... but this will be used as a section context block:
  93. *
  94. * $items = array(
  95. * 1 => array('name' => 'foo'),
  96. * 'banana' => array('name' => 'bar'),
  97. * 42 => array('name' => 'baz'),
  98. * );
  99. *
  100. * @param mixed $value
  101. *
  102. * @return boolean True if the value is 'iterable'
  103. */
  104. protected function isIterable($value)
  105. {
  106. if (is_object($value)) {
  107. return $value instanceof Traversable;
  108. } elseif (is_array($value)) {
  109. $i = 0;
  110. foreach ($value as $k => $v) {
  111. if ($k !== $i++) {
  112. return false;
  113. }
  114. }
  115. return true;
  116. } else {
  117. return false;
  118. }
  119. }
  120. /**
  121. * Helper method to prepare the Context stack.
  122. *
  123. * Adds the Mustache HelperCollection to the stack's top context frame if helpers are present.
  124. *
  125. * @param mixed $context Optional first context frame (default: null)
  126. *
  127. * @return Mustache_Context
  128. */
  129. protected function prepareContextStack($context = null)
  130. {
  131. $stack = new Mustache_Context;
  132. $helpers = $this->mustache->getHelpers();
  133. if (!$helpers->isEmpty()) {
  134. $stack->push($helpers);
  135. }
  136. if (!empty($context)) {
  137. $stack->push($context);
  138. }
  139. return $stack;
  140. }
  141. /**
  142. * Resolve a context value.
  143. *
  144. * Invoke the value if it is callable, otherwise return the value.
  145. *
  146. * @param mixed $value
  147. * @param Mustache_Context $context
  148. * @param string $indent
  149. *
  150. * @return string
  151. */
  152. protected function resolveValue($value, Mustache_Context $context, $indent = '')
  153. {
  154. if (($this->strictCallables ? is_object($value) : !is_string($value)) && is_callable($value)) {
  155. return $this->mustache
  156. ->loadLambda((string) call_user_func($value))
  157. ->renderInternal($context, $indent);
  158. }
  159. return $value;
  160. }
  161. }