PageRenderTime 579ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/Nette/Templates/BaseTemplate.php

https://github.com/Vrtak-CZ/ORM-benchmark
PHP | 410 lines | 190 code | 97 blank | 123 comment | 38 complexity | 899e1733d8a50317aa2166735d0536c7 MD5 | raw file
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nette.org/license Nette license
  7. * @link http://nette.org
  8. * @category Nette
  9. * @package Nette\Templates
  10. */
  11. namespace Nette\Templates;
  12. use Nette;
  13. /**
  14. * Template.
  15. *
  16. * @copyright Copyright (c) 2004, 2010 David Grudl
  17. * @package Nette\Templates
  18. */
  19. abstract class BaseTemplate extends Nette\Object implements ITemplate
  20. {
  21. /** @var bool */
  22. public $warnOnUndefined = TRUE;
  23. /** @var array of function(BaseTemplate $sender); Occurs before a template is compiled - implement to customize the filters */
  24. public $onPrepareFilters = array();
  25. /** @var array */
  26. private $params = array();
  27. /** @var array compile-time filters */
  28. private $filters = array();
  29. /** @var array run-time helpers */
  30. private $helpers = array();
  31. /** @var array */
  32. private $helperLoaders = array();
  33. /**
  34. * Registers callback as template compile-time filter.
  35. * @param callback
  36. * @return void
  37. */
  38. public function registerFilter($callback)
  39. {
  40. $callback = callback($callback);
  41. if (in_array($callback, $this->filters)) {
  42. throw new \InvalidStateException("Filter '$callback' was registered twice.");
  43. }
  44. $this->filters[] = $callback;
  45. }
  46. /**
  47. * Returns all registered compile-time filters.
  48. * @return array
  49. */
  50. final public function getFilters()
  51. {
  52. return $this->filters;
  53. }
  54. /********************* rendering ****************d*g**/
  55. /**
  56. * Renders template to output.
  57. * @return void
  58. * @abstract
  59. */
  60. public function render()
  61. {
  62. }
  63. /**
  64. * Renders template to string.
  65. * @param bool can throw exceptions? (hidden parameter)
  66. * @return string
  67. */
  68. public function __toString()
  69. {
  70. ob_start();
  71. try {
  72. $this->render();
  73. return ob_get_clean();
  74. } catch (\Exception $e) {
  75. ob_end_clean();
  76. if (func_num_args() && func_get_arg(0)) {
  77. throw $e;
  78. } else {
  79. Nette\Debug::toStringException($e);
  80. }
  81. }
  82. }
  83. /**
  84. * Applies filters on template content.
  85. * @param string
  86. * @param string
  87. * @return string
  88. */
  89. protected function compile($content, $label = NULL)
  90. {
  91. if (!$this->filters) {
  92. $this->onPrepareFilters($this);
  93. }
  94. try {
  95. foreach ($this->filters as $filter) {
  96. $content = self::extractPhp($content, $blocks);
  97. $content = $filter($content);
  98. $content = strtr($content, $blocks); // put PHP code back
  99. }
  100. } catch (\Exception $e) {
  101. throw new \InvalidStateException("Filter $filter: " . $e->getMessage() . ($label ? " (in $label)" : ''), 0, $e);
  102. }
  103. if ($label) {
  104. $content = "<?php\n// $label\n//\n?>$content";
  105. }
  106. return self::optimizePhp($content);
  107. }
  108. /********************* template helpers ****************d*g**/
  109. /**
  110. * Registers callback as template run-time helper.
  111. * @param string
  112. * @param callback
  113. * @return void
  114. */
  115. public function registerHelper($name, $callback)
  116. {
  117. $this->helpers[strtolower($name)] = callback($callback);
  118. }
  119. /**
  120. * Registers callback as template run-time helpers loader.
  121. * @param callback
  122. * @return void
  123. */
  124. public function registerHelperLoader($callback)
  125. {
  126. $this->helperLoaders[] = callback($callback);
  127. }
  128. /**
  129. * Returns all registered run-time helpers.
  130. * @return array
  131. */
  132. final public function getHelpers()
  133. {
  134. return $this->helpers;
  135. }
  136. /**
  137. * Call a template run-time helper. Do not call directly.
  138. * @param string helper name
  139. * @param array arguments
  140. * @return mixed
  141. */
  142. public function __call($name, $args)
  143. {
  144. $lname = strtolower($name);
  145. if (!isset($this->helpers[$lname])) {
  146. foreach ($this->helperLoaders as $loader) {
  147. $helper = $loader($lname);
  148. if ($helper) {
  149. $this->registerHelper($lname, $helper);
  150. return $this->helpers[$lname]->invokeArgs($args);
  151. }
  152. }
  153. return parent::__call($name, $args);
  154. }
  155. return $this->helpers[$lname]->invokeArgs($args);
  156. }
  157. /**
  158. * Sets translate adapter.
  159. * @param Nette\ITranslator
  160. * @return BaseTemplate provides a fluent interface
  161. */
  162. public function setTranslator(Nette\ITranslator $translator = NULL)
  163. {
  164. $this->registerHelper('translate', $translator === NULL ? NULL : array($translator, 'translate'));
  165. return $this;
  166. }
  167. /********************* template parameters ****************d*g**/
  168. /**
  169. * Adds new template parameter.
  170. * @param string name
  171. * @param mixed value
  172. * @return void
  173. */
  174. public function add($name, $value)
  175. {
  176. if (array_key_exists($name, $this->params)) {
  177. throw new \InvalidStateException("The variable '$name' exists yet.");
  178. }
  179. $this->params[$name] = $value;
  180. }
  181. /**
  182. * Sets all parameters.
  183. * @param array
  184. * @return BaseTemplate provides a fluent interface
  185. */
  186. public function setParams(array $params)
  187. {
  188. $this->params = $params;
  189. return $this;
  190. }
  191. /**
  192. * Returns array of all parameters.
  193. * @return array
  194. */
  195. public function getParams()
  196. {
  197. return $this->params;
  198. }
  199. /**
  200. * Sets a template parameter. Do not call directly.
  201. * @param string name
  202. * @param mixed value
  203. * @return void
  204. */
  205. public function __set($name, $value)
  206. {
  207. $this->params[$name] = $value;
  208. }
  209. /**
  210. * Returns a template parameter. Do not call directly.
  211. * @param string name
  212. * @return mixed value
  213. */
  214. public function &__get($name)
  215. {
  216. if ($this->warnOnUndefined && !array_key_exists($name, $this->params)) {
  217. trigger_error("The variable '$name' does not exist in template.", E_USER_NOTICE);
  218. }
  219. return $this->params[$name];
  220. }
  221. /**
  222. * Determines whether parameter is defined. Do not call directly.
  223. * @param string name
  224. * @return bool
  225. */
  226. public function __isset($name)
  227. {
  228. return isset($this->params[$name]);
  229. }
  230. /**
  231. * Removes a template parameter. Do not call directly.
  232. * @param string name
  233. * @return void
  234. */
  235. public function __unset($name)
  236. {
  237. unset($this->params[$name]);
  238. }
  239. /********************* tools ****************d*g**/
  240. /**
  241. * Extracts all blocks of PHP code.
  242. * @param string
  243. * @param array
  244. * @return string
  245. */
  246. private static function extractPhp($source, & $blocks)
  247. {
  248. $res = '';
  249. $blocks = array();
  250. $tokens = token_get_all($source);
  251. foreach ($tokens as $n => $token) {
  252. if (is_array($token)) {
  253. if ($token[0] === T_INLINE_HTML) {
  254. $res .= $token[1];
  255. continue;
  256. } elseif ($token[0] === T_OPEN_TAG && $token[1] === '<?' && isset($tokens[$n+1][1]) && $tokens[$n+1][1] === 'xml') {
  257. $php = & $res;
  258. $token[1] = '<<?php ?>?';
  259. } elseif ($token[0] === T_OPEN_TAG || $token[0] === T_OPEN_TAG_WITH_ECHO) {
  260. $res .= $id = "\x01@php:p" . count($blocks) . "@\x02";
  261. $php = & $blocks[$id];
  262. }
  263. $php .= $token[1];
  264. } else {
  265. $php .= $token;
  266. }
  267. }
  268. return $res;
  269. }
  270. /**
  271. * Removes unnecessary blocks of PHP code.
  272. * @param string
  273. * @return string
  274. */
  275. public static function optimizePhp($source)
  276. {
  277. $res = $php = '';
  278. $lastChar = ';';
  279. $tokens = new \ArrayIterator(token_get_all($source));
  280. foreach ($tokens as $key => $token) {
  281. if (is_array($token)) {
  282. if ($token[0] === T_INLINE_HTML) {
  283. $lastChar = '';
  284. $res .= $token[1];
  285. } elseif ($token[0] === T_CLOSE_TAG) {
  286. $next = isset($tokens[$key + 1]) ? $tokens[$key + 1] : NULL;
  287. if (substr($res, -1) !== '<' && preg_match('#^<\?php\s*$#', $php)) {
  288. $php = ''; // removes empty (?php ?), but retains ((?php ?)?php
  289. } elseif (is_array($next) && $next[0] === T_OPEN_TAG) { // remove ?)(?php
  290. if ($lastChar !== ';' && $lastChar !== '{' && $lastChar !== '}' && $lastChar !== ':' && $lastChar !== '/' ) $php .= $lastChar = ';';
  291. if (substr($next[1], -1) === "\n") $php .= "\n";
  292. $tokens->next();
  293. } elseif ($next) {
  294. $res .= preg_replace('#;?(\s)*$#', '$1', $php) . $token[1]; // remove last semicolon before ?)
  295. $php = '';
  296. } else { // remove last ?)
  297. if ($lastChar !== '}' && $lastChar !== ';') $php .= ';';
  298. }
  299. } elseif ($token[0] === T_ELSE || $token[0] === T_ELSEIF) {
  300. if ($tokens[$key + 1] === ':' && $lastChar === '}') $php .= ';'; // semicolon needed in if(): ... if() ... else:
  301. $lastChar = '';
  302. $php .= $token[1];
  303. } else {
  304. if (!in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG))) $lastChar = '';
  305. $php .= $token[1];
  306. }
  307. } else {
  308. $php .= $lastChar = $token;
  309. }
  310. }
  311. return $res . $php;
  312. }
  313. }