Engine.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <?php
  2. namespace Symfony\Components\Templating;
  3. use Symfony\Components\Templating\Loader\LoaderInterface;
  4. use Symfony\Components\Templating\Renderer\PhpRenderer;
  5. use Symfony\Components\Templating\Renderer\RendererInterface;
  6. use Symfony\Components\Templating\Helper\HelperInterface;
  7. /*
  8. * This file is part of the symfony package.
  9. *
  10. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  11. *
  12. * For the full copyright and license information, please view the LICENSE
  13. * file that was distributed with this source code.
  14. */
  15. /**
  16. * Engine is the main class of the templating component.
  17. *
  18. * @package symfony
  19. * @subpackage templating
  20. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  21. */
  22. class Engine
  23. {
  24. protected $loader;
  25. protected $renderers;
  26. protected $current;
  27. protected $helpers;
  28. protected $parents;
  29. protected $stack;
  30. protected $charset;
  31. /**
  32. * Constructor.
  33. *
  34. * @param LoaderInterface $loader A loader instance
  35. * @param array $renderers An array of renderer instances
  36. * @param array $helpers A array of helper instances
  37. */
  38. public function __construct(LoaderInterface $loader, array $renderers = array(), array $helpers = array())
  39. {
  40. $this->loader = $loader;
  41. $this->renderers = $renderers;
  42. $this->helpers = array();
  43. $this->parents = array();
  44. $this->stack = array();
  45. $this->charset = 'UTF-8';
  46. $this->cache = array();
  47. $this->addHelpers($helpers);
  48. if (!isset($this->renderers['php']))
  49. {
  50. $this->renderers['php'] = new PhpRenderer();
  51. }
  52. foreach ($this->renderers as $renderer)
  53. {
  54. $renderer->setEngine($this);
  55. }
  56. }
  57. /**
  58. * Renders a template.
  59. *
  60. * The template name is composed of segments separated by a colon (:).
  61. * By default, this engine knows how to parse templates with one or two segments:
  62. *
  63. * * index: The template logical name is index and the renderer is php
  64. * * index:twig: The template logical name is index and the renderer is twig
  65. *
  66. * @param string $name A template name
  67. * @param array $parameters An array of parameters to pass to the template
  68. *
  69. * @return string The evaluated template as a string
  70. *
  71. * @throws \InvalidArgumentException if the renderer does not exist or if the template does not exist
  72. * @throws \RuntimeException if the template cannot be rendered
  73. */
  74. public function render($name, array $parameters = array())
  75. {
  76. if (isset($this->cache[$name]))
  77. {
  78. list($name, $options, $template) = $this->cache[$name];
  79. }
  80. else
  81. {
  82. list($name, $options) = $this->splitTemplateName($old = $name);
  83. // load
  84. $template = $this->loader->load($name, $options);
  85. if (false === $template)
  86. {
  87. throw new \InvalidArgumentException(sprintf('The template "%s" does not exist (renderer: %s).', $name, $options['renderer']));
  88. }
  89. $this->cache[$old] = array($name, $options, $template);
  90. }
  91. $this->current = $name;
  92. $this->parents[$name] = null;
  93. // renderer
  94. $renderer = $template->getRenderer() ? $template->getRenderer() : $options['renderer'];
  95. if (!isset($this->renderers[$options['renderer']]))
  96. {
  97. throw new \InvalidArgumentException(sprintf('The renderer "%s" is not registered.', $renderer));
  98. }
  99. // render
  100. if (false === $content = $this->renderers[$renderer]->evaluate($template, $parameters))
  101. {
  102. throw new \RuntimeException(sprintf('The template "%s" cannot be rendered (renderer: %s).', $name, $renderer));
  103. }
  104. // decorator
  105. if ($this->parents[$name])
  106. {
  107. $slots = $this->get('slots');
  108. $this->stack[] = $slots->get('_content');
  109. $slots->set('_content', $content);
  110. $content = $this->render($this->parents[$name], $parameters);
  111. $slots->set('_content', array_pop($this->stack));
  112. }
  113. return $content;
  114. }
  115. /**
  116. * Outputs a rendered template.
  117. *
  118. * @param string $name A template name
  119. * @param array $parameters An array of parameters to pass to the template
  120. *
  121. * @see render()
  122. */
  123. public function output($name, array $parameters = array())
  124. {
  125. echo $this->render($name, $parameters);
  126. }
  127. /**
  128. * Gets a helper value.
  129. *
  130. * @param string $name The helper name
  131. *
  132. * @return mixed The helper value
  133. *
  134. * @throws \InvalidArgumentException if the helper is not defined
  135. */
  136. public function __get($name)
  137. {
  138. return $this->$name = $this->get($name);
  139. }
  140. public function addHelpers(array $helpers = array())
  141. {
  142. foreach ($helpers as $alias => $helper)
  143. {
  144. $this->set($helper, is_int($alias) ? null : $alias);
  145. }
  146. }
  147. /**
  148. * Sets a helper.
  149. *
  150. * @param HelperInterface $value The helper instance
  151. * @param string $alias An alias
  152. */
  153. public function set(HelperInterface $helper, $alias = null)
  154. {
  155. $this->helpers[$helper->getName()] = $helper;
  156. if (null !== $alias)
  157. {
  158. $this->helpers[$alias] = $helper;
  159. }
  160. $helper->setCharset($this->charset);
  161. }
  162. /**
  163. * Returns true if the helper if defined.
  164. *
  165. * @param string $name The helper name
  166. *
  167. * @return Boolean true if the helper is defined, false otherwise
  168. */
  169. public function has($name)
  170. {
  171. return isset($this->helpers[$name]);
  172. }
  173. /**
  174. * Gets a helper value.
  175. *
  176. * @param string $name The helper name
  177. *
  178. * @return HelperInterface The helper instance
  179. *
  180. * @throws \InvalidArgumentException if the helper is not defined
  181. */
  182. public function get($name)
  183. {
  184. if (!isset($this->helpers[$name]))
  185. {
  186. throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
  187. }
  188. return $this->helpers[$name];
  189. }
  190. /**
  191. * Decorates the current template with another one.
  192. *
  193. * @param string $template The decorator logical name
  194. */
  195. public function extend($template)
  196. {
  197. $this->parents[$this->current] = $template;
  198. }
  199. /**
  200. * Escapes a string by using the current charset.
  201. *
  202. * @param string $value A string to escape
  203. *
  204. * @return string The escaped string or the original value if not a string
  205. */
  206. public function escape($value)
  207. {
  208. return is_string($value) || (is_object($value) && method_exists($value, '__toString')) ? htmlspecialchars($value, ENT_QUOTES, $this->charset) : $value;
  209. }
  210. /**
  211. * Sets the charset to use.
  212. *
  213. * @param string $charset The charset
  214. */
  215. public function setCharset($charset)
  216. {
  217. $this->charset = $charset;
  218. }
  219. /**
  220. * Gets the current charset.
  221. *
  222. * @return string The current charset
  223. */
  224. public function getCharset()
  225. {
  226. return $this->charset;
  227. }
  228. /**
  229. * Gets the loader associated with this engine.
  230. *
  231. * @return LoaderInterface A LoaderInterface instance
  232. */
  233. public function getLoader()
  234. {
  235. return $this->loader;
  236. }
  237. /**
  238. * Sets a template renderer.
  239. *
  240. * @param string $name The renderer name
  241. * @param RendererInterface $renderer A RendererInterface instance
  242. */
  243. public function setRenderer($name, RendererInterface $renderer)
  244. {
  245. $this->renderers[$name] = $renderer;
  246. $renderer->setEngine($this);
  247. }
  248. protected function splitTemplateName($name)
  249. {
  250. if (false !== $pos = strpos($name, ':'))
  251. {
  252. $renderer = substr($name, $pos + 1);
  253. $name = substr($name, 0, $pos);
  254. }
  255. else
  256. {
  257. $renderer = 'php';
  258. }
  259. return array($name, array('renderer' => $renderer));
  260. }
  261. }