├── LICENSE
├── README.md
├── bin
└── generate_readme
├── composer.json
├── docs
├── filters
│ ├── SI.md
│ ├── _package.md
│ ├── age.md
│ ├── bytes.md
│ ├── date.md
│ ├── filePermissions.md
│ ├── lowerRoman.md
│ ├── upperFirst.md
│ └── upperRoman.md
└── tests
│ ├── _package.md
│ └── numeric.md
└── src
└── Twig
├── Filters
├── AgeFilter.php
├── BytesFilter.php
├── DateFilter.php
├── FilePermissionsFilter.php
├── LowerRomanFilter.php
├── SIFilter.php
├── UpperFirstFilter.php
└── UpperRomanFilter.php
├── Tests
└── NumericTest.php
└── Text
└── RomanNumeralsTrait.php
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) https://github.com/GeckoPackages
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Abandoned!
2 |
3 | We will try to move anything of value from here to twigphp/Twig-extensions if possible.
4 |
--------------------------------------------------------------------------------
/bin/generate_readme:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | generateReadMe())) {
19 | echo sprintf("\nFailed to write content to \"%s\".", $readMeFile);
20 | exit(-1);
21 | }
22 |
23 | exit(0);
24 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gecko-packages/gecko-twig",
3 | "type": "library",
4 | "homepage": "https://github.com/GeckoPackages",
5 | "description": "Additional Twig filters and tests.",
6 | "license": "MIT",
7 | "keywords": ["Twig", "Filter", "Bytes", "SI", "Roman"],
8 | "require": {
9 | "php": ">=7.0 <7.3",
10 | "twig/twig": "^2.0"
11 | },
12 | "require-dev": {
13 | "phpunit/phpunit": "^4.5|^5",
14 | "symfony/phpunit-bridge": "^2.8|^3.0"
15 | },
16 | "suggest": {
17 | "ext-mbstring": "For multi byte character support."
18 | },
19 | "autoload": {
20 | "psr-4": {
21 | "GeckoPackages\\Twig\\": "src\\Twig"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/filters/SI.md:
--------------------------------------------------------------------------------
1 | ### SI
2 |
3 | Formats a number with a SI symbol, either automatically or by given symbol.
4 |
5 | Formats a number with a [SI symbol](https://en.wikipedia.org/wiki/Metric_prefix#List_of_SI_prefixes), either automatically or by given symbol.
6 |
7 | Symbols supported:
8 |
9 | | Symbol | Description | | |
10 | | ------ | ----------------------- | ------------- | ----------------------------------- |
11 | | y | yocto | septillionth | 0.000 000 000 000 000 000 000 001 |
12 | | z | zepto | sextillionth | 0.000 000 000 000 000 000 001 |
13 | | a | atto | quintillionth | 0.000 000 000 000 000 001 |
14 | | f | femto | quadrillionth | 0.000 000 000 000 001 |
15 | | p | pico | trillionth | 0.000 000 000 001 |
16 | | n | nano | billionth | 0.000 000 001 |
17 | | μ(/u) | micro | millionth | 0.000 001 |
18 | | m | milli | thousandth | 0.001 |
19 | | c | centi | hundredth | 0.01 |
20 | | d | deci | tenth | 0.1 |
21 | | | one | one | 1 |
22 | | da | deca | ten | 10 |
23 | | h | hecto | hundred | 100 |
24 | | k(/K) | kilo | thousand | 1000 |
25 | | M | mega | million | 1000 000 |
26 | | G | giga | billion | 1000 000 000 |
27 | | T | tera | trillion | 1000 000 000 000 |
28 | | P | peta | quadrillion | 1000 000 000 000 000 |
29 | | E | exa | quintillion | 1000 000 000 000 000 000 |
30 | | Z | zetta | sextillion | 1000 000 000 000 000 000 000 |
31 | | Y | yotta | septillion | 1000 000 000 000 000 000 000 000 |
32 | | 'auto' | Auto match (best match) | - | * |
33 |
34 | The default used by the filter is `auto`.
35 |
36 | #### Examples
37 |
38 | ```Twig
39 | {{ 1|SI('z') }}
40 | {# 1,000,000,000,000,000,000,000z #}
41 |
42 | {{ '1337e0'|SI }}
43 | {# 1K #}
44 |
45 | {{ 4.2|SI('μ') }}
46 | {# 4,200,000μ #}
47 |
48 | {{ '-8123456'|SI('', '%number% %symbol%', 2, ',', '.') }}
49 | {# -8.123.456,00 #}
50 |
51 | {{ 1500000000000000000000000|SI('Y', '%number% %symbol%', 2, ',', '')|raw }}
52 | {# 1,50 Y #}
53 |
54 | ```
55 |
56 | The filter uses the number formatting set on the `Core` extension of Twig. The output can be customized even more by passing a `format`.
57 |
--------------------------------------------------------------------------------
/docs/filters/_package.md:
--------------------------------------------------------------------------------
1 | You can add any of the filters to the Twig environment.
2 | Example:
3 |
4 | ```php
5 | /** @var Twig_Environment $env */
6 | $env->addFilter(new \GeckoPackages\Twig\Filters\AgeFilter());
7 | ```
8 |
--------------------------------------------------------------------------------
/docs/filters/age.md:
--------------------------------------------------------------------------------
1 | ### Age
2 |
3 | Calculates the time difference (age) between a date and the current date.
4 |
5 | Calculates and returns the time difference (age) between a date and the current date.
6 |
7 | You use an accuracy:
8 |
9 | | symbol | accuracy |
10 | | ------ | -------- |
11 | | y | Year |
12 | | d | Day |
13 | | h | Hour |
14 | | i | Minute |
15 | | s | Seconds |
16 |
17 | The default is `y`. Symbols are case insensitive.
18 |
19 | #### Examples
20 |
21 | ```Twig
22 | {# today is new \DateTime() #}
23 |
24 | {{ today|date_modify("-36 hours")|age('d') }} day.
25 | {# 1.5 day. #}
26 |
27 | {{ today|date_modify("180 minutes")|age('h') }} hours.
28 | {# -3 hours. note the "minus" "#}
29 |
30 | {{ today|date_modify("-180 minutes")|age('i') }} minutes.
31 | {# 180 minutes. #}
32 |
33 | {{ today|date_modify("-180 minutes")|age('s') }} seconds.
34 | {# 10800 seconds. #}
35 |
36 | ```
37 |
38 | Pass a timezone as second argument to set for the date passed. \*
39 | Pass a timezone as third argument for creating the current date. \*
40 |
41 | * Pass `null` to use the default, `false` to leave unchanged.
42 |
--------------------------------------------------------------------------------
/docs/filters/bytes.md:
--------------------------------------------------------------------------------
1 | ### Bytes
2 |
3 | Formats a number of bytes with binary or SI prefix multiple, either automatically or by given symbol.
4 |
5 | Formats a number of bytes to a specific SI or binary unit or in a auto (best match) way.
6 | Specific units of IEC 60027-2 A.2 (1024 based [binary prefix](https://en.wikipedia.org/wiki/Binary_prefix)) and SI (1000 based [SI prefix](https://en.wikipedia.org/wiki/Metric_prefix#List_of_SI_prefixes)) are supported.
7 |
8 | Symbols supported:
9 |
10 | | binary | SI |
11 | | ----------- | ------------- |
12 | | b (bit) | b (bit) |
13 | | B (byte) | B (byte) |
14 | | Ki (kibi) | k(/K) (kilo) |
15 | | Mi (mebi) | M (mega) |
16 | | Gi (gibi) | G (giga) |
17 | | Ti (tebi) | T (tera) |
18 | | Pi (pebi) | P (peta) |
19 | | Ei (exbi) | E (exa) |
20 | | Zi (zebi) | Z (zetta) |
21 | | Yi (yobi) | Y (yotta) |
22 | | 'auto,bin' | 'auto,SI' |
23 |
24 | The default is `auto,bin`.
25 |
26 | #### Examples
27 |
28 | ```Twig
29 |
30 | {{ 1099511627776|bytes }}
31 | {# 1TiB #}
32 |
33 | {{ 1000|bytes('auto,SI') }}
34 | {# 1KB #}
35 |
36 | {{ (1024*2)|bytes('Kib') }}
37 | {# 16Kib #}
38 |
39 | {{ (250.5 * 1048576)|bytes('auto,bin', '%number% %symbol%', 4, ',', '') }}
40 | {# 250,5000 MiB #}
41 |
42 | ```
43 |
44 | The filter uses the number formatting set on the `Core` extension of Twig. The output can be customized even more by passing a `format`.
45 |
--------------------------------------------------------------------------------
/docs/filters/date.md:
--------------------------------------------------------------------------------
1 | ### Date
2 |
3 | Replacement for the date filter of Twig, returns an empty string if the date is `empty()`.
4 |
5 | Replacement of the date filter provided by [Twig](http://twig.sensiolabs.org/doc/filters/date.html). Returns an empty string `""` if the give date to format is `empty()` (and not an `array`).
6 | If it is not the method returns the value as provided by the default date filter of Twig.
7 |
8 | #### Examples
9 |
10 | ```Twig
11 | zero int [{{ 0|date }}]
12 | {# zero int [] #}
13 | zero float [{{ 0.0|date }}]
14 | {# zero float [] #}
15 | zero string [{{ '0'|date }}]
16 | {# zero string [] #}
17 | empty string [{{ ''|date }}]
18 | {# empty string [] #}
19 | null value [{{ null|date }}]
20 | {# null value [] #}
21 | false value [{{ false|date }}]
22 | {# false value [] #}
23 | timestamp [{{ timestamp|date('m/d/Y') }}]
24 | {# timestamp [09/19/2016] #}
25 | ```
26 |
--------------------------------------------------------------------------------
/docs/filters/filePermissions.md:
--------------------------------------------------------------------------------
1 | ### File Permissions
2 |
3 | Formats file permissions in symbolic (UNIX) notation.
4 |
5 | Formats file permissions in symbolic (UNIX) notation.
6 |
7 | #### Examples
8 |
9 | ```Twig
10 |
11 | {{ 755|filePermissions}}
12 | {# urwxr-xr-x #}
13 |
14 | {{ './'|filePermissions}}
15 | {# drwxrwxr-x #}
16 |
17 | {{ '0444'|filePermissions}}
18 | {# ur--r--r-- #}
19 |
20 | ```
21 |
--------------------------------------------------------------------------------
/docs/filters/lowerRoman.md:
--------------------------------------------------------------------------------
1 | ### Lower Roman
2 |
3 | Lowercase Roman numerals in a string.
4 |
5 | Lowercase Roman numerals in a string.
6 | Supports the Roman numerals in modern notation (`strict`) or `loose` notation.
7 |
8 | | Roman | Value |
9 | | ----- |------ |
10 | | I | 1 |
11 | | IV | 4 |
12 | | V | 5 |
13 | | IX | 9 |
14 | | X | 10 |
15 | | XL | 40 |
16 | | L | 50 |
17 | | XC | 90 |
18 | | C | 100 |
19 | | CD | 400 |
20 | | D | 500 |
21 | | CM | 900 |
22 | | M | 1000 |
23 |
24 | Note: large numbers, for example in 'apostrophus' and 'vinculum' are not supported.
25 |
26 | In `strict` mode:
27 | - Symbols are combined from left to right, high to low values.
28 | - Symbols are not repeated more than 3 times.
29 | - C may b placed after D or M.
30 | - X may be placed before L or C.
31 | - I may be placed before V or X.
32 | - This makes the maximum number supported 'MMMCMXCIX'.
33 |
34 | In `loose` mode, follows `strict` mode with the following exceptions:
35 | - Symbols may be repeated more than 3 times.
36 | - There is no more maximum number.
37 |
38 | In `loose-order`, follows `loose` mode with the following exception:
39 | - Symbols may appear in any order.
40 |
41 | The default mode is `strict`.
42 |
43 | More details and background information on [Wikipedia](https://en.wikipedia.org/wiki/Roman_numerals).
44 |
45 | #### Examples
46 |
47 | ```Twig
48 |
49 | {{ 'MCMLIV. Chapter sub XI NOT XICA'|lowerRoman }}
50 | {# mcmliv. Chapter sub xi NOT XICA #}
51 |
52 | {{ 'IIXX, XIiX, III, MDcdIII, TESTXI, MMMM'|lowerRoman('loose-order') }}
53 | {# iixx, xiix, iii, mdcdiii, TESTXI, mmmm #}
54 |
55 | ```
56 |
--------------------------------------------------------------------------------
/docs/filters/upperFirst.md:
--------------------------------------------------------------------------------
1 | ### Upper First
2 |
3 | Uppercase the first character of a string.
4 |
5 | Uppercase the first character of a string. For multi byte character support the filter will use [`mbstring`](https://secure.php.net/manual/en/book.mbstring.php).
6 |
7 | #### Examples
8 |
9 | ```Twig
10 |
11 | {{ 'hello world!'|upperFirst }}
12 | {# Hello world! #}
13 |
14 | {{ 'čůrá Test'|upperFirst }}
15 | {# Čůrá Test #}
16 |
17 | ```
18 |
--------------------------------------------------------------------------------
/docs/filters/upperRoman.md:
--------------------------------------------------------------------------------
1 | ### Upper Roman
2 |
3 | Uppercase Roman numerals in a string.
4 |
5 | Uppercase Roman numerals in a string.
6 | For details about the supported `modes` see the `Lower Roman` filter.
7 |
8 | The default mode is `strict`.
9 |
10 | #### Examples
11 |
12 | ```Twig
13 |
14 | {{ 'a vi b'|upperRoman }}
15 | {# a VI b #}
16 |
17 | {{ 'mcmliv. chapter sub xi not XiCa'|upperRoman }}
18 | {# MCMLIV. chapter sub XI not XiCa #}
19 |
20 |
21 | ```
22 |
--------------------------------------------------------------------------------
/docs/tests/_package.md:
--------------------------------------------------------------------------------
1 | You can add any of the tests to the Twig environment.
2 | Example:
3 |
4 | ```php
5 | /** @var Twig_Environment $env */
6 | $env->addTest(new \GeckoPackages\Twig\Tests\NumericTest());
7 | ```
8 |
--------------------------------------------------------------------------------
/docs/tests/numeric.md:
--------------------------------------------------------------------------------
1 | ### Numeric
2 |
3 | Test given value is numeric (behaviour like PHP 7).
4 |
5 | Test if a given value is `numeric`.
6 | The test will return false for hexadecimal strings as this is the behaviour of [`is_numeric`](https://secure.php.net/manual/en/function.is-numeric.php) on PHP 7.
7 |
8 | #### Examples
9 |
10 | ```Twig
11 |
12 | {{ 12 is numeric ? 'Yes' : 'No' }}
13 | {# Yes #}
14 |
15 | {{ '-1.3' is numeric ? 'Yes' : 'No' }}
16 | {# Yes #}
17 |
18 | {{ '0x539' is not numeric ? 'Hex. is not numeric' : 'N'}}
19 | {# Hex. is not numeric #}
20 |
21 | ```
22 |
--------------------------------------------------------------------------------
/src/Twig/Filters/AgeFilter.php:
--------------------------------------------------------------------------------
1 | diff($date, false);
49 |
50 | switch (strtolower($acc)) {
51 | case 'y':
52 | $v =
53 | $diff->y
54 | + ($diff->m / 12)
55 | + (($diff->d + (($diff->h + (($diff->i + ($diff->s / 60)) / 60)) / 24)) / 365)
56 | ;
57 |
58 | break;
59 | // case 'm' is not supported by design
60 | case 'd':
61 | $v =
62 | (int) $diff->format('%a')
63 | + (($diff->h + (($diff->i + ($diff->s / 60)) / 60)) / 24)
64 | ;
65 |
66 | break;
67 | case 'h':
68 | $v =
69 | 24 * (int) $diff->format('%a')
70 | + $diff->h
71 | + (($diff->i + ($diff->s / 60)) / 60)
72 | ;
73 |
74 | break;
75 | case 'i':
76 | $v =
77 | 60 * 24 * (int) $diff->format('%a')
78 | + 60 * $diff->h
79 | + $diff->i
80 | + ($diff->s / 60)
81 | ;
82 |
83 | break;
84 | case 's':
85 | return (int) $now->format('U') - (int) $date->format('U');
86 | default:
87 | throw new \Twig_Error_Runtime(sprintf('Accuracy must be any of "y, d, h, i, s", got "%s".', $acc));
88 | }
89 |
90 | // (int) cast for HHVM =< 3.9.10
91 | // https://github.com/facebook/hhvm/pull/6134 / https://github.com/facebook/hhvm/issues/5537
92 | return 1 === (int) $diff->invert ? $v : -1 * $v;
93 | },
94 | ['needs_environment' => true]
95 | );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/Twig/Filters/BytesFilter.php:
--------------------------------------------------------------------------------
1 | 1, // kilo
73 | 'K' => 1, // "
74 | 'M' => 2, // mega
75 | 'G' => 3, // giga
76 | 'T' => 4, // tera
77 | 'P' => 5, // peta
78 | 'E' => 6, // exa
79 | 'Z' => 7, // zetta
80 | 'Y' => 8, // yotta
81 | ];
82 |
83 | if ($symbolLength === 1) {
84 | if ('b' === $symbol) {
85 | $number *= 8;
86 | } elseif ('B' !== $symbol) {
87 | throw new \Twig_Error_Runtime(sprintf('Unsupported symbol \'%s\'.', $symbol));
88 | }
89 | } elseif ($symbolLength <= 3) {
90 | // SI vs. bin.
91 | switch ($symbol[1]) {
92 | case 'i': { // Binary
93 | if ($symbolLength < 3) {
94 | throw new \Twig_Error_Runtime(sprintf('Binary symbol must be end with either \'b\' or \'B\', got "%s".', $symbol));
95 | } elseif ('b' === $symbol[2]) { // binary| bit
96 | $number *= 8;
97 | } elseif ('B' !== $symbol[2]) { // binary| byte
98 | throw new \Twig_Error_Runtime(sprintf('Binary symbol must be end with either \'b\' or \'B\', got "%s".', $symbol));
99 | }
100 |
101 | $magnitude = 1024;
102 | break;
103 | }
104 | case 'b': { // SI | bit
105 | $magnitude = 1000;
106 | $number *= 8;
107 | break;
108 | }
109 | case 'B': { // SI | byte
110 | $magnitude = 1000;
111 | break;
112 | }
113 | default: {
114 | throw new \Twig_Error_Runtime(sprintf('Symbol must be binary (b|B[x]) or SI and must end with either \'b\' or \'B\', got "%s".', $symbol));
115 | }
116 | }
117 |
118 | if (!array_key_exists($symbol[0], $symbolMag)) {
119 | throw new \Twig_Error_Runtime(sprintf('Symbol must start with \'k\', \'K\', \'M\', \'G\', \'T\', \'P\', \'E\', \'Z\', or \'Y\', got "%s".', $symbol));
120 | }
121 |
122 | $number /= pow($magnitude, $symbolMag[$symbol[0]]); // ** on PHP 5.6
123 | } elseif ('auto,bin' === $symbol) {
124 | if ($number < 1024 && $number > -1024) {
125 | $symbol = 'B';
126 | } else {
127 | $negative = $number < 0;
128 | $number = $negative ? abs($number) : $number;
129 |
130 | // since it is not guaranteed that array() will set the pointer to the first element
131 | reset($symbolMag);
132 | $mag = 0;
133 |
134 | while ($number >= 1023.9999999999 && $mag <= 8) { // large numbers rounding issues
135 | ++$mag;
136 | $number /= 1024; // $number >>= 10; doesn't work for large numbers (> PHP_INT_MAX) and looses the decimals
137 | next($symbolMag);
138 | }
139 |
140 | if ($negative) {
141 | $number *= -1;
142 | }
143 | $symbol = key($symbolMag).'iB';
144 | }
145 | } elseif ('auto,SI' === $symbol) {
146 | if ($number < 1000 && $number > -1000) {
147 | $symbol = 'B';
148 | } else {
149 | $negative = $number < 0;
150 | $number = $negative ? abs($number) : $number;
151 |
152 | // since it is not guaranteed that array() will set the pointer to the first element
153 | reset($symbolMag);
154 | $mag = 0;
155 | while ($number >= 1000 && $mag <= 8) {
156 | ++$mag;
157 | $number /= 1000;
158 | next($symbolMag);
159 | }
160 |
161 | if ($negative) {
162 | $number *= -1;
163 | }
164 |
165 | $symbol = key($symbolMag).'B';
166 | }
167 | } else {
168 | throw new \Twig_Error_Runtime(sprintf('Unsupported symbol "%s".', $symbol));
169 | }
170 |
171 | $defaults = $env->getExtension('Twig_Extension_Core')->getNumberFormat();
172 | if (null === $decimal) {
173 | $decimal = $defaults[0];
174 | }
175 |
176 | if (null === $decimalPoint) {
177 | $decimalPoint = $defaults[1];
178 | }
179 |
180 | if (null === $thousandSep) {
181 | $thousandSep = $defaults[2];
182 | }
183 |
184 | $number = number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
185 | $format = str_replace('%symbol%', $symbol, $format);
186 |
187 | return str_replace('%number%', $number, $format);
188 | },
189 | ['needs_environment' => true] // 'is_safe' => false: since the given $format which might need escaping is returned.
190 | );
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/src/Twig/Filters/DateFilter.php:
--------------------------------------------------------------------------------
1 | true]
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Twig/Filters/FilePermissionsFilter.php:
--------------------------------------------------------------------------------
1 | false: since the given $string which might need escaping is returned.
82 | );
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Twig/Filters/LowerRomanFilter.php:
--------------------------------------------------------------------------------
1 | numeralRomanMatchCallBack(
41 | $string,
42 | $matchMode,
43 | function (array $matches) {
44 | if (empty($matches[1])) {
45 | return $matches[1];
46 | }
47 |
48 | return strtolower($matches[1]);
49 | }
50 | );
51 | }
52 | // array $options, 'is_safe' => false: since the given $string which might need escaping is returned.
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Twig/Filters/SIFilter.php:
--------------------------------------------------------------------------------
1 | 1 note: double 'k'/'K 'and two char. 'da'
74 | ];
75 |
76 | if (1 === strlen($symbol) || 'μ' === $symbol) { // note: string length of 'μ' is 2
77 | $index = array_search($symbol, $symbolMag, true);
78 | if (false === $index) {
79 | throw new \Twig_Error_Runtime(sprintf('Unsupported symbol "%s".', $symbol));
80 | }
81 |
82 | if ($index > 10) {
83 | // division
84 | if ($index > 13) {
85 | $index -= 3; // double 'k' correction
86 | $pow = 1000;
87 | } else {
88 | $pow = 10;
89 | }
90 |
91 | $number /= pow($pow, $index - 10); // -10 includes the double 'u' correction
92 | } else {
93 | // multiply
94 | if ($index > 8) {
95 | $pow = 10;
96 | $index -= 3; // includes the double 'u' correction
97 | } else {
98 | if ($index > 6) {
99 | --$index; // double 'u' correction
100 | }
101 |
102 | $pow = 1000;
103 | }
104 |
105 | $number *= pow($pow, 8 - $index);
106 | }
107 | } elseif ($symbol === 'da') {
108 | $number /= 10;
109 | } elseif ($symbol === 'auto') {
110 | $negative = $number < 0;
111 | $number = $negative ? abs($number) : $number;
112 |
113 | if (($number >= 1 && $number <= 10) || 0 === $number) {
114 | $symbol = '';
115 | } elseif ($number < 1) {
116 | if ($number < 0.001) {
117 | $mag = 8;
118 | while ($number < 1 && $mag >= 0) {
119 | --$mag; // first decrement is double 'u' correction
120 | $number *= 1000;
121 | }
122 | } else {
123 | $mag = 11;
124 | while ($number < 1) {
125 | --$mag;
126 | $number *= 10;
127 | }
128 | }
129 |
130 | $symbol = $symbolMag[$mag];
131 | } else {
132 | if ($number < 1000) {
133 | $mag = 0;
134 | while ($number >= 10) {
135 | ++$mag;
136 | $number /= 10;
137 | }
138 | } else {
139 | $mag = 2;
140 | while ($number >= 1000 && $mag <= 10) {
141 | ++$mag;
142 | $number /= 1000;
143 | }
144 | }
145 |
146 | $mag += $mag > 2 ? 11 : 10;
147 | $symbol = $symbolMag[$mag];
148 | }
149 |
150 | if ($negative) {
151 | $number *= -1;
152 | }
153 | } elseif ($symbol !== '') {
154 | throw new \Twig_Error_Runtime(sprintf('Unsupported symbol "%s".', $symbol));
155 | }
156 |
157 | $defaults = $env->getExtension('Twig_Extension_Core')->getNumberFormat();
158 | if (null === $decimal) {
159 | $decimal = $defaults[0];
160 | }
161 |
162 | if (null === $decimalPoint) {
163 | $decimalPoint = $defaults[1];
164 | }
165 |
166 | if (null === $thousandSep) {
167 | $thousandSep = $defaults[2];
168 | }
169 |
170 | $number = number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
171 | $format = str_replace('%symbol%', $symbol, $format);
172 | if ('' === $symbol) {
173 | $format = trim($format);
174 | }
175 |
176 | return str_replace('%number%', $number, $format);
177 | },
178 | ['needs_environment' => true] // 'is_safe' => false: since the given $format which might need escaping is returned.
179 | );
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/src/Twig/Filters/UpperFirstFilter.php:
--------------------------------------------------------------------------------
1 | getCharset()) {
50 | return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_substr($string, 1, mb_strlen($string, $charset), $charset);
51 | }
52 |
53 | return ucfirst($string);
54 | },
55 | ['needs_environment' => true] // 'is_safe' => false: since the given $format which might need escaping is returned.
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Twig/Filters/UpperRomanFilter.php:
--------------------------------------------------------------------------------
1 | numeralRomanMatchCallBack(
41 | $string,
42 | $matchMode,
43 | function (array $matches) {
44 | if (empty($matches[1])) {
45 | return $matches[1];
46 | }
47 |
48 | return strtoupper($matches[1]);
49 | }
50 | );
51 | }
52 | // array $options, 'is_safe' => false: since the given $string which might need escaping is returned.
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Twig/Tests/NumericTest.php:
--------------------------------------------------------------------------------
1 | 'GeckoPackages\Twig\Tests\NumericTestNode']
29 | );
30 | }
31 | }
32 |
33 | final class NumericTestNode extends \Twig_Node_Expression_Test
34 | {
35 | public function compile(\Twig_Compiler $compiler)
36 | {
37 | $compiler->raw('is_numeric(')->subcompile($this->getNode('node'))->raw(')');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Twig/Text/RomanNumeralsTrait.php:
--------------------------------------------------------------------------------
1 |