PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/kohana-twig/vendor/Twig-1.0/lib/Twig/Extension/Core.php

https://bitbucket.org/sapphiriq/assets-example
PHP | 499 lines | 361 code | 76 blank | 62 comment | 47 complexity | e0e13684f191510f662956423d896ccf MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) 2009 Fabien Potencier
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. class Twig_Extension_Core extends Twig_Extension
  11. {
  12. /**
  13. * Returns the token parser instance to add to the existing list.
  14. *
  15. * @return array An array of Twig_TokenParser instances
  16. */
  17. public function getTokenParsers()
  18. {
  19. return array(
  20. new Twig_TokenParser_For(),
  21. new Twig_TokenParser_If(),
  22. new Twig_TokenParser_Extends(),
  23. new Twig_TokenParser_Include(),
  24. new Twig_TokenParser_Block(),
  25. new Twig_TokenParser_Filter(),
  26. new Twig_TokenParser_Macro(),
  27. new Twig_TokenParser_Import(),
  28. new Twig_TokenParser_From(),
  29. new Twig_TokenParser_Set(),
  30. new Twig_TokenParser_Spaceless(),
  31. );
  32. }
  33. /**
  34. * Returns a list of filters to add to the existing list.
  35. *
  36. * @return array An array of filters
  37. */
  38. public function getFilters()
  39. {
  40. $filters = array(
  41. // formatting filters
  42. 'date' => new Twig_Filter_Function('twig_date_format_filter'),
  43. 'format' => new Twig_Filter_Function('sprintf'),
  44. 'replace' => new Twig_Filter_Function('twig_strtr'),
  45. // encoding
  46. 'url_encode' => new Twig_Filter_Function('twig_urlencode_filter'),
  47. 'json_encode' => new Twig_Filter_Function('json_encode'),
  48. // string filters
  49. 'title' => new Twig_Filter_Function('twig_title_string_filter', array('needs_environment' => true)),
  50. 'capitalize' => new Twig_Filter_Function('twig_capitalize_string_filter', array('needs_environment' => true)),
  51. 'upper' => new Twig_Filter_Function('strtoupper'),
  52. 'lower' => new Twig_Filter_Function('strtolower'),
  53. 'striptags' => new Twig_Filter_Function('strip_tags'),
  54. // array helpers
  55. 'join' => new Twig_Filter_Function('twig_join_filter'),
  56. 'reverse' => new Twig_Filter_Function('twig_reverse_filter'),
  57. 'length' => new Twig_Filter_Function('twig_length_filter', array('needs_environment' => true)),
  58. 'sort' => new Twig_Filter_Function('twig_sort_filter'),
  59. 'merge' => new Twig_Filter_Function('twig_array_merge'),
  60. // iteration and runtime
  61. 'default' => new Twig_Filter_Function('twig_default_filter'),
  62. 'keys' => new Twig_Filter_Function('twig_get_array_keys_filter'),
  63. // escaping
  64. 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
  65. 'e' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
  66. );
  67. if (function_exists('mb_get_info')) {
  68. $filters['upper'] = new Twig_Filter_Function('twig_upper_filter', array('needs_environment' => true));
  69. $filters['lower'] = new Twig_Filter_Function('twig_lower_filter', array('needs_environment' => true));
  70. }
  71. return $filters;
  72. }
  73. /**
  74. * Returns a list of global functions to add to the existing list.
  75. *
  76. * @return array An array of global functions
  77. */
  78. public function getFunctions()
  79. {
  80. return array(
  81. 'range' => new Twig_Function_Method($this, 'getRange'),
  82. 'constant' => new Twig_Function_Method($this, 'getConstant'),
  83. 'cycle' => new Twig_Function_Method($this, 'getCycle'),
  84. );
  85. }
  86. public function getRange($start, $end, $step = 1)
  87. {
  88. return range($start, $end, $step);
  89. }
  90. public function getConstant($value)
  91. {
  92. return constant($value);
  93. }
  94. public function getCycle($values, $i)
  95. {
  96. if (!is_array($values) && !$values instanceof ArrayAccess) {
  97. return $values;
  98. }
  99. return $values[$i % count($values)];
  100. }
  101. /**
  102. * Returns a list of filters to add to the existing list.
  103. *
  104. * @return array An array of filters
  105. */
  106. public function getTests()
  107. {
  108. return array(
  109. 'even' => new Twig_Test_Function('twig_test_even'),
  110. 'odd' => new Twig_Test_Function('twig_test_odd'),
  111. 'defined' => new Twig_Test_Function('twig_test_defined'),
  112. 'sameas' => new Twig_Test_Function('twig_test_sameas'),
  113. 'none' => new Twig_Test_Function('twig_test_none'),
  114. 'divisibleby' => new Twig_Test_Function('twig_test_divisibleby'),
  115. 'constant' => new Twig_Test_Function('twig_test_constant'),
  116. 'empty' => new Twig_Test_Function('twig_test_empty'),
  117. );
  118. }
  119. /**
  120. * Returns a list of operators to add to the existing list.
  121. *
  122. * @return array An array of operators
  123. */
  124. public function getOperators()
  125. {
  126. return array(
  127. array(
  128. 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
  129. '-' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Neg'),
  130. '+' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Pos'),
  131. ),
  132. array(
  133. 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  134. 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  135. '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  136. '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  137. '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  138. '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  139. '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  140. '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  141. 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  142. 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  143. '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  144. '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  145. '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  146. '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  147. '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  148. '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  149. '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  150. 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  151. 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  152. '..' => array('precedence' => 110, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  153. '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
  154. ),
  155. );
  156. }
  157. public function parseNotTestExpression(Twig_Parser $parser, $node)
  158. {
  159. return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
  160. }
  161. public function parseTestExpression(Twig_Parser $parser, $node)
  162. {
  163. $stream = $parser->getStream();
  164. $name = $stream->expect(Twig_Token::NAME_TYPE);
  165. $arguments = null;
  166. if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
  167. $arguments = $parser->getExpressionParser()->parseArguments();
  168. }
  169. return new Twig_Node_Expression_Test($node, $name->getValue(), $arguments, $parser->getCurrentToken()->getLine());
  170. }
  171. /**
  172. * Returns the name of the extension.
  173. *
  174. * @return string The extension name
  175. */
  176. public function getName()
  177. {
  178. return 'core';
  179. }
  180. }
  181. function twig_date_format_filter($date, $format = 'F j, Y H:i')
  182. {
  183. if (!$date instanceof DateTime) {
  184. $date = new DateTime((ctype_digit($date) ? '@' : '').$date);
  185. }
  186. return $date->format($format);
  187. }
  188. function twig_urlencode_filter($url, $raw = false)
  189. {
  190. if ($raw) {
  191. return rawurlencode($url);
  192. }
  193. return urlencode($url);
  194. }
  195. function twig_array_merge($arr1, $arr2)
  196. {
  197. if (!is_array($arr1) || !is_array($arr2)) {
  198. throw new Twig_Error_Runtime('The merge filter only work with arrays or hashes.');
  199. }
  200. return array_merge($arr1, $arr2);
  201. }
  202. function twig_join_filter($value, $glue = '')
  203. {
  204. return implode($glue, (array) $value);
  205. }
  206. function twig_default_filter($value, $default = '')
  207. {
  208. return twig_test_empty($value) ? $default : $value;
  209. }
  210. function twig_get_array_keys_filter($array)
  211. {
  212. if (is_object($array) && $array instanceof Traversable) {
  213. return array_keys(iterator_to_array($array));
  214. }
  215. if (!is_array($array)) {
  216. return array();
  217. }
  218. return array_keys($array);
  219. }
  220. function twig_reverse_filter($array)
  221. {
  222. if (is_object($array) && $array instanceof Traversable) {
  223. return array_reverse(iterator_to_array($array));
  224. }
  225. if (!is_array($array)) {
  226. return array();
  227. }
  228. return array_reverse($array);
  229. }
  230. function twig_sort_filter($array)
  231. {
  232. asort($array);
  233. return $array;
  234. }
  235. function twig_in_filter($value, $compare)
  236. {
  237. if (is_array($compare)) {
  238. return in_array($value, $compare);
  239. } elseif (is_string($compare)) {
  240. return false !== strpos($compare, (string) $value);
  241. } elseif (is_object($compare) && $compare instanceof Traversable) {
  242. return in_array($value, iterator_to_array($compare, false));
  243. }
  244. return false;
  245. }
  246. function twig_strtr($pattern, $replacements)
  247. {
  248. return str_replace(array_keys($replacements), array_values($replacements), $pattern);
  249. }
  250. /*
  251. * Each type specifies a way for applying a transformation to a string
  252. * The purpose is for the string to be "escaped" so it is suitable for
  253. * the format it is being displayed in.
  254. *
  255. * For example, the string: "It's required that you enter a username & password.\n"
  256. * If this were to be displayed as HTML it would be sensible to turn the
  257. * ampersand into '&amp;' and the apostrophe into '&aps;'. However if it were
  258. * going to be used as a string in JavaScript to be displayed in an alert box
  259. * it would be right to leave the string as-is, but c-escape the apostrophe and
  260. * the new line.
  261. */
  262. function twig_escape_filter(Twig_Environment $env, $string, $type = 'html', $charset = null)
  263. {
  264. if (is_object($string) && $string instanceof Twig_Markup) {
  265. return $string;
  266. }
  267. if (!is_string($string) && !(is_object($string) && method_exists($string, '__toString'))) {
  268. return $string;
  269. }
  270. if (null === $charset) {
  271. $charset = $env->getCharset();
  272. }
  273. switch ($type) {
  274. case 'js':
  275. // escape all non-alphanumeric characters
  276. // into their \xHH or \uHHHH representations
  277. if ('UTF-8' != $charset) {
  278. $string = _twig_convert_encoding($string, 'UTF-8', $charset);
  279. }
  280. if (null === $string = preg_replace_callback('#[^\p{L}\p{N} ]#u', '_twig_escape_js_callback', $string)) {
  281. throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
  282. }
  283. if ('UTF-8' != $charset) {
  284. $string = _twig_convert_encoding($string, $charset, 'UTF-8');
  285. }
  286. return $string;
  287. case 'html':
  288. return htmlspecialchars($string, ENT_QUOTES, $charset);
  289. default:
  290. throw new Twig_Error_Runtime(sprintf('Invalid escape type "%s".', $type));
  291. }
  292. }
  293. function twig_escape_filter_is_safe(Twig_Node $filterArgs)
  294. {
  295. foreach ($filterArgs as $arg) {
  296. if ($arg instanceof Twig_Node_Expression_Constant) {
  297. return array($arg->getAttribute('value'));
  298. } else {
  299. return array();
  300. }
  301. break;
  302. }
  303. return array('html');
  304. }
  305. if (function_exists('iconv')) {
  306. function _twig_convert_encoding($string, $to, $from)
  307. {
  308. return iconv($from, $to, $string);
  309. }
  310. } elseif (function_exists('mb_convert_encoding')) {
  311. function _twig_convert_encoding($string, $to, $from)
  312. {
  313. return mb_convert_encoding($string, $to, $from);
  314. }
  315. } else {
  316. function _twig_convert_encoding($string, $to, $from)
  317. {
  318. throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
  319. }
  320. }
  321. function _twig_escape_js_callback($matches)
  322. {
  323. $char = $matches[0];
  324. // \xHH
  325. if (!isset($char[1])) {
  326. return '\\x'.substr('00'.bin2hex($char), -2);
  327. }
  328. // \uHHHH
  329. $char = _twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
  330. return '\\u'.substr('0000'.bin2hex($char), -4);
  331. }
  332. // add multibyte extensions if possible
  333. if (function_exists('mb_get_info')) {
  334. function twig_length_filter(Twig_Environment $env, $thing)
  335. {
  336. return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
  337. }
  338. function twig_upper_filter(Twig_Environment $env, $string)
  339. {
  340. if (null !== ($charset = $env->getCharset())) {
  341. return mb_strtoupper($string, $charset);
  342. }
  343. return strtoupper($string);
  344. }
  345. function twig_lower_filter(Twig_Environment $env, $string)
  346. {
  347. if (null !== ($charset = $env->getCharset())) {
  348. return mb_strtolower($string, $charset);
  349. }
  350. return strtolower($string);
  351. }
  352. function twig_title_string_filter(Twig_Environment $env, $string)
  353. {
  354. if (null !== ($charset = $env->getCharset())) {
  355. return mb_convert_case($string, MB_CASE_TITLE, $charset);
  356. }
  357. return ucwords(strtolower($string));
  358. }
  359. function twig_capitalize_string_filter(Twig_Environment $env, $string)
  360. {
  361. if (null !== ($charset = $env->getCharset())) {
  362. return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
  363. mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
  364. }
  365. return ucfirst(strtolower($string));
  366. }
  367. }
  368. // and byte fallback
  369. else
  370. {
  371. function twig_length_filter(Twig_Environment $env, $thing)
  372. {
  373. return is_scalar($thing) ? strlen($thing) : count($thing);
  374. }
  375. function twig_title_string_filter(Twig_Environment $env, $string)
  376. {
  377. return ucwords(strtolower($string));
  378. }
  379. function twig_capitalize_string_filter(Twig_Environment $env, $string)
  380. {
  381. return ucfirst(strtolower($string));
  382. }
  383. }
  384. function twig_ensure_traversable($seq)
  385. {
  386. if (is_array($seq) || (is_object($seq) && $seq instanceof Traversable)) {
  387. return $seq;
  388. } else {
  389. return array();
  390. }
  391. }
  392. function twig_test_sameas($value, $test)
  393. {
  394. return $value === $test;
  395. }
  396. function twig_test_none($value)
  397. {
  398. return null === $value;
  399. }
  400. function twig_test_divisibleby($value, $num)
  401. {
  402. return 0 == $value % $num;
  403. }
  404. function twig_test_even($value)
  405. {
  406. return $value % 2 == 0;
  407. }
  408. function twig_test_odd($value)
  409. {
  410. return $value % 2 == 1;
  411. }
  412. function twig_test_constant($value, $constant)
  413. {
  414. return constant($constant) === $value;
  415. }
  416. function twig_test_defined($name, $context)
  417. {
  418. return array_key_exists($name, $context);
  419. }
  420. function twig_test_empty($value)
  421. {
  422. return null === $value || false === $value || '' === (string) $value;
  423. }