PageRenderTime 61ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/twig/twig/lib/Twig/Template.php

https://bitbucket.org/laborautonomo/laborautonomo-site
PHP | 455 lines | 228 code | 56 blank | 171 comment | 43 complexity | 461e0d2b058020ab47835a4b881f2f65 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) 2009 Fabien Potencier
  6. * (c) 2009 Armin Ronacher
  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. * Default base class for compiled templates.
  13. *
  14. * @author Fabien Potencier <fabien@symfony.com>
  15. */
  16. abstract class Twig_Template implements Twig_TemplateInterface
  17. {
  18. protected static $cache = array();
  19. protected $parent;
  20. protected $parents;
  21. protected $env;
  22. protected $blocks;
  23. protected $traits;
  24. /**
  25. * Constructor.
  26. *
  27. * @param Twig_Environment $env A Twig_Environment instance
  28. */
  29. public function __construct(Twig_Environment $env)
  30. {
  31. $this->env = $env;
  32. $this->blocks = array();
  33. $this->traits = array();
  34. }
  35. /**
  36. * Returns the template name.
  37. *
  38. * @return string The template name
  39. */
  40. abstract public function getTemplateName();
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function getEnvironment()
  45. {
  46. return $this->env;
  47. }
  48. /**
  49. * Returns the parent template.
  50. *
  51. * This method is for internal use only and should never be called
  52. * directly.
  53. *
  54. * @return Twig_TemplateInterface|false The parent template or false if there is no parent
  55. */
  56. public function getParent(array $context)
  57. {
  58. if (null !== $this->parent) {
  59. return $this->parent;
  60. }
  61. $parent = $this->doGetParent($context);
  62. if (false === $parent) {
  63. return false;
  64. } elseif ($parent instanceof Twig_Template) {
  65. $name = $parent->getTemplateName();
  66. $this->parents[$name] = $parent;
  67. $parent = $name;
  68. } elseif (!isset($this->parents[$parent])) {
  69. $this->parents[$parent] = $this->env->loadTemplate($parent);
  70. }
  71. return $this->parents[$parent];
  72. }
  73. protected function doGetParent(array $context)
  74. {
  75. return false;
  76. }
  77. public function isTraitable()
  78. {
  79. return true;
  80. }
  81. /**
  82. * Displays a parent block.
  83. *
  84. * This method is for internal use only and should never be called
  85. * directly.
  86. *
  87. * @param string $name The block name to display from the parent
  88. * @param array $context The context
  89. * @param array $blocks The current set of blocks
  90. */
  91. public function displayParentBlock($name, array $context, array $blocks = array())
  92. {
  93. $name = (string) $name;
  94. if (isset($this->traits[$name])) {
  95. $this->traits[$name][0]->displayBlock($name, $context, $blocks);
  96. } elseif (false !== $parent = $this->getParent($context)) {
  97. $parent->displayBlock($name, $context, $blocks);
  98. } else {
  99. throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
  100. }
  101. }
  102. /**
  103. * Displays a block.
  104. *
  105. * This method is for internal use only and should never be called
  106. * directly.
  107. *
  108. * @param string $name The block name to display
  109. * @param array $context The context
  110. * @param array $blocks The current set of blocks
  111. */
  112. public function displayBlock($name, array $context, array $blocks = array())
  113. {
  114. $name = (string) $name;
  115. if (isset($blocks[$name])) {
  116. $b = $blocks;
  117. unset($b[$name]);
  118. call_user_func($blocks[$name], $context, $b);
  119. } elseif (isset($this->blocks[$name])) {
  120. call_user_func($this->blocks[$name], $context, $blocks);
  121. } elseif (false !== $parent = $this->getParent($context)) {
  122. $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks));
  123. }
  124. }
  125. /**
  126. * Renders a parent block.
  127. *
  128. * This method is for internal use only and should never be called
  129. * directly.
  130. *
  131. * @param string $name The block name to render from the parent
  132. * @param array $context The context
  133. * @param array $blocks The current set of blocks
  134. *
  135. * @return string The rendered block
  136. */
  137. public function renderParentBlock($name, array $context, array $blocks = array())
  138. {
  139. ob_start();
  140. $this->displayParentBlock($name, $context, $blocks);
  141. return ob_get_clean();
  142. }
  143. /**
  144. * Renders a block.
  145. *
  146. * This method is for internal use only and should never be called
  147. * directly.
  148. *
  149. * @param string $name The block name to render
  150. * @param array $context The context
  151. * @param array $blocks The current set of blocks
  152. *
  153. * @return string The rendered block
  154. */
  155. public function renderBlock($name, array $context, array $blocks = array())
  156. {
  157. ob_start();
  158. $this->displayBlock($name, $context, $blocks);
  159. return ob_get_clean();
  160. }
  161. /**
  162. * Returns whether a block exists or not.
  163. *
  164. * This method is for internal use only and should never be called
  165. * directly.
  166. *
  167. * This method does only return blocks defined in the current template
  168. * or defined in "used" traits.
  169. *
  170. * It does not return blocks from parent templates as the parent
  171. * template name can be dynamic, which is only known based on the
  172. * current context.
  173. *
  174. * @param string $name The block name
  175. *
  176. * @return Boolean true if the block exists, false otherwise
  177. */
  178. public function hasBlock($name)
  179. {
  180. return isset($this->blocks[(string) $name]);
  181. }
  182. /**
  183. * Returns all block names.
  184. *
  185. * This method is for internal use only and should never be called
  186. * directly.
  187. *
  188. * @return array An array of block names
  189. *
  190. * @see hasBlock
  191. */
  192. public function getBlockNames()
  193. {
  194. return array_keys($this->blocks);
  195. }
  196. /**
  197. * Returns all blocks.
  198. *
  199. * This method is for internal use only and should never be called
  200. * directly.
  201. *
  202. * @return array An array of blocks
  203. *
  204. * @see hasBlock
  205. */
  206. public function getBlocks()
  207. {
  208. return $this->blocks;
  209. }
  210. /**
  211. * {@inheritdoc}
  212. */
  213. public function display(array $context, array $blocks = array())
  214. {
  215. $this->displayWithErrorHandling($this->env->mergeGlobals($context), $blocks);
  216. }
  217. /**
  218. * {@inheritdoc}
  219. */
  220. public function render(array $context)
  221. {
  222. $level = ob_get_level();
  223. ob_start();
  224. try {
  225. $this->display($context);
  226. } catch (Exception $e) {
  227. while (ob_get_level() > $level) {
  228. ob_end_clean();
  229. }
  230. throw $e;
  231. }
  232. return ob_get_clean();
  233. }
  234. protected function displayWithErrorHandling(array $context, array $blocks = array())
  235. {
  236. try {
  237. $this->doDisplay($context, $blocks);
  238. } catch (Twig_Error $e) {
  239. if (!$e->getTemplateFile()) {
  240. $e->setTemplateFile($this->getTemplateName());
  241. }
  242. // this is mostly useful for Twig_Error_Loader exceptions
  243. // see Twig_Error_Loader
  244. if (false === $e->getTemplateLine()) {
  245. $e->setTemplateLine(-1);
  246. $e->guess();
  247. }
  248. throw $e;
  249. } catch (Exception $e) {
  250. throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, null, $e);
  251. }
  252. }
  253. /**
  254. * Auto-generated method to display the template with the given context.
  255. *
  256. * @param array $context An array of parameters to pass to the template
  257. * @param array $blocks An array of blocks to pass to the template
  258. */
  259. abstract protected function doDisplay(array $context, array $blocks = array());
  260. /**
  261. * Returns a variable from the context.
  262. *
  263. * This method is for internal use only and should never be called
  264. * directly.
  265. *
  266. * This method should not be overridden in a sub-class as this is an
  267. * implementation detail that has been introduced to optimize variable
  268. * access for versions of PHP before 5.4. This is not a way to override
  269. * the way to get a variable value.
  270. *
  271. * @param array $context The context
  272. * @param string $item The variable to return from the context
  273. * @param Boolean $ignoreStrictCheck Whether to ignore the strict variable check or not
  274. *
  275. * @return The content of the context variable
  276. *
  277. * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
  278. */
  279. final protected function getContext($context, $item, $ignoreStrictCheck = false)
  280. {
  281. if (!array_key_exists($item, $context)) {
  282. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  283. return null;
  284. }
  285. throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
  286. }
  287. return $context[$item];
  288. }
  289. /**
  290. * Returns the attribute value for a given array/object.
  291. *
  292. * @param mixed $object The object or array from where to get the item
  293. * @param mixed $item The item to get from the array or object
  294. * @param array $arguments An array of arguments to pass if the item is an object method
  295. * @param string $type The type of attribute (@see Twig_TemplateInterface)
  296. * @param Boolean $isDefinedTest Whether this is only a defined check
  297. * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not
  298. *
  299. * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
  300. *
  301. * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
  302. */
  303. protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
  304. {
  305. // array
  306. if (Twig_TemplateInterface::METHOD_CALL !== $type) {
  307. $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
  308. if ((is_array($object) && array_key_exists($arrayItem, $object))
  309. || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
  310. ) {
  311. if ($isDefinedTest) {
  312. return true;
  313. }
  314. return $object[$arrayItem];
  315. }
  316. if (Twig_TemplateInterface::ARRAY_CALL === $type || !is_object($object)) {
  317. if ($isDefinedTest) {
  318. return false;
  319. }
  320. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  321. return null;
  322. }
  323. if (is_object($object)) {
  324. throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
  325. } elseif (is_array($object)) {
  326. throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
  327. } elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
  328. throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
  329. } else {
  330. throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
  331. }
  332. }
  333. }
  334. if (!is_object($object)) {
  335. if ($isDefinedTest) {
  336. return false;
  337. }
  338. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  339. return null;
  340. }
  341. throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
  342. }
  343. $class = get_class($object);
  344. // object property
  345. if (Twig_TemplateInterface::METHOD_CALL !== $type) {
  346. if (isset($object->$item) || array_key_exists((string) $item, $object)) {
  347. if ($isDefinedTest) {
  348. return true;
  349. }
  350. if ($this->env->hasExtension('sandbox')) {
  351. $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
  352. }
  353. return $object->$item;
  354. }
  355. }
  356. // object method
  357. if (!isset(self::$cache[$class]['methods'])) {
  358. self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
  359. }
  360. $lcItem = strtolower($item);
  361. if (isset(self::$cache[$class]['methods'][$lcItem])) {
  362. $method = (string) $item;
  363. } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
  364. $method = 'get'.$item;
  365. } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
  366. $method = 'is'.$item;
  367. } elseif (isset(self::$cache[$class]['methods']['__call'])) {
  368. $method = (string) $item;
  369. } else {
  370. if ($isDefinedTest) {
  371. return false;
  372. }
  373. if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
  374. return null;
  375. }
  376. throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
  377. }
  378. if ($isDefinedTest) {
  379. return true;
  380. }
  381. if ($this->env->hasExtension('sandbox')) {
  382. $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
  383. }
  384. $ret = call_user_func_array(array($object, $method), $arguments);
  385. // useful when calling a template method from a template
  386. // this is not supported but unfortunately heavily used in the Symfony profiler
  387. if ($object instanceof Twig_TemplateInterface) {
  388. return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
  389. }
  390. return $ret;
  391. }
  392. /**
  393. * This method is only useful when testing Twig. Do not use it.
  394. */
  395. public static function clearCache()
  396. {
  397. self::$cache = array();
  398. }
  399. }