Complex classes like Validator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Validator, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class Validator { |
||
32 | /** |
||
33 | * Verify template |
||
34 | * |
||
35 | * @param array<string,array|string|integer> $context Current context |
||
36 | * @param string $template handlebars template |
||
37 | */ |
||
38 | 758 | public static function verify(&$context, $template) { |
|
39 | 758 | $template = SafeString::stripExtendedComments($template); |
|
40 | 758 | $context['level'] = 0; |
|
41 | 758 | Parser::setDelimiter($context); |
|
42 | |||
43 | 758 | while (preg_match($context['tokens']['search'], $template, $matches)) { |
|
44 | // Skip a token when it is slash escaped |
||
45 | 747 | if ($context['flags']['slash'] && ($matches[Token::POS_LSPACE] === '') && preg_match('/^(.*?)(\\\\+)$/s', $matches[Token::POS_LOTHER], $escmatch)) { |
|
46 | 4 | if (strlen($escmatch[2]) % 4) { |
|
47 | 2 | static::pushToken($context, substr($matches[Token::POS_LOTHER], 0, -2) . $context['tokens']['startchar']); |
|
48 | 2 | $matches[Token::POS_BEGINTAG] = substr($matches[Token::POS_BEGINTAG], 1); |
|
49 | 2 | $template = implode('', array_slice($matches, Token::POS_BEGINTAG)); |
|
50 | 2 | continue; |
|
51 | } else { |
||
52 | 2 | $matches[Token::POS_LOTHER] = $escmatch[1] . str_repeat('\\', strlen($escmatch[2]) / 2); |
|
53 | } |
||
54 | } |
||
55 | 745 | $context['tokens']['count']++; |
|
56 | 745 | $V = static::token($matches, $context); |
|
57 | 745 | static::pushLeft($context); |
|
58 | 745 | if ($V) { |
|
59 | 706 | if (is_array($V)) { |
|
60 | 699 | array_push($V, $matches, $context['tokens']['partialind']); |
|
61 | } |
||
62 | 706 | static::pushToken($context, $V); |
|
63 | } |
||
64 | 745 | $template = "{$matches[Token::POS_RSPACE]}{$matches[Token::POS_ROTHER]}"; |
|
65 | } |
||
66 | 758 | static::pushToken($context, $template); |
|
67 | |||
68 | 758 | if ($context['level'] > 0) { |
|
69 | 8 | array_pop($context['stack']); |
|
70 | 8 | array_pop($context['stack']); |
|
71 | 8 | $token = array_pop($context['stack']); |
|
72 | 8 | $context['error'][] = 'Unclosed token ' . ($context['rawblock'] ? "{{{{{$token}}}}}" : ( $context['partialblock'] ? "{{#>{$token}}}" : "{{#{$token}}}")) . ' !!'; |
|
73 | } |
||
74 | 758 | } |
|
75 | |||
76 | /** |
||
77 | * push left string of current token and clear it |
||
78 | * |
||
79 | * @param array<string,array|string|integer> $context Current context |
||
80 | */ |
||
81 | 745 | protected static function pushLeft(&$context) { |
|
82 | 745 | $L = $context['currentToken'][Token::POS_LOTHER] . $context['currentToken'][Token::POS_LSPACE]; |
|
83 | |||
84 | 745 | if ($context['currentToken'][Token::POS_OP] === '!') { |
|
85 | $appender = function (&$pb) use ($context, $L) { |
||
86 | 1 | $pb .= $L; |
|
87 | 27 | }; |
|
88 | 27 | if (count($context['partialblock']) > 0) { |
|
89 | 1 | array_walk($context['partialblock'], $appender); |
|
90 | } |
||
91 | 27 | if (count($context['inlinepartial']) > 0) { |
|
92 | array_walk($context['inlinepartial'], $appender); |
||
93 | } |
||
94 | } |
||
95 | |||
96 | 745 | static::pushToken($context, $L); |
|
97 | 745 | $context['currentToken'][Token::POS_LOTHER] = $context['currentToken'][Token::POS_LSPACE] = ''; |
|
98 | 745 | } |
|
99 | |||
100 | /** |
||
101 | * push a token into the stack when it is not empty string |
||
102 | * |
||
103 | * @param array<string,array|string|integer> $context Current context |
||
104 | * @param string|array $token a parsed token or a string |
||
105 | */ |
||
106 | 758 | protected static function pushToken(&$context, $token) { |
|
118 | |||
119 | /** |
||
120 | * push current token into the section stack |
||
121 | * |
||
122 | * @param array<string,array|string|integer> $context Current context |
||
123 | * @param string $operation operation string |
||
124 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
125 | */ |
||
126 | 374 | protected static function pushStack(&$context, $operation, $vars) { |
|
133 | |||
134 | /** |
||
135 | * Verify delimiters and operators |
||
136 | * |
||
137 | * @param string[] $token detected handlebars {{ }} token |
||
138 | * @param array<string,array|string|integer> $context current compile context |
||
139 | * |
||
140 | * @return boolean|null Return true when invalid |
||
141 | * |
||
142 | * @expect null when input array_fill(0, 11, ''), array() |
||
143 | * @expect null when input array(0, 0, 0, 0, 0, '{{', '#', '...', '}}'), array() |
||
144 | * @expect true when input array(0, 0, 0, 0, 0, '{', '#', '...', '}'), array() |
||
145 | */ |
||
146 | 746 | protected static function delimiter($token, &$context) { |
|
158 | |||
159 | /** |
||
160 | * Verify operators |
||
161 | * |
||
162 | * @param string $operator the operator string |
||
163 | * @param array<string,array|string|integer> $context current compile context |
||
164 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
165 | * |
||
166 | * @return boolean|integer|null Return true when invalid or detected |
||
167 | * |
||
168 | * @expect null when input '', array(), array() |
||
169 | * @expect 2 when input '^', array('usedFeature' => array('isec' => 1), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'elselvl' => array(), 'flags' => array('spvar' => 0), 'elsechain' => false, 'helperresolver' => 0), array(array('foo')) |
||
170 | * @expect true when input '/', array('stack' => array('[with]', '#'), 'level' => 1, 'currentToken' => array(0,0,0,0,0,0,0,'with'), 'flags' => array('nohbh' => 0)), array(array()) |
||
171 | * @expect 4 when input '#', array('usedFeature' => array('sec' => 3), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0), 'elsechain' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('x')) |
||
172 | * @expect 5 when input '#', array('usedFeature' => array('if' => 4), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0), 'elsechain' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('if')) |
||
173 | * @expect 6 when input '#', array('usedFeature' => array('with' => 5), 'level' => 0, 'flags' => array('nohbh' => 0, 'runpart' => 0, 'spvar' => 0), 'currentToken' => array(0,0,0,0,0,0,0,0), 'elsechain' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('with')) |
||
174 | * @expect 7 when input '#', array('usedFeature' => array('each' => 6), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0), 'elsechain' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('each')) |
||
175 | * @expect 8 when input '#', array('usedFeature' => array('unless' => 7), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0, 'nohbh' => 0), 'elsechain' => false, 'elselvl' => array(), 'helperresolver' => 0), array(array('unless')) |
||
176 | * @expect 9 when input '#', array('helpers' => array('abc' => ''), 'usedFeature' => array('helper' => 8), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0), 'elsechain' => false, 'elselvl' => array()), array(array('abc')) |
||
177 | * @expect 11 when input '#', array('helpers' => array('abc' => ''), 'usedFeature' => array('helper' => 10), 'level' => 0, 'currentToken' => array(0,0,0,0,0,0,0,0), 'flags' => array('spvar' => 0), 'elsechain' => false, 'elselvl' => array()), array(array('abc')) |
||
178 | * @expect true when input '>', array('partialresolver' => false, 'usedFeature' => array('partial' => 7), 'level' => 0, 'flags' => array('skippartial' => 0, 'runpart' => 0, 'spvar' => 0), 'currentToken' => array(0,0,0,0,0,0,0,0), 'elsechain' => false, 'elselvl' => array()), array('test') |
||
179 | */ |
||
180 | 707 | protected static function operator($operator, &$context, &$vars) { |
|
181 | switch ($operator) { |
||
182 | 707 | case '#*': |
|
183 | 14 | if (!$context['compile']) { |
|
184 | 14 | static::pushLeft($context); |
|
185 | 14 | $context['stack'][] = count($context['parsed'][0]); |
|
186 | 14 | static::pushStack($context, '#*', $vars); |
|
187 | 14 | array_unshift($context['inlinepartial'], ''); |
|
188 | } |
||
189 | 14 | return static::inline($context, $vars); |
|
190 | |||
191 | 704 | case '#>': |
|
192 | 22 | if (!$context['compile']) { |
|
193 | 22 | static::pushLeft($context); |
|
194 | 22 | $context['stack'][] = count($context['parsed'][0]); |
|
195 | 22 | $vars[Parser::PARTIALBLOCK] = ++$context['usedFeature']['pblock']; |
|
196 | 22 | static::pushStack($context, '#>', $vars); |
|
|
|||
197 | 22 | array_unshift($context['partialblock'], ''); |
|
198 | } |
||
199 | 22 | return static::partial($context, $vars); |
|
200 | |||
201 | 700 | case '>': |
|
202 | 99 | return static::partial($context, $vars); |
|
203 | |||
204 | 661 | case '^': |
|
205 | 64 | if (!isset($vars[0][0])) { |
|
206 | 24 | if (!$context['flags']['else']) { |
|
207 | 1 | $context['error'][] = 'Do not support {{^}}, you should do compile with LightnCandy::FLAG_ELSE flag'; |
|
208 | 1 | return; |
|
209 | } else { |
||
210 | 23 | return static::doElse($context, $vars); |
|
211 | } |
||
212 | } |
||
213 | |||
214 | 40 | static::doElseChain($context); |
|
215 | |||
216 | 40 | if (static::isBlockHelper($context, $vars)) { |
|
217 | 1 | static::pushStack($context, '#', $vars); |
|
218 | 1 | return static::blockCustomHelper($context, $vars, true); |
|
219 | } |
||
220 | |||
221 | 39 | static::pushStack($context, '^', $vars); |
|
222 | 39 | return static::invertedSection($context, $vars); |
|
223 | |||
224 | 661 | case '/': |
|
225 | 347 | $r = static::blockEnd($context, $vars); |
|
226 | 347 | if ($r !== Token::POS_BACKFILL) { |
|
227 | 347 | array_pop($context['stack']); |
|
228 | 347 | array_pop($context['stack']); |
|
229 | 347 | array_pop($context['stack']); |
|
230 | } |
||
231 | 347 | return $r; |
|
232 | |||
233 | 636 | case '#': |
|
234 | 323 | static::doElseChain($context); |
|
235 | 323 | static::pushStack($context, '#', $vars); |
|
236 | |||
237 | 323 | if (static::isBlockHelper($context, $vars)) { |
|
238 | 63 | return static::blockCustomHelper($context, $vars); |
|
239 | } |
||
240 | |||
241 | 269 | return static::blockBegin($context, $vars); |
|
242 | } |
||
243 | 536 | } |
|
244 | |||
245 | /** |
||
246 | * validate inline partial begin token |
||
247 | * |
||
248 | * @param array<string,array|string|integer> $context current compile context |
||
249 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
250 | * |
||
251 | * @return boolean|null Return true when inline partial ends |
||
252 | */ |
||
253 | 706 | protected static function inlinePartial(&$context, $vars) { |
|
254 | 706 | if (count($context['inlinepartial']) > 0) { |
|
255 | 14 | $ended = false; |
|
256 | 14 | $append = $context['currentToken'][Token::POS_LOTHER] . $context['currentToken'][Token::POS_LSPACE]; |
|
257 | array_walk($context['inlinepartial'], function (&$pb) use ($context, $append) { |
||
258 | 14 | $pb .= $append; |
|
259 | 14 | }); |
|
260 | 14 | if ($context['currentToken'][Token::POS_OP] === '/') { |
|
261 | 14 | if (static::blockEnd($context, $vars, '#*') !== null) { |
|
262 | 14 | $context['usedFeature']['inlpartial']++; |
|
263 | 14 | $tmpl = array_shift($context['inlinepartial']); |
|
264 | 14 | $c = $context['stack'][count($context['stack']) - 4]; |
|
265 | 14 | $context['parsed'][0] = array_slice($context['parsed'][0], 0, $c + 1); |
|
266 | 14 | $P = &$context['parsed'][0][$c]; |
|
267 | 14 | if (isset($P[1][1][0])) { |
|
268 | 13 | $context['usedPartial'][$P[1][1][0]] = $tmpl; |
|
269 | 13 | $P[1][0][0] = Partial::compileDynamic($context, $P[1][1][0]); |
|
270 | } |
||
271 | 14 | $ended = true; |
|
272 | } |
||
273 | } |
||
274 | 14 | $append = Token::toString($context['currentToken']); |
|
275 | array_walk($context['inlinepartial'], function (&$pb) use ($context, $append) { |
||
276 | 3 | $pb .= $append; |
|
277 | 14 | }); |
|
278 | 14 | return $ended; |
|
279 | } |
||
280 | 706 | } |
|
281 | |||
282 | /** |
||
283 | * validate partial block token |
||
284 | * |
||
285 | * @param array<string,array|string|integer> $context current compile context |
||
286 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
287 | * |
||
288 | * @return boolean|null Return true when partial block ends |
||
289 | */ |
||
290 | 706 | protected static function partialBlock(&$context, $vars) { |
|
291 | 706 | if (count($context['partialblock']) > 0) { |
|
292 | 21 | $ended = false; |
|
293 | 21 | $append = $context['currentToken'][Token::POS_LOTHER] . $context['currentToken'][Token::POS_LSPACE]; |
|
294 | array_walk($context['partialblock'], function (&$pb) use ($context, $append) { |
||
295 | 21 | $pb .= $append; |
|
296 | 21 | }); |
|
297 | 21 | if ($context['currentToken'][Token::POS_OP] === '/') { |
|
298 | 21 | if (static::blockEnd($context, $vars, '#>') !== null) { |
|
299 | 21 | $c = $context['stack'][count($context['stack']) - 4]; |
|
300 | 21 | $found = Partial::resolve($context, $vars[0][0]) !== null; |
|
301 | 21 | $v = $found ? "@partial-block{$context['parsed'][0][$c][1][Parser::PARTIALBLOCK]}" : "{$vars[0][0]}"; |
|
302 | 21 | if ($found) { |
|
303 | 17 | $context['partials'][$v] = $context['partialblock'][0]; |
|
304 | } |
||
305 | 21 | $context['usedPartial'][$v] = $context['partialblock'][0]; |
|
306 | 21 | Partial::compileDynamic($context, $v); |
|
307 | 21 | if ($found) { |
|
308 | 17 | Partial::read($context, $vars[0][0]); |
|
309 | } |
||
310 | 21 | array_shift($context['partialblock']); |
|
311 | 21 | $context['parsed'][0] = array_slice($context['parsed'][0], 0, $c + 1); |
|
312 | 21 | $ended = true; |
|
313 | } |
||
314 | } |
||
315 | 21 | $append = Token::toString($context['currentToken']); |
|
316 | 21 | array_walk($context['partialblock'], function (&$pb) use ($context, $append) { |
|
317 | 15 | $pb .= $append; |
|
318 | 21 | }); |
|
319 | 21 | return $ended; |
|
320 | } |
||
321 | 706 | } |
|
322 | |||
323 | /** |
||
324 | * handle else chain |
||
325 | * |
||
326 | * @param array<string,array|string|integer> $context current compile context |
||
327 | */ |
||
328 | 352 | protected static function doElseChain(&$context) { |
|
329 | 352 | if ($context['elsechain']) { |
|
330 | 12 | $context['elsechain'] = false; |
|
331 | } else { |
||
332 | 352 | array_unshift($context['elselvl'], array()); |
|
333 | } |
||
334 | 352 | } |
|
335 | |||
336 | /** |
||
337 | * validate block begin token |
||
338 | * |
||
339 | * @param array<string,array|string|integer> $context current compile context |
||
340 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
341 | * |
||
342 | * @return boolean Return true always |
||
343 | */ |
||
344 | 268 | protected static function blockBegin(&$context, $vars) { |
|
345 | 268 | switch ((isset($vars[0][0]) && is_string($vars[0][0])) ? $vars[0][0] : null) { |
|
346 | 268 | case 'with': |
|
347 | 34 | return static::with($context, $vars); |
|
348 | 241 | case 'each': |
|
349 | 56 | return static::section($context, $vars, true); |
|
350 | 196 | case 'unless': |
|
351 | 7 | return static::unless($context, $vars); |
|
352 | 190 | case 'if': |
|
353 | 77 | return static::doIf($context, $vars); |
|
354 | default: |
||
355 | 120 | return static::section($context, $vars); |
|
356 | } |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * validate builtin helpers |
||
361 | * |
||
362 | * @param array<string,array|string|integer> $context current compile context |
||
363 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
364 | */ |
||
365 | 157 | protected static function builtin(&$context, $vars) { |
|
377 | |||
378 | /** |
||
379 | * validate section token |
||
380 | * |
||
381 | * @param array<string,array|string|integer> $context current compile context |
||
382 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
383 | * @param boolean $isEach the section is #each |
||
384 | * |
||
385 | * @return boolean Return true always |
||
386 | */ |
||
387 | 176 | protected static function section(&$context, $vars, $isEach = false) { |
|
398 | |||
399 | /** |
||
400 | * validate with token |
||
401 | * |
||
402 | * @param array<string,array|string|integer> $context current compile context |
||
403 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
404 | * |
||
405 | * @return boolean Return true always |
||
406 | */ |
||
407 | 34 | protected static function with(&$context, $vars) { |
|
411 | |||
412 | /** |
||
413 | * validate unless token |
||
414 | * |
||
415 | * @param array<string,array|string|integer> $context current compile context |
||
416 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
417 | * |
||
418 | * @return boolean Return true always |
||
419 | */ |
||
420 | 7 | protected static function unless(&$context, $vars) { |
|
424 | |||
425 | /** |
||
426 | * validate if token |
||
427 | * |
||
428 | * @param array<string,array|string|integer> $context current compile context |
||
429 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
430 | * |
||
431 | * @return boolean Return true always |
||
432 | */ |
||
433 | 77 | protected static function doIf(&$context, $vars) { |
|
437 | |||
438 | /** |
||
439 | * validate block custom helper token |
||
440 | * |
||
441 | * @param array<string,array|string|integer> $context current compile context |
||
442 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
443 | * @param boolean $inverted the logic will be inverted |
||
444 | * |
||
445 | * @return integer|null Return number of used custom helpers |
||
446 | */ |
||
447 | 63 | protected static function blockCustomHelper(&$context, $vars, $inverted = false) { |
|
448 | 63 | if (is_string($vars[0][0])) { |
|
449 | 63 | if (static::resolveHelper($context, $vars)) { |
|
450 | 63 | return ++$context['usedFeature']['helper']; |
|
451 | } |
||
452 | } |
||
453 | } |
||
454 | |||
455 | /** |
||
456 | * validate inverted section |
||
457 | * |
||
458 | * @param array<string,array|string|integer> $context current compile context |
||
459 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
460 | * |
||
461 | * @return integer Return number of inverted sections |
||
462 | */ |
||
463 | 38 | protected static function invertedSection(&$context, $vars) { |
|
466 | |||
467 | /** |
||
468 | * Return compiled PHP code for a handlebars block end token |
||
469 | * |
||
470 | * @param array<string,array|string|integer> $context current compile context |
||
471 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
472 | * @param string|null $match should also match to this operator |
||
473 | * |
||
474 | * @return boolean Return true |
||
475 | */ |
||
476 | 367 | protected static function blockEnd(&$context, &$vars, $match = null) { |
|
477 | 367 | $context['level']--; |
|
478 | 367 | $c = count($context['stack']) - 2; |
|
479 | 367 | $pop = ($c >= 0) ? $context['stack'][$c + 1] : ''; |
|
480 | 367 | if (($match !== null) && ($match !== $pop)) { |
|
481 | 6 | return; |
|
482 | } |
||
483 | 367 | $pop2 = ($c >= 0) ? $context['stack'][$c]: ''; |
|
484 | 367 | switch ($context['currentToken'][Token::POS_INNERTAG]) { |
|
485 | 367 | case 'with': |
|
486 | 38 | if (!$context['flags']['nohbh']) { |
|
487 | 36 | if ($pop2 !== '[with]') { |
|
488 | 1 | $context['error'][] = 'Unexpect token: {{/with}} !'; |
|
489 | 1 | return; |
|
490 | } |
||
491 | } |
||
492 | 37 | return true; |
|
493 | } |
||
494 | |||
495 | switch($pop) { |
||
496 | 347 | case '#': |
|
497 | 70 | case '^': |
|
498 | 318 | $elsechain = array_shift($context['elselvl']); |
|
499 | 318 | if (isset($elsechain[0])) { |
|
500 | 12 | $context['currentToken'][Token::POS_RSPACE] = $context['currentToken'][Token::POS_BACKFILL] = '{{/' . implode('}}{{/', $elsechain) . '}}' . Token::toString($context['currentToken']) . $context['currentToken'][Token::POS_RSPACE]; |
|
501 | 12 | return Token::POS_BACKFILL; |
|
502 | } |
||
503 | 32 | case '#>': |
|
504 | 15 | case '#*': |
|
505 | 346 | list($levels, $spvar, $var) = Expression::analyze($context, $vars[0]); |
|
506 | 346 | $v = Expression::toString($levels, $spvar, $var); |
|
507 | 346 | if ($pop2 !== $v) { |
|
508 | 2 | $context['error'][] = 'Unexpect token ' . Token::toString($context['currentToken']) . " ! Previous token {{{$pop}$pop2}} is not closed"; |
|
509 | 2 | return; |
|
510 | } |
||
511 | 345 | return true; |
|
512 | default: |
||
513 | 1 | $context['error'][] = 'Unexpect token: ' . Token::toString($context['currentToken']) . ' !'; |
|
514 | 1 | return; |
|
515 | } |
||
516 | } |
||
517 | |||
518 | /** |
||
519 | * handle delimiter change |
||
520 | * |
||
521 | * @param array<string,array|string|integer> $context current compile context |
||
522 | * |
||
523 | * @return boolean|null Return true when delimiter changed |
||
524 | */ |
||
525 | 735 | protected static function isDelimiter(&$context) { |
|
532 | |||
533 | /** |
||
534 | * handle raw block |
||
535 | * |
||
536 | * @param string[] $token detected handlebars {{ }} token |
||
537 | * @param array<string,array|string|integer> $context current compile context |
||
538 | * |
||
539 | * @return boolean|null Return true when in rawblock mode |
||
540 | */ |
||
541 | 745 | protected static function rawblock(&$token, &$context) { |
|
571 | |||
572 | /** |
||
573 | * handle comment |
||
574 | * |
||
575 | * @param string[] $token detected handlebars {{ }} token |
||
576 | * @param array<string,array|string|integer> $context current compile context |
||
577 | * |
||
578 | * @return boolean|null Return true when is comment |
||
579 | */ |
||
580 | 726 | protected static function comment(&$token, &$context) { |
|
586 | |||
587 | /** |
||
588 | * Collect handlebars usage information, detect template error. |
||
589 | * |
||
590 | * @param string[] $token detected handlebars {{ }} token |
||
591 | * @param array<string,array|string|integer> $context current compile context |
||
592 | */ |
||
593 | 745 | protected static function token(&$token, &$context) { |
|
594 | 745 | $context['currentToken'] = &$token; |
|
595 | |||
596 | 745 | if (static::rawblock($token, $context)) { |
|
597 | 4 | return Token::toString($token); |
|
598 | } |
||
599 | |||
600 | 745 | if (static::delimiter($token, $context)) { |
|
601 | 10 | return; |
|
602 | } |
||
603 | |||
604 | 735 | if (static::isDelimiter($context)) { |
|
605 | 15 | static::spacing($token, $context); |
|
606 | 15 | return; |
|
607 | } |
||
608 | |||
609 | 726 | if (static::comment($token, $context)) { |
|
610 | 26 | static::spacing($token, $context); |
|
611 | 26 | return; |
|
612 | } |
||
613 | |||
614 | 706 | list($raw, $vars) = Parser::parse($token, $context); |
|
615 | |||
616 | 706 | $partials = static::partialBlock($context, $vars); |
|
617 | 706 | $partials = static::inlinePartial($context, $vars) || $partials; |
|
618 | |||
619 | 706 | if ($partials) { |
|
620 | 31 | $context['stack'] = array_slice($context['stack'], 0, -4); |
|
621 | 31 | $context['currentToken'][Token::POS_LOTHER] = ''; |
|
622 | 31 | $context['currentToken'][Token::POS_LSPACE] = ''; |
|
623 | 31 | return; |
|
624 | } |
||
625 | |||
626 | // Handle spacing (standalone tags, partial indent) |
||
627 | 706 | static::spacing($token, $context, (($token[Token::POS_OP] === '') || ($token[Token::POS_OP] === '&')) && (!$context['flags']['else'] || !isset($vars[0][0]) || ($vars[0][0] !== 'else')) || ($context['flags']['nostd'] > 0)); |
|
628 | |||
629 | 706 | if (static::operator($token[Token::POS_OP], $context, $vars)) { |
|
630 | 426 | return isset($token[Token::POS_BACKFILL]) ? null : array($raw, $vars); |
|
631 | } |
||
632 | |||
633 | 539 | if (count($vars) == 0) { |
|
634 | 6 | return $context['error'][] = 'Wrong variable naming in ' . Token::toString($token); |
|
635 | } |
||
636 | |||
637 | 533 | if (!isset($vars[0])) { |
|
638 | 1 | return $context['error'][] = 'Do not support name=value in ' . Token::toString($token) . ', you should use it after a custom helper.'; |
|
639 | } |
||
640 | |||
641 | 532 | $context['usedFeature'][$raw ? 'raw' : 'enc']++; |
|
642 | |||
643 | 532 | foreach ($vars as $var) { |
|
644 | 532 | if (!isset($var[0]) || ($var[0] === 0)) { |
|
645 | 73 | if ($context['level'] == 0) { |
|
646 | 25 | $context['usedFeature']['rootthis']++; |
|
647 | } |
||
648 | 532 | $context['usedFeature']['this']++; |
|
649 | } |
||
650 | } |
||
651 | |||
652 | 532 | if (!isset($vars[0][0])) { |
|
653 | 54 | return array($raw, $vars); |
|
654 | } |
||
655 | |||
656 | 498 | if (($vars[0][0] === 'else') && $context['flags']['else']) { |
|
657 | 36 | static::doElse($context, $vars); |
|
658 | 36 | return array($raw, $vars); |
|
659 | } |
||
660 | |||
661 | 474 | if (!static::helper($context, $vars)) { |
|
662 | 359 | static::lookup($context, $vars); |
|
663 | 359 | static::log($context, $vars); |
|
664 | } |
||
665 | |||
666 | 474 | return array($raw, $vars); |
|
667 | } |
||
668 | |||
669 | /** |
||
670 | * Return 1 or larger number when else token detected |
||
671 | * |
||
672 | * @param array<string,array|string|integer> $context current compile context |
||
673 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
674 | * |
||
675 | * @return integer Return 1 or larger number when else token detected |
||
676 | */ |
||
677 | 58 | protected static function doElse(&$context, $vars) { |
|
678 | 58 | if ($context['level'] == 0) { |
|
679 | 1 | $context['error'][] = '{{else}} only valid in if, unless, each, and #section context'; |
|
680 | } |
||
681 | |||
682 | 58 | if (isset($vars[1][0])) { |
|
683 | 12 | $token = $context['currentToken']; |
|
684 | 12 | $context['currentToken'][Token::POS_RSPACE] = "{{#{$vars[1][0]} " . preg_replace('/^\\s*else\\s+' . $vars[1][0] . '\\s*/', '', $token[Token::POS_INNERTAG]) . '}}' . $context['currentToken'][Token::POS_RSPACE]; |
|
685 | 12 | array_unshift($context['elselvl'][0], $vars[1][0]); |
|
686 | 12 | $context['elsechain'] = true; |
|
687 | } |
||
688 | |||
689 | 58 | return ++$context['usedFeature']['else']; |
|
690 | } |
||
691 | |||
692 | /** |
||
693 | * Return true when this is {{log ...}} |
||
694 | * |
||
695 | * @param array<string,array|string|integer> $context current compile context |
||
696 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
697 | * |
||
698 | * @return boolean|null Return true when it is custom helper |
||
699 | */ |
||
700 | 359 | public static function log(&$context, $vars) { |
|
701 | 359 | if (isset($vars[0][0]) && ($vars[0][0] === 'log')) { |
|
702 | 3 | if (!$context['flags']['nohbh']) { |
|
703 | 3 | if (count($vars) < 2) { |
|
704 | 1 | $context['error'][] = "No argument after {{log}} !"; |
|
705 | } |
||
706 | 3 | $context['usedFeature']['log']++; |
|
707 | 3 | return true; |
|
708 | } |
||
709 | } |
||
710 | 356 | } |
|
711 | |||
712 | /** |
||
713 | * Return true when this is {{lookup ...}} |
||
714 | * |
||
715 | * @param array<string,array|string|integer> $context current compile context |
||
716 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
717 | * |
||
718 | * @return boolean|null Return true when it is custom helper |
||
719 | */ |
||
720 | 359 | public static function lookup(&$context, $vars) { |
|
733 | |||
734 | /** |
||
735 | * Return true when the name is listed in helper table |
||
736 | * |
||
737 | * @param array<string,array|string|integer> $context current compile context |
||
738 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
739 | * @param boolean $checkSubexp true when check for subexpression |
||
740 | * |
||
741 | * @return boolean Return true when it is custom helper |
||
742 | */ |
||
743 | 482 | public static function helper(&$context, $vars, $checkSubexp = false) { |
|
744 | 482 | if (static::resolveHelper($context, $vars)) { |
|
745 | 130 | $context['usedFeature']['helper']++; |
|
762 | |||
763 | /** |
||
764 | * use helperresolver to resolve helper, return true when helper founded |
||
765 | * |
||
766 | * @param array<string,array|string|integer> $context Current context of compiler progress. |
||
767 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
768 | * |
||
769 | * @return boolean $found helper exists or not |
||
770 | */ |
||
771 | 644 | public static function resolveHelper(&$context, &$vars) { |
|
789 | |||
790 | /** |
||
791 | * detect for block custom helper |
||
792 | * |
||
793 | * @param array<string,array|string|integer> $context current compile context |
||
794 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
795 | * |
||
796 | * @return boolean|null Return true when this token is block custom helper |
||
797 | */ |
||
798 | 352 | protected static function isBlockHelper($context, $vars) { |
|
809 | |||
810 | /** |
||
811 | * validate inline partial |
||
812 | * |
||
813 | * @param array<string,array|string|integer> $context current compile context |
||
814 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
815 | * |
||
816 | * @return boolean Return true always |
||
817 | */ |
||
818 | 14 | protected static function inline(&$context, $vars) { |
|
830 | |||
831 | /** |
||
832 | * validate partial |
||
833 | * |
||
834 | * @param array<string,array|string|integer> $context current compile context |
||
835 | * @param array<boolean|integer|string|array> $vars parsed arguments list |
||
836 | * |
||
837 | * @return integer|boolean Return 1 or larger number for runtime partial, return true for other case |
||
838 | */ |
||
839 | 105 | protected static function partial(&$context, $vars) { |
|
861 | |||
862 | /** |
||
863 | * Modify $token when spacing rules matched. |
||
864 | * |
||
865 | * @param array<string> $token detected handlebars {{ }} token |
||
866 | * @param array<string,array|string|integer> $context current compile context |
||
867 | * @param boolean $nost do not do stand alone logic |
||
868 | * |
||
869 | * @return string|null Return compiled code segment for the token |
||
870 | */ |
||
871 | 735 | protected static function spacing(&$token, &$context, $nost = false) { |
|
922 | } |
||
923 | |||
924 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: