PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

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