source: pro-violet-viettel/sourcecode/application/third_party/Twig/Extension/Core.php

Last change on this file was 345, checked in by quyenla, 11 years ago

collaborator page

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