PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/h2o/tags.php

https://github.com/uzicoppa/Zend_View_H2o
PHP | 435 lines | 343 code | 65 blank | 27 comment | 33 complexity | e29508582cd451f4df07d7ecea6759a2 MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * @author taylor.luk
  5. * @todo tags need more test coverage
  6. */
  7. /**
  8. * ifchanged tag
  9. *
  10. * Usage:
  11. *
  12. * Variable mode
  13. * {% ifchanged data.date %}...{% endifchanged %}
  14. *
  15. * Lazy mode *not implemented in h2o yet
  16. * {% ifchanged %}...{{ data.date }}...{% endifchanged %}
  17. *
  18. */
  19. class IfChanged_Tag extends H2o_Node {
  20. private $nodelist_true;
  21. private $nodelist_false;
  22. private $_varlist = null;
  23. private $_last_seen = null;
  24. function __construct($argstring, $parser, $position = 0) {
  25. $this->nodelist_true = $parser->parse('endifchanged', 'else');
  26. if ($parser->token->content === 'else')
  27. $this->nodelist_false = $parser->parse('endifchanged');
  28. $this->_varlist = current(H2o_Parser::parseArguments($argstring));
  29. if (!$this->_varlist)
  30. throw new TemplateSyntaxError('H2o doesn\'t support lazy ifchanged yet. Please, supply a variable.');
  31. }
  32. function render($context, $stream) {
  33. if ($this->_varlist) {
  34. $compare_to = $context->resolve($this->_varlist);
  35. } else {
  36. /**
  37. * @todo Rendering method $this->nodelist_true->render() should return a result.
  38. * Further more $compare_to variable should be set to this result.
  39. */
  40. $compare_to = '';
  41. }
  42. if ($compare_to != $this->_last_seen) {
  43. $this->_last_seen = $compare_to;
  44. $this->nodelist_true->render($context, $stream);
  45. } elseif ($this->nodelist_false) {
  46. $this->nodelist_false->render($context, $stream);
  47. }
  48. }
  49. }
  50. class If_Tag extends H2o_Node {
  51. private $body;
  52. private $else;
  53. private $negate;
  54. function __construct($argstring, $parser, $position = 0) {
  55. if (preg_match('/\s(and|or)\s/', $argstring))
  56. throw new TemplateSyntaxError('H2o doesn\'t support multiple expressions');
  57. $this->body = $parser->parse('endif', 'else');
  58. if ($parser->token->content === 'else')
  59. $this->else = $parser->parse('endif');
  60. $this->args = H2o_Parser::parseArguments($argstring);
  61. $first = current($this->args);
  62. if (isset($first['operator']) && $first['operator'] === 'not') {
  63. array_shift($this->args);
  64. $this->negate = true;
  65. }
  66. }
  67. function render($context, $stream) {
  68. if ($this->test($context))
  69. $this->body->render($context, $stream);
  70. elseif ($this->else)
  71. $this->else->render($context, $stream);
  72. }
  73. function test($context) {
  74. $test = Evaluator::exec($this->args, $context);
  75. return $this->negate? !$test : $test;
  76. }
  77. }
  78. class For_Tag extends H2o_Node {
  79. public $position;
  80. private $iteratable, $key, $item, $body, $else, $limit, $reversed;
  81. private $syntax = '{
  82. ([a-zA-Z][a-zA-Z0-9-_]*)(?:,\s?([a-zA-Z][a-zA-Z0-9-_]*))?
  83. \s+in\s+
  84. ([a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*)\s* # Iteratable name
  85. (?:limit\s*:\s*(\d+))?\s*
  86. (reversed)? # Reverse keyword
  87. }x';
  88. function __construct($argstring, $parser, $position) {
  89. if (!preg_match($this->syntax, $argstring, $match))
  90. throw new TemplateSyntaxError("Invalid for loop syntax ");
  91. $this->body = $parser->parse('endfor', 'else');
  92. if ($parser->token->content === 'else')
  93. $this->else = $parser->parse('endfor');
  94. @list(,$this->key, $this->item, $this->iteratable, $this->limit, $this->reversed) = $match;
  95. if ($this->limit)
  96. $this->limit = (int) $this->limit;
  97. # Swap value if no key found
  98. if (!$this->item) {
  99. list($this->key, $this->item) = array($this->item, $this->key);
  100. }
  101. $this->iteratable = symbol($this->iteratable);
  102. $this->reversed = (bool) $this->reversed;
  103. }
  104. function render($context, $stream) {
  105. $iteratable = $context->resolve($this->iteratable);
  106. if ($this->reversed)
  107. $iteratable = array_reverse($iteratable);
  108. if ($this->limit)
  109. $iteratable = array_slice($iteratable, 0, $this->limit);
  110. $length = count($iteratable);
  111. if ($length) {
  112. $parent = $context['loop'];
  113. $context->push();
  114. $rev_count = $is_even = $idx = 0;
  115. foreach($iteratable as $key => $value) {
  116. $is_even = $idx % 2;
  117. $rev_count = $length - $idx;
  118. if ($this->key) {
  119. $context[$this->key] = $key;
  120. }
  121. $context[$this->item] = $value;
  122. $context['loop'] = array(
  123. 'parent' => $parent,
  124. 'first' => $idx === 0,
  125. 'last' => $rev_count === 1,
  126. 'odd' => !$is_even,
  127. 'even' => $is_even,
  128. 'length' => $length,
  129. 'counter' => $idx + 1,
  130. 'counter0' => $idx,
  131. 'revcounter' => $rev_count,
  132. 'revcounter0' => $rev_count - 1
  133. );
  134. $this->body->render($context, $stream);
  135. ++$idx;
  136. }
  137. $context->pop();
  138. } elseif ($this->else)
  139. $this->else->render($context, $stream);
  140. }
  141. }
  142. class Block_Tag extends H2o_Node {
  143. public $name;
  144. public $position;
  145. public $stack;
  146. private $syntax = '/^[a-zA-Z_][a-zA-Z0-9_-]*$/';
  147. function __construct($argstring, $parser, $position) {
  148. if (!preg_match($this->syntax, $argstring))
  149. throw new TemplateSyntaxError('Block tag expects a name, example: block [content]');
  150. $this->name = $argstring;
  151. if (isset($parser->storage['blocks'][$this->name]))
  152. throw new TemplateSyntaxError('Block name exists, Please select a different block name');
  153. $this->filename = $parser->filename;
  154. $this->stack = array($parser->parse('endblock', "endblock {$this->name}"));
  155. $parser->storage['blocks'][$this->name] = $this;
  156. $this->position = $position;
  157. }
  158. function addLayer(&$nodelist) {
  159. $nodelist->parent = $this;
  160. array_push($this->stack, $nodelist);
  161. }
  162. function render($context, $stream, $index = 1) {
  163. $key = count($this->stack) - $index;
  164. if (isset($this->stack[$key])) {
  165. $context->push();
  166. $context['block'] = new BlockContext($this, $context, $index);
  167. $this->stack[$key]->render($context, $stream);
  168. $context->pop();
  169. }
  170. }
  171. }
  172. class Extends_Tag extends H2o_Node {
  173. public $filename;
  174. public $position;
  175. public $nodelist;
  176. private $syntax = '/^["\'](.*?)["\']$/';
  177. function __construct($argstring, $parser, $position = 0) {
  178. if (!$parser->first)
  179. throw new TemplateSyntaxError('extends must be first in file');
  180. if (!preg_match($this->syntax, $argstring))
  181. throw new TemplatesyntaxError('filename must be quoted');
  182. $this->filename = stripcslashes(substr($argstring, 1, -1));
  183. # Parse the current template
  184. $parser->parse();
  185. # Parse parent template
  186. $this->nodelist = $parser->runtime->loadSubTemplate($this->filename, $parser->options);
  187. $parser->storage['templates'] = array_merge(
  188. $parser->storage['templates'], $this->nodelist->parser->storage['templates']
  189. );
  190. $parser->storage['templates'][] = $this->filename;
  191. if (!isset($this->nodelist->parser->storage['blocks']) || !isset($parser->storage['blocks']))
  192. return ;
  193. # Blocks of parent template
  194. $blocks =& $this->nodelist->parser->storage['blocks'];
  195. # Push child blocks on top of parent blocks
  196. foreach($parser->storage['blocks'] as $name => &$block) {
  197. if (isset($blocks[$name])) {
  198. $blocks[$name]->addLayer($block);
  199. }
  200. }
  201. }
  202. function render($context, $stream) {
  203. $this->nodelist->render($context, $stream);
  204. }
  205. }
  206. class Include_Tag extends H2o_Node {
  207. private $nodelist;
  208. private $syntax = '/^["\'](.*?)["\']$/';
  209. function __construct($argstring, $parser, $position = 0) {
  210. if (!preg_match($this->syntax, $argstring))
  211. throw new TemplateSyntaxError();
  212. $this->filename = stripcslashes(substr($argstring, 1, -1));
  213. $this->nodelist = $parser->runtime->loadSubTemplate($this->filename, $parser->options);
  214. $parser->storage['templates'] = array_merge(
  215. $this->nodelist->parser->storage['templates'], $parser->storage['templates']
  216. );
  217. $parser->storage['templates'][] = $this->filename;
  218. }
  219. function render($context, $stream) {
  220. $this->nodelist->render($context, $stream);
  221. }
  222. }
  223. class With_Tag extends H2o_Node {
  224. public $position;
  225. private $variable, $shortcut;
  226. private $nodelist;
  227. private $syntax = '/^([\w]+(:?\.[\w\d]+)*)\s+as\s+([\w]+(:?\.[\w\d]+)?)$/';
  228. function __construct($argstring, $parser, $position = 0) {
  229. if (!preg_match($this->syntax, $argstring, $matches))
  230. throw new TemplateSyntaxError('Invalid with tag syntax');
  231. # extract the long name and shortcut
  232. list(,$this->variable, ,$this->shortcut) = $matches;
  233. $this->nodelist = $parser->parse('endwith');
  234. }
  235. function render($context, $stream) {
  236. $variable = $context->getVariable($this->variable);
  237. $context->push(array($this->shortcut => $variable));
  238. $this->nodelist->render($context, $stream);
  239. $context->pop();
  240. }
  241. }
  242. class Cycle_Tag extends H2o_Node {
  243. private $uid;
  244. private $sequence;
  245. function __construct($argstring, $parser, $pos) {
  246. $args = h2o_parser::parseArguments($argstring);
  247. if (count($args) < 2) {
  248. throw new Exception('Cycle tag require more than two items');
  249. }
  250. $this->sequence = $args;
  251. $this->uid = '__cycle__'.$pos;
  252. }
  253. function render($context, $stream) {
  254. if (!is_null($item = $context->getVariable($this->uid))) {
  255. $item = ($item + 1) % count($this->sequence);
  256. } else {
  257. $item = 0;
  258. }
  259. $stream->write($context->resolve($this->sequence[$item]));
  260. $context->set($this->uid, $item);
  261. }
  262. }
  263. class Load_Tag extends H2o_Node {
  264. public $position;
  265. private $searchpath = array(H2O_ROOT);
  266. private $extension;
  267. function __construct($argstring, $parser, $pos = 0) {
  268. $this->extension = stripcslashes(preg_replace("/^[\"'](.*)[\"']$/", "$1", $argstring));
  269. if ($parser->runtime->searchpath)
  270. $this->appendPath($parser->runtime->searchpath);
  271. $parser->storage['included'][$this->extension] = $file = $this->load();
  272. $this->position = $pos;
  273. }
  274. function render($context, $stream) {
  275. $this->load();
  276. }
  277. function appendPath($path) {
  278. $this->searchpath[] = $path;
  279. }
  280. private function load() {
  281. if (isset(h2o::$extensions[$this->extension])) {
  282. return true;
  283. }
  284. foreach($this->searchpath as $path) {
  285. $file = $path.'ext'.DS.$this->extension.'.php';
  286. if (is_file($file)) {
  287. h2o::load($this->extension, $file);
  288. return $file;
  289. }
  290. }
  291. throw new H2o_Error(
  292. "Extension: {$this->extension} cannot be loaded, please confirm it exist in extension path"
  293. );
  294. }
  295. }
  296. class Debug_Tag extends H2o_Node {
  297. private $argument;
  298. function __construct($argstring, $parser, $pos = 0) {
  299. $this->argument = $argstring;
  300. }
  301. function render($context, $stream) {
  302. if ($this->argument) {
  303. $object = $context->resolve(symbol($this->argument));
  304. } else {
  305. $object = $context->scopes[0];
  306. }
  307. $output = "<pre>". print_r($object, true). "</pre>";
  308. $stream->write($output);
  309. }
  310. }
  311. class Now_Tag extends H2o_Node {
  312. function __construct($argstring, $parser, $pos=0) {
  313. $this->format = $argstring;
  314. if (!$this->format) {
  315. $this->format = "D M j G:i:s T Y";
  316. }
  317. }
  318. function render($contxt, $stream) {
  319. sleep(1);
  320. $time = date($this->format);
  321. $stream->write($time);
  322. }
  323. }
  324. class Autoescape_Tag extends H2o_Node {
  325. protected $enable;
  326. function __construct($argstring, $parser, $pos = 0) {
  327. if ($argstring === 'on')
  328. $this->enable = true;
  329. elseif ($argstring === 'off')
  330. $this->enable = false;
  331. else throw new H2o_Error(
  332. "Invalid syntax : autoescape on|off "
  333. );
  334. }
  335. function render($context, $stream) {
  336. $context->autoescape = $this->enable;
  337. }
  338. }
  339. class Csrf_token_Tag extends H2o_Node {
  340. function render($context, $stream) {
  341. $token = "";
  342. if (isset($_COOKIE["csrftoken"]))
  343. $token = $_COOKIE["csrftoken"];
  344. else {
  345. global $SECRET_KEY;
  346. if (defined('SECRET_KEY'))
  347. $token = md5(mt_rand() . SECRET_KEY);
  348. else
  349. $token = md5(mt_rand());
  350. }
  351. setcookie("csrftoken", $token, time()+60*60*24*365, "/");
  352. $stream->write("<div style='display:none'><input type=\"hidden\" value=\"$token\" name=\"csrfmiddlewaretoken\" /></div>");
  353. }
  354. }
  355. H2o::addTag(array('block', 'extends', 'include', 'if', 'ifchanged', 'for', 'with', 'cycle', 'load', 'debug', 'now', 'autoescape', 'csrf_token'));
  356. ?>