Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
95.08% |
58 / 61 |
|
72.73% |
8 / 11 |
CRAP | |
0.00% |
0 / 1 |
extension | |
95.08% |
58 / 61 |
|
72.73% |
8 / 11 |
17 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTokenParsers | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getFilters | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
getFunctions | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getOperators | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
1 | |||
loop_subset | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
5 | |||
lang | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
lang_defined | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
lang_js | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
lang_raw | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\template\twig; |
15 | |
16 | use Twig\Error\RuntimeError; |
17 | use Twig\Extension\CoreExtension; |
18 | use Twig\Runtime\EscaperRuntime; |
19 | |
20 | class extension extends \Twig\Extension\AbstractExtension |
21 | { |
22 | /** @var \phpbb\template\context */ |
23 | protected $context; |
24 | |
25 | /** @var \phpbb\template\twig\environment */ |
26 | protected $environment; |
27 | |
28 | /** @var \phpbb\language\language */ |
29 | protected $language; |
30 | |
31 | /** |
32 | * Constructor |
33 | * |
34 | * @param \phpbb\template\context $context |
35 | * @param \phpbb\template\twig\environment $environment |
36 | * @param \phpbb\language\language $language |
37 | */ |
38 | public function __construct(\phpbb\template\context $context, \phpbb\template\twig\environment $environment, $language) |
39 | { |
40 | $this->context = $context; |
41 | $this->environment = $environment; |
42 | $this->language = $language; |
43 | } |
44 | |
45 | /** |
46 | * Get the name of this extension |
47 | * |
48 | * @return string |
49 | */ |
50 | public function getName() |
51 | { |
52 | return 'phpbb'; |
53 | } |
54 | |
55 | /** |
56 | * Returns the token parser instance to add to the existing list. |
57 | * |
58 | * @return \Twig\TokenParser\TokenParserInterface[] An array of \Twig\TokenParser\AbstractTokenParser instances |
59 | */ |
60 | public function getTokenParsers() |
61 | { |
62 | return array( |
63 | new \phpbb\template\twig\tokenparser\defineparser, |
64 | new \phpbb\template\twig\tokenparser\includeparser, |
65 | new \phpbb\template\twig\tokenparser\includejs, |
66 | new \phpbb\template\twig\tokenparser\includecss, |
67 | new \phpbb\template\twig\tokenparser\event($this->environment), |
68 | ); |
69 | } |
70 | |
71 | /** |
72 | * Returns a list of filters to add to the existing list. |
73 | * |
74 | * @return \Twig\TwigFilter[] An array of filters |
75 | */ |
76 | public function getFilters() |
77 | { |
78 | return array( |
79 | new \Twig\TwigFilter('subset', array($this, 'loop_subset'), array('needs_environment' => true)), |
80 | // @deprecated 3.2.0 Uses twig's JS escape method instead of addslashes |
81 | new \Twig\TwigFilter('addslashes', 'addslashes'), |
82 | new \Twig\TwigFilter('int', 'intval'), |
83 | new \Twig\TwigFilter('float', 'floatval'), |
84 | ); |
85 | } |
86 | |
87 | /** |
88 | * Returns a list of global functions to add to the existing list. |
89 | * |
90 | * @return \Twig\TwigFunction[] An array of global functions |
91 | */ |
92 | public function getFunctions() |
93 | { |
94 | return array( |
95 | new \Twig\TwigFunction('lang', array($this, 'lang')), |
96 | new \Twig\TwigFunction('lang_defined', array($this, 'lang_defined')), |
97 | new \Twig\TwigFunction('lang_js', [$this, 'lang_js']), |
98 | new \Twig\TwigFunction('lang_raw', [$this, 'lang_raw']), |
99 | new \Twig\TwigFunction('get_class', 'get_class'), |
100 | ); |
101 | } |
102 | |
103 | /** |
104 | * Returns a list of operators to add to the existing list. |
105 | * |
106 | * @return array[] An array of operators |
107 | * @psalm-suppress LessSpecificImplementedReturnType |
108 | */ |
109 | public function getOperators() |
110 | { |
111 | return array( |
112 | array( |
113 | '!' => array('precedence' => 50, 'class' => '\Twig\Node\Expression\Unary\NotUnary'), |
114 | ), |
115 | array( |
116 | // precedence settings are copied from similar operators in Twig core extension |
117 | '||' => array('precedence' => 10, 'class' => '\Twig\Node\Expression\Binary\OrBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
118 | '&&' => array('precedence' => 15, 'class' => '\Twig\Node\Expression\Binary\AndBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
119 | |
120 | 'eq' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\EqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
121 | |
122 | 'ne' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\NotEqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
123 | 'neq' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\NotEqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
124 | '<>' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\NotEqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
125 | |
126 | '===' => array('precedence' => 20, 'class' => '\phpbb\template\twig\node\expression\binary\equalequal', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
127 | '!==' => array('precedence' => 20, 'class' => '\phpbb\template\twig\node\expression\binary\notequalequal', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
128 | |
129 | 'gt' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\GreaterBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
130 | 'gte' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\GreaterEqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
131 | 'ge' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\GreaterEqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
132 | 'lt' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\LessBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
133 | 'lte' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\LessEqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
134 | 'le' => array('precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\LessEqualBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
135 | |
136 | 'mod' => array('precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\ModBinary', 'associativity' => \Twig\ExpressionParser::OPERATOR_LEFT), |
137 | ), |
138 | ); |
139 | } |
140 | |
141 | /** |
142 | * Grabs a subset of a loop |
143 | * |
144 | * @param \Twig\Environment $env A Twig\Environment instance |
145 | * @param mixed $item A variable |
146 | * @param integer $start Start of the subset |
147 | * @param integer $end End of the subset |
148 | * @param boolean $preserveKeys Whether to preserve key or not (when the input is an array) |
149 | * |
150 | * @return mixed The sliced variable |
151 | */ |
152 | public function loop_subset(\Twig\Environment $env, $item, $start, $end = null, $preserveKeys = false) |
153 | { |
154 | // We do almost the same thing as Twig's slice (array_slice), except when $end is positive |
155 | if ($end >= 1) |
156 | { |
157 | // When end is > 1, subset will end on the last item in an array with the specified $end |
158 | // This is different from slice in that it is the number we end on rather than the number |
159 | // of items to grab (length) |
160 | |
161 | // Start must always be the actual starting number for this calculation (not negative) |
162 | $start = ($start < 0) ? count($item) + $start : $start; |
163 | $end = $end - $start; |
164 | } |
165 | |
166 | // We always include the last element (this was the past design) |
167 | $end = ($end == -1 || $end === null) ? null : $end + 1; |
168 | |
169 | return CoreExtension::slice($env->getCharset(), $item, $start, $end, $preserveKeys); |
170 | } |
171 | |
172 | /** |
173 | * Get output for a language variable (L_FOO, LA_FOO) |
174 | * |
175 | * This function checks to see if the language var was outputted to $context |
176 | * (e.g. in the ACP, L_TITLE) |
177 | * If not, we return the result of $user->lang() |
178 | * |
179 | * @return string |
180 | */ |
181 | public function lang() |
182 | { |
183 | $args = func_get_args(); |
184 | $key = $args[0]; |
185 | |
186 | $context_vars = $this->context->get_root_ref(); |
187 | |
188 | if (is_string($key) && isset($context_vars['L_' . $key])) |
189 | { |
190 | return $context_vars['L_' . $key]; |
191 | } |
192 | |
193 | // LA_ is transformed into lang(\'$1\')|escape('js'), so we should not |
194 | // need to check for it |
195 | |
196 | return call_user_func_array(array($this->language, 'lang'), $args); |
197 | } |
198 | |
199 | /** |
200 | * Check if a language variable exists |
201 | * |
202 | * @return bool |
203 | */ |
204 | public function lang_defined($key) |
205 | { |
206 | return call_user_func_array([$this->language, 'is_set'], [$key]); |
207 | } |
208 | |
209 | /** |
210 | * Get output for language variable in JS code |
211 | * |
212 | * @throws RuntimeError When data passed to twig_escape_filter is not a UTF8 string |
213 | */ |
214 | public function lang_js(): string |
215 | { |
216 | $args = func_get_args(); |
217 | |
218 | return $this->environment->getRuntime(EscaperRuntime::class)->escape(call_user_func_array([$this, 'lang'], $args), 'js'); |
219 | } |
220 | |
221 | /** |
222 | * Get raw value associated with lang key |
223 | * |
224 | * @param string $key |
225 | * |
226 | * @return array|string Raw value associated with lang key |
227 | */ |
228 | public function lang_raw(string $key): array|string |
229 | { |
230 | return call_user_func_array(array($this->language, 'lang_raw'), [$key]); |
231 | } |
232 | } |