PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/application/libraries/Twig/Extension/Core.php

https://bitbucket.org/masnug/grc276-blog-laravel
PHP | 847 lines | 406 code | 81 blank | 360 comment | 64 complexity | 4f33fd77978ec08e5ce720e31a2b4dba MD5 | raw file
  1. <?php
  2. if (!defined('ENT_SUBSTITUTE')) {
  3. define('ENT_SUBSTITUTE', 8);
  4. }
  5. /*
  6. * This file is part of Twig.
  7. *
  8. * (c) 2009 Fabien Potencier
  9. *
  10. * For the full copyright and license information, please view the LICENSE
  11. * file that was distributed with this source code.
  12. */
  13. class Twig_Extension_Core extends Twig_Extension
  14. {
  15. /**
  16. * Returns the token parser instance to add to the existing list.
  17. *
  18. * @return array An array of Twig_TokenParser instances
  19. */
  20. public function getTokenParsers()
  21. {
  22. return array(
  23. new Twig_TokenParser_For(),
  24. new Twig_TokenParser_If(),
  25. new Twig_TokenParser_Extends(),
  26. new Twig_TokenParser_Include(),
  27. new Twig_TokenParser_Block(),
  28. new Twig_TokenParser_Use(),
  29. new Twig_TokenParser_Filter(),
  30. new Twig_TokenParser_Macro(),
  31. new Twig_TokenParser_Import(),
  32. new Twig_TokenParser_From(),
  33. new Twig_TokenParser_Set(),
  34. new Twig_TokenParser_Spaceless(),
  35. );
  36. }
  37. /**
  38. * Returns a list of filters to add to the existing list.
  39. *
  40. * @return array An array of filters
  41. */
  42. public function getFilters()
  43. {
  44. $filters = array(
  45. // formatting filters
  46. 'date' => new Twig_Filter_Function('twig_date_format_filter'),
  47. 'format' => new Twig_Filter_Function('sprintf'),
  48. 'replace' => new Twig_Filter_Function('twig_strtr'),
  49. // encoding
  50. 'url_encode' => new Twig_Filter_Function('twig_urlencode_filter'),
  51. 'json_encode' => new Twig_Filter_Function('twig_jsonencode_filter'),
  52. // string filters
  53. 'title' => new Twig_Filter_Function('twig_title_string_filter', array('needs_environment' => true)),
  54. 'capitalize' => new Twig_Filter_Function('twig_capitalize_string_filter', array('needs_environment' => true)),
  55. 'upper' => new Twig_Filter_Function('strtoupper'),
  56. 'lower' => new Twig_Filter_Function('strtolower'),
  57. 'striptags' => new Twig_Filter_Function('strip_tags'),
  58. // array helpers
  59. 'join' => new Twig_Filter_Function('twig_join_filter'),
  60. 'reverse' => new Twig_Filter_Function('twig_reverse_filter'),
  61. 'length' => new Twig_Filter_Function('twig_length_filter', array('needs_environment' => true)),
  62. 'sort' => new Twig_Filter_Function('twig_sort_filter'),
  63. 'merge' => new Twig_Filter_Function('twig_array_merge'),
  64. // iteration and runtime
  65. 'default' => new Twig_Filter_Function('twig_default_filter'),
  66. 'keys' => new Twig_Filter_Function('twig_get_array_keys_filter'),
  67. // escaping
  68. 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
  69. 'e' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
  70. );
  71. if (function_exists('mb_get_info')) {
  72. $filters['upper'] = new Twig_Filter_Function('twig_upper_filter', array('needs_environment' => true));
  73. $filters['lower'] = new Twig_Filter_Function('twig_lower_filter', array('needs_environment' => true));
  74. }
  75. return $filters;
  76. }
  77. /**
  78. * Returns a list of global functions to add to the existing list.
  79. *
  80. * @return array An array of global functions
  81. */
  82. public function getFunctions()
  83. {
  84. return array(
  85. 'range' => new Twig_Function_Function('range'),
  86. 'constant' => new Twig_Function_Function('constant'),
  87. 'cycle' => new Twig_Function_Function('twig_cycle'),
  88. );
  89. }
  90. /**
  91. * Returns a list of filters to add to the existing list.
  92. *
  93. * @return array An array of filters
  94. */
  95. public function getTests()
  96. {
  97. return array(
  98. 'even' => new Twig_Test_Function('twig_test_even'),
  99. 'odd' => new Twig_Test_Function('twig_test_odd'),
  100. 'defined' => new Twig_Test_Function('twig_test_defined'),
  101. 'sameas' => new Twig_Test_Function('twig_test_sameas'),
  102. 'none' => new Twig_Test_Function('twig_test_none'),
  103. 'null' => new Twig_Test_Function('twig_test_none'),
  104. 'divisibleby' => new Twig_Test_Function('twig_test_divisibleby'),
  105. 'constant' => new Twig_Test_Function('twig_test_constant'),
  106. 'empty' => new Twig_Test_Function('twig_test_empty'),
  107. );
  108. }
  109. /**
  110. * Returns a list of operators to add to the existing list.
  111. *
  112. * @return array An array of operators
  113. */
  114. public function getOperators()
  115. {
  116. return array(
  117. array(
  118. 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
  119. '-' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Neg'),
  120. '+' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Pos'),
  121. ),
  122. array(
  123. 'b-and' => array('precedence' => 5, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  124. 'b-xor' => array('precedence' => 5, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  125. 'b-or' => array('precedence' => 5, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  126. 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  127. 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  128. '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  129. '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  130. '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  131. '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  132. '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  133. '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  134. 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  135. 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  136. '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  137. '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  138. '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  139. '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  140. '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  141. '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  142. '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  143. 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  144. 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  145. '..' => array('precedence' => 110, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
  146. '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
  147. ),
  148. );
  149. }
  150. public function parseNotTestExpression(Twig_Parser $parser, $node)
  151. {
  152. return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
  153. }
  154. public function parseTestExpression(Twig_Parser $parser, $node)
  155. {
  156. $stream = $parser->getStream();
  157. $name = $stream->expect(Twig_Token::NAME_TYPE);
  158. $arguments = null;
  159. if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
  160. $arguments = $parser->getExpressionParser()->parseArguments();
  161. }
  162. return new Twig_Node_Expression_Test($node, $name->getValue(), $arguments, $parser->getCurrentToken()->getLine());
  163. }
  164. /**
  165. * Returns the name of the extension.
  166. *
  167. * @return string The extension name
  168. */
  169. public function getName()
  170. {
  171. return 'core';
  172. }
  173. }
  174. /**
  175. * Cycles over a value.
  176. *
  177. * @param ArrayAccess|array $values An array or an ArrayAccess instance
  178. * @param integer $i The cycle value
  179. *
  180. * @return string The next value in the cycle
  181. */
  182. function twig_cycle($values, $i)
  183. {
  184. if (!is_array($values) && !$values instanceof ArrayAccess) {
  185. return $values;
  186. }
  187. return $values[$i % count($values)];
  188. }
  189. /**
  190. * Converts a date to the given format.
  191. *
  192. * <pre>
  193. * {{ post.published_at|date("m/d/Y") }}
  194. * </pre>
  195. *
  196. * @param DateTime|string $date A date
  197. * @param string $format A format
  198. * @param DateTimeZone|string $timezone A timezone
  199. *
  200. * @return string The formatter date
  201. */
  202. function twig_date_format_filter($date, $format = 'F j, Y H:i', $timezone = null)
  203. {
  204. if (!$date instanceof DateTime && !$date instanceof DateInterval) {
  205. if (ctype_digit((string) $date)) {
  206. $date = new DateTime('@'.$date);
  207. $date->setTimezone(new DateTimeZone(date_default_timezone_get()));
  208. } else {
  209. $date = new DateTime($date);
  210. }
  211. }
  212. if (null !== $timezone) {
  213. if (!$timezone instanceof DateTimeZone) {
  214. $timezone = new DateTimeZone($timezone);
  215. }
  216. $date->setTimezone($timezone);
  217. }
  218. return $date->format($format);
  219. }
  220. /**
  221. * URL encodes a string.
  222. *
  223. * @param string $url A URL
  224. * @param bool $raw true to use rawurlencode() instead of urlencode
  225. *
  226. * @return string The URL encoded value
  227. */
  228. function twig_urlencode_filter($url, $raw = false)
  229. {
  230. if ($raw) {
  231. return rawurlencode($url);
  232. }
  233. return urlencode($url);
  234. }
  235. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  236. /**
  237. * JSON encodes a PHP variable.
  238. *
  239. * @param mixed $value The value to encode.
  240. * @param integer $options Not used on PHP 5.2.x
  241. *
  242. * @return mixed The JSON encoded value
  243. */
  244. function twig_jsonencode_filter($value, $options = 0)
  245. {
  246. if ($value instanceof Twig_Markup) {
  247. $value = (string) $value;
  248. } elseif (is_array($value)) {
  249. array_walk_recursive($value, '_twig_markup2string');
  250. }
  251. return json_encode($value);
  252. }
  253. } else {
  254. /**
  255. * JSON encodes a PHP variable.
  256. *
  257. * @param mixed $value The value to encode.
  258. * @param integer $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
  259. *
  260. * @return mixed The JSON encoded value
  261. */
  262. function twig_jsonencode_filter($value, $options = 0)
  263. {
  264. if ($value instanceof Twig_Markup) {
  265. $value = (string) $value;
  266. } elseif (is_array($value)) {
  267. array_walk_recursive($value, '_twig_markup2string');
  268. }
  269. return json_encode($value, $options);
  270. }
  271. }
  272. function _twig_markup2string(&$value)
  273. {
  274. if ($value instanceof Twig_Markup) {
  275. $value = (string) $value;
  276. }
  277. }
  278. /**
  279. * Merges an array with another one.
  280. *
  281. * <pre>
  282. * {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
  283. *
  284. * {% set items = items|merge({ 'peugeot': 'car' }) %}
  285. *
  286. * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
  287. * </pre>
  288. *
  289. * @param array $arr1 An array
  290. * @param array $arr2 An array
  291. *
  292. * @return array The merged array
  293. */
  294. function twig_array_merge($arr1, $arr2)
  295. {
  296. if (!is_array($arr1) || !is_array($arr2)) {
  297. throw new Twig_Error_Runtime('The merge filter only work with arrays or hashes.');
  298. }
  299. return array_merge($arr1, $arr2);
  300. }
  301. /**
  302. * Joins the values to a string.
  303. *
  304. * The separator between elements is an empty string per default, you can define it with the optional parameter.
  305. *
  306. * <pre>
  307. * {{ [1, 2, 3]|join('|') }}
  308. * {# returns 1|2|3 #}
  309. *
  310. * {{ [1, 2, 3]|join }}
  311. * {# returns 123 #}
  312. * </pre>
  313. *
  314. * @param array $value An array
  315. * @param string $glue The separator
  316. *
  317. * @return string The concatenated string
  318. */
  319. function twig_join_filter($value, $glue = '')
  320. {
  321. return implode($glue, (array) $value);
  322. }
  323. /**
  324. * Returns the value or the default value when it is undefined or empty.
  325. *
  326. * <pre>
  327. *
  328. * {{ var.foo|default('foo item on var is not defined') }}
  329. *
  330. * </pre>
  331. *
  332. * @param mixed $value A value
  333. * @param mixed $default The default value
  334. *
  335. * @param mixed The value or the default value;
  336. */
  337. function twig_default_filter($value, $default = '')
  338. {
  339. if (twig_test_empty($value)) {
  340. return $default;
  341. } else {
  342. return $value;
  343. }
  344. }
  345. /**
  346. * Returns the keys for the given array.
  347. *
  348. * It is useful when you want to iterate over the keys of an array:
  349. *
  350. * <pre>
  351. * {% for key in array|keys %}
  352. * {# ... #}
  353. * {% endfor %}
  354. * </pre>
  355. *
  356. * @param array $array An array
  357. *
  358. * @return array The keys
  359. */
  360. function twig_get_array_keys_filter($array)
  361. {
  362. if (is_object($array) && $array instanceof Traversable) {
  363. return array_keys(iterator_to_array($array));
  364. }
  365. if (!is_array($array)) {
  366. return array();
  367. }
  368. return array_keys($array);
  369. }
  370. /**
  371. * Reverses an array.
  372. *
  373. * @param array|Traversable $array An array or a Traversable instance
  374. *
  375. * return array The array reversed
  376. */
  377. function twig_reverse_filter($array)
  378. {
  379. if (is_object($array) && $array instanceof Traversable) {
  380. return array_reverse(iterator_to_array($array));
  381. }
  382. if (!is_array($array)) {
  383. return array();
  384. }
  385. return array_reverse($array);
  386. }
  387. /**
  388. * Sorts an array.
  389. *
  390. * @param array $array An array
  391. */
  392. function twig_sort_filter($array)
  393. {
  394. asort($array);
  395. return $array;
  396. }
  397. /* used internally */
  398. function twig_in_filter($value, $compare)
  399. {
  400. if (is_array($compare)) {
  401. return in_array($value, $compare);
  402. } elseif (is_string($compare)) {
  403. return false !== strpos($compare, (string) $value);
  404. } elseif (is_object($compare) && $compare instanceof Traversable) {
  405. return in_array($value, iterator_to_array($compare, false));
  406. }
  407. return false;
  408. }
  409. /**
  410. * Replaces placeholders in a string.
  411. *
  412. * <pre>
  413. * {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }}
  414. * </pre>
  415. *
  416. * @param string $pattern A string
  417. * @param string $replacements The values for the placeholders
  418. *
  419. * @return string The string where the placeholders have been replaced
  420. */
  421. function twig_strtr($pattern, $replacements)
  422. {
  423. return str_replace(array_keys($replacements), array_values($replacements), $pattern);
  424. }
  425. /**
  426. * Escapes a string.
  427. *
  428. * @param Twig_Environment $env A Twig_Environment instance
  429. * @param string $string The value to be escaped
  430. * @param string $type The escaping strategy
  431. * @param string $charset The charset
  432. * @param Boolean $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
  433. */
  434. function twig_escape_filter(Twig_Environment $env, $string, $type = 'html', $charset = null, $autoescape = false)
  435. {
  436. if ($autoescape && is_object($string) && $string instanceof Twig_Markup) {
  437. return $string;
  438. }
  439. if (!is_string($string) && !(is_object($string) && method_exists($string, '__toString'))) {
  440. return $string;
  441. }
  442. if (null === $charset) {
  443. $charset = $env->getCharset();
  444. }
  445. switch ($type) {
  446. case 'js':
  447. // escape all non-alphanumeric characters
  448. // into their \xHH or \uHHHH representations
  449. if ('UTF-8' != $charset) {
  450. $string = _twig_convert_encoding($string, 'UTF-8', $charset);
  451. }
  452. if (null === $string = preg_replace_callback('#[^\p{L}\p{N} ]#u', '_twig_escape_js_callback', $string)) {
  453. throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
  454. }
  455. if ('UTF-8' != $charset) {
  456. $string = _twig_convert_encoding($string, $charset, 'UTF-8');
  457. }
  458. return $string;
  459. case 'html':
  460. return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
  461. default:
  462. throw new Twig_Error_Runtime(sprintf('Invalid escape type "%s".', $type));
  463. }
  464. }
  465. /* used internally */
  466. function twig_escape_filter_is_safe(Twig_Node $filterArgs)
  467. {
  468. foreach ($filterArgs as $arg) {
  469. if ($arg instanceof Twig_Node_Expression_Constant) {
  470. return array($arg->getAttribute('value'));
  471. } else {
  472. return array();
  473. }
  474. break;
  475. }
  476. return array('html');
  477. }
  478. if (function_exists('iconv')) {
  479. function _twig_convert_encoding($string, $to, $from)
  480. {
  481. return iconv($from, $to, $string);
  482. }
  483. } elseif (function_exists('mb_convert_encoding')) {
  484. function _twig_convert_encoding($string, $to, $from)
  485. {
  486. return mb_convert_encoding($string, $to, $from);
  487. }
  488. } else {
  489. function _twig_convert_encoding($string, $to, $from)
  490. {
  491. throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
  492. }
  493. }
  494. function _twig_escape_js_callback($matches)
  495. {
  496. $char = $matches[0];
  497. // \xHH
  498. if (!isset($char[1])) {
  499. return '\\x'.substr('00'.bin2hex($char), -2);
  500. }
  501. // \uHHHH
  502. $char = _twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
  503. return '\\u'.substr('0000'.bin2hex($char), -4);
  504. }
  505. // add multibyte extensions if possible
  506. if (function_exists('mb_get_info')) {
  507. /**
  508. * Returns the length of a PHP variable.
  509. *
  510. * @param Twig_Environment $env A Twig_Environment instance
  511. * @param mixed $thing A PHP variable
  512. *
  513. * @return integer The length of the value
  514. */
  515. function twig_length_filter(Twig_Environment $env, $thing)
  516. {
  517. return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
  518. }
  519. /**
  520. * Converts a string to uppercase.
  521. *
  522. * @param Twig_Environment $env A Twig_Environment instance
  523. * @param string $string A string
  524. *
  525. * @return string The uppercased string
  526. */
  527. function twig_upper_filter(Twig_Environment $env, $string)
  528. {
  529. if (null !== ($charset = $env->getCharset())) {
  530. return mb_strtoupper($string, $charset);
  531. }
  532. return strtoupper($string);
  533. }
  534. /**
  535. * Converts a string to lowercase.
  536. *
  537. * @param Twig_Environment $env A Twig_Environment instance
  538. * @param string $string A string
  539. *
  540. * @return string The lowercased string
  541. */
  542. function twig_lower_filter(Twig_Environment $env, $string)
  543. {
  544. if (null !== ($charset = $env->getCharset())) {
  545. return mb_strtolower($string, $charset);
  546. }
  547. return strtolower($string);
  548. }
  549. /**
  550. * Returns a titlecased string.
  551. *
  552. * @param Twig_Environment $env A Twig_Environment instance
  553. * @param string $string A string
  554. *
  555. * @return string The titlecased string
  556. */
  557. function twig_title_string_filter(Twig_Environment $env, $string)
  558. {
  559. if (null !== ($charset = $env->getCharset())) {
  560. return mb_convert_case($string, MB_CASE_TITLE, $charset);
  561. }
  562. return ucwords(strtolower($string));
  563. }
  564. /**
  565. * Returns a capitalized string.
  566. *
  567. * @param Twig_Environment $env A Twig_Environment instance
  568. * @param string $string A string
  569. *
  570. * @return string The capitalized string
  571. */
  572. function twig_capitalize_string_filter(Twig_Environment $env, $string)
  573. {
  574. if (null !== ($charset = $env->getCharset())) {
  575. return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
  576. mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
  577. }
  578. return ucfirst(strtolower($string));
  579. }
  580. }
  581. // and byte fallback
  582. else
  583. {
  584. /**
  585. * Returns the length of a PHP variable.
  586. *
  587. * @param Twig_Environment $env A Twig_Environment instance
  588. * @param mixed $thing A PHP variable
  589. *
  590. * @return integer The length of the value
  591. */
  592. function twig_length_filter(Twig_Environment $env, $thing)
  593. {
  594. return is_scalar($thing) ? strlen($thing) : count($thing);
  595. }
  596. /**
  597. * Returns a titlecased string.
  598. *
  599. * @param Twig_Environment $env A Twig_Environment instance
  600. * @param string $string A string
  601. *
  602. * @return string The titlecased string
  603. */
  604. function twig_title_string_filter(Twig_Environment $env, $string)
  605. {
  606. return ucwords(strtolower($string));
  607. }
  608. /**
  609. * Returns a capitalized string.
  610. *
  611. * @param Twig_Environment $env A Twig_Environment instance
  612. * @param string $string A string
  613. *
  614. * @return string The capitalized string
  615. */
  616. function twig_capitalize_string_filter(Twig_Environment $env, $string)
  617. {
  618. return ucfirst(strtolower($string));
  619. }
  620. }
  621. /* used internally */
  622. function twig_ensure_traversable($seq)
  623. {
  624. if (is_array($seq) || (is_object($seq) && $seq instanceof Traversable)) {
  625. return $seq;
  626. } else {
  627. return array();
  628. }
  629. }
  630. /**
  631. * Checks that a variable points to the same memory address than another one.
  632. *
  633. * <pre>
  634. * {% if foo.attribute is sameas(false) %}
  635. * the foo attribute really is the ``false`` PHP value
  636. * {% endif %}
  637. * </pre>
  638. *
  639. * @param mixed $value A PHP variable
  640. * @param mixed $test The PHP variable to test against
  641. *
  642. * @return Boolean true if the values are the same, false otherwise
  643. */
  644. function twig_test_sameas($value, $test)
  645. {
  646. return $value === $test;
  647. }
  648. /**
  649. * Checks that a variable is null.
  650. *
  651. * <pre>
  652. * {{ var is none }}
  653. * </pre>
  654. *
  655. * @param mixed $value a PHP variable.
  656. *
  657. * @return Boolean true if the value is null, false otherwise
  658. */
  659. function twig_test_none($value)
  660. {
  661. return null === $value;
  662. }
  663. /**
  664. * Checks if a variable is divisible by a number.
  665. *
  666. * <pre>
  667. * {% if loop.index is divisibleby(3) %}
  668. * </pre>
  669. *
  670. * @param integer $value A PHP value
  671. * @param integer $num A number
  672. *
  673. * @return Boolean true if the value is divisible by the number, false otherwise
  674. */
  675. function twig_test_divisibleby($value, $num)
  676. {
  677. return 0 == $value % $num;
  678. }
  679. /**
  680. * Checks if a number is even.
  681. *
  682. * <pre>
  683. * {{ var is even }}
  684. * </pre>
  685. *
  686. * @param integer $value An integer
  687. *
  688. * @return Boolean true if the value is even, false otherwise
  689. */
  690. function twig_test_even($value)
  691. {
  692. return $value % 2 == 0;
  693. }
  694. /**
  695. * Checks if a number is odd.
  696. *
  697. * <pre>
  698. * {{ var is odd }}
  699. * </pre>
  700. *
  701. * @param integer $value An integer
  702. *
  703. * @return Boolean true if the value is odd, false otherwise
  704. */
  705. function twig_test_odd($value)
  706. {
  707. return $value % 2 == 1;
  708. }
  709. /**
  710. * Checks if a variable is the exact same value as a constant.
  711. *
  712. * <pre>
  713. * {% if post.status is constant('Post::PUBLISHED') %}
  714. * the status attribute is exactly the same as Post::PUBLISHED
  715. * {% endif %}
  716. * </pre>
  717. *
  718. * @param mixed $value A PHP value
  719. * @param mixed $constant The constant to test against
  720. *
  721. * @return Boolean true if the value is the same as the constant, false otherwise
  722. */
  723. function twig_test_constant($value, $constant)
  724. {
  725. return constant($constant) === $value;
  726. }
  727. /**
  728. * Checks if a variable is defined in the current context.
  729. *
  730. * <pre>
  731. * {# defined works with variable names #}
  732. * {% if foo is defined %}
  733. * {# ... #}
  734. * {% endif %}
  735. * </pre>
  736. *
  737. * @param mixed $name A PHP variable
  738. * @param array $context The current context
  739. *
  740. * @return Boolean true if the value is defined, false otherwise
  741. */
  742. function twig_test_defined($name, $context)
  743. {
  744. return array_key_exists($name, $context);
  745. }
  746. /**
  747. * Checks if a variable is empty.
  748. *
  749. * <pre>
  750. * {# evaluates to true if the foo variable is null, false, or the empty string #}
  751. * {% if foo is empty %}
  752. * {# ... #}
  753. * {% endif %}
  754. * </pre>
  755. *
  756. * @param mixed $value A PHP variable
  757. *
  758. * @return Boolean true if the value is empty, false otherwise
  759. */
  760. function twig_test_empty($value)
  761. {
  762. if ($value instanceof Countable) {
  763. return 0 == count($value);
  764. }
  765. return false === $value || (empty($value) && '0' != $value);
  766. }