1 | <?php |
||
2 | |||
3 | /* |
||
4 | * |
||
5 | * (c) Yaroslav Honcharuk <[email protected]> |
||
6 | * |
||
7 | * For the full copyright and license information, please view the LICENSE |
||
8 | * file that was distributed with this source code. |
||
9 | */ |
||
10 | |||
11 | namespace Yarhon\RouteGuardBundle\Twig\TokenParser; |
||
12 | |||
13 | use Twig\Token; |
||
14 | use Twig\Parser; |
||
15 | use Twig\TokenStream; |
||
16 | use Twig\Node\Node; |
||
17 | use Twig_Error_Syntax as SyntaxError; // Workaround for PhpStorm to recognise type hints. Namespaced name: Twig\Error\SyntaxError |
||
18 | use Yarhon\RouteGuardBundle\Twig\Node\RouteExpression; |
||
19 | |||
20 | /** |
||
21 | * @author Yaroslav Honcharuk <[email protected]> |
||
22 | */ |
||
23 | class RouteExpressionParser |
||
24 | { |
||
25 | /** |
||
26 | * @var Parser; |
||
27 | */ |
||
28 | private $parser; |
||
29 | |||
30 | /** |
||
31 | * @param Parser $parser |
||
32 | */ |
||
33 | 39 | public function setParser(Parser $parser) |
|
34 | { |
||
35 | 39 | $this->parser = $parser; |
|
36 | 39 | } |
|
37 | |||
38 | /** |
||
39 | * @param Token $token |
||
40 | * |
||
41 | * @return RouteExpression |
||
42 | * |
||
43 | * @throws SyntaxError |
||
44 | */ |
||
45 | 34 | public function parse(Token $token) |
|
46 | { |
||
47 | 34 | $routeContextArguments = $this->parseRouteContextArguments(); |
|
48 | 34 | $expression = new RouteExpression($routeContextArguments, $token->getLine()); |
|
49 | |||
50 | 33 | if ($generateAs = $this->parseGenerateAs()) { |
|
51 | 23 | $expression->setGenerateAs(...$generateAs); |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
52 | } |
||
53 | |||
54 | 31 | return $expression; |
|
55 | } |
||
56 | |||
57 | 34 | private function parseRouteContextArguments() |
|
58 | { |
||
59 | 34 | $stream = $this->parser->getStream(); |
|
60 | 34 | $line = $stream->getCurrent()->getLine(); |
|
61 | |||
62 | 34 | $arguments = []; |
|
63 | 34 | while (!$stream->test(Token::BLOCK_END_TYPE) && !$stream->test('as')) { |
|
64 | 33 | if (count($arguments)) { |
|
65 | 20 | $stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); |
|
66 | } |
||
67 | |||
68 | 33 | $arguments[] = $this->parser->getExpressionParser()->parseExpression(); |
|
69 | } |
||
70 | |||
71 | 34 | return new Node($arguments, [], $line); |
|
72 | } |
||
73 | |||
74 | 33 | private function parseGenerateAs() |
|
75 | { |
||
76 | 33 | $stream = $this->parser->getStream(); |
|
77 | |||
78 | 33 | $generateAs = []; |
|
79 | |||
80 | 33 | if ($stream->nextIf('as')) { |
|
81 | // $functionName = $stream->expect(Token::NAME_TYPE, ['url', 'path'])->getValue(); |
||
82 | // Workaround for bug in Twig_TokenStream::expect() method. See self::streamExpect(). |
||
83 | 25 | $message = '"name" expected with value "url" or "path"'; |
|
84 | 25 | $referenceType = $this->streamExpect($stream, Token::NAME_TYPE, ['url', 'path'], $message)->getValue(); |
|
85 | 23 | $generateAs[] = $referenceType; |
|
86 | |||
87 | 23 | if ($stream->test(['absolute', 'relative'])) { |
|
88 | 2 | $relative = 'absolute' !== $stream->getCurrent()->getValue(); |
|
89 | 2 | $generateAs[] = $relative; |
|
90 | 2 | $stream->next(); |
|
91 | } |
||
92 | } |
||
93 | |||
94 | 31 | return $generateAs; |
|
95 | } |
||
96 | |||
97 | /** |
||
98 | * Workaround for bug inside \Twig_TokenStream::expect. |
||
99 | * In case of invalid template syntax, when exception is thrown, if type and/or value argument is an array, |
||
100 | * an "Array to string conversion" error happens: |
||
101 | * - for type because of: Twig_Token::typeToEnglish($type) |
||
102 | * - for value because of: sprintf(' with value "%s"', $value). |
||
103 | * |
||
104 | * @param TokenStream $stream |
||
105 | * @param array|int $type |
||
106 | * @param array|string|null $values |
||
107 | * @param string|null $message |
||
108 | * |
||
109 | * @return Token |
||
110 | * |
||
111 | * @throws SyntaxError |
||
112 | */ |
||
113 | 25 | private function streamExpect(TokenStream $stream, $type, $values = null, $message = null) |
|
114 | { |
||
115 | 25 | $token = $stream->getCurrent(); |
|
116 | 25 | if (!$token->test($type, $values)) { |
|
117 | 2 | if ($message) { |
|
118 | 2 | $message = ' ('.$message.')'; |
|
119 | } |
||
120 | |||
121 | 2 | throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s"%s.', |
|
122 | 2 | Token::typeToEnglish($token->getType()), $token->getValue(), $message), |
|
123 | 2 | $token->getLine(), |
|
124 | 2 | $stream->getSourceContext() |
|
125 | ); |
||
126 | } |
||
127 | 23 | $stream->next(); |
|
128 | |||
129 | 23 | return $token; |
|
130 | } |
||
131 | } |
||
132 |