DiscoverRoutingFunctionNodeVisitor::doEnterNode()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
rs 10
c 0
b 0
f 0
ccs 5
cts 5
cp 1
cc 2
nc 2
nop 2
crap 2
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\NodeVisitor;
12
13
use Twig\Node\Node;
14
use Twig\Environment;
15
use Twig\NodeVisitor\AbstractNodeVisitor;
16
use Twig\NodeVisitor\NodeVisitorInterface;
17
use Twig\Node\Expression\FunctionExpression;
18
use Twig\Node\Expression\NameExpression;
19
use Twig\Error\SyntaxError;
20
use Yarhon\RouteGuardBundle\Twig\Node\RouteNode;
21
use Yarhon\RouteGuardBundle\Twig\Node\RouteExpression;
22
23
/**
24
 * Note: we extend from AbstractNodeVisitor just for compatibility with Twig 1.x NodeVisitorInterface.
25
 * When this compatibility would no longer be needed, we could drop usage of AbstractNodeVisitor
26
 * and implement NodeVisitorInterface directly.
27
 *
28
 * @author Yaroslav Honcharuk <[email protected]>
29
 */
30
class DiscoverRoutingFunctionNodeVisitor extends AbstractNodeVisitor
31
{
32
    /**
33
     * @var DiscoveredFunctions
34
     */
35
    private $discoveredFunctions;
36
37
    /**
38
     * @var string
39
     */
40
    private $tagName;
41
42
    /**
43
     * @var string
44
     */
45
    private $tagVariableName;
46
47
    /**
48
     * @var Scope
49
     */
50
    private $scope;
51
52
    /**
53
     * @param string $tagName
54
     * @param string $tagVariableName
55
     */
56 24
    public function __construct($tagName, $tagVariableName)
57
    {
58 24
        $this->tagName = $tagName;
59 24
        $this->tagVariableName = $tagVariableName;
60 24
        $this->discoveredFunctions = new DiscoveredFunctions();
61 24
        $this->scope = new Scope();
62 24
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67 23
    protected function doEnterNode(Node $node, Environment $env)
68
    {
69 23
        if ($this->isTargetNode($node)) {
70 5
            $this->scope = $this->scope->enter();
71 5
            $this->scope->set('insideTargetNode', true);
72
        }
73
74 23
        return $node;
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     *
80
     * @throws SyntaxError If zero / more than one routing function calls was found inside node
81
     */
82 23
    protected function doLeaveNode(Node $node, Environment $env)
83
    {
84 23
        if ($this->isTargetNode($node)) {
85
            /* @var RouteNode $node */
86
87 4
            if (!$this->scope->has('routingFunction')) {
88 1
                throw new SyntaxError(
89 1
                    sprintf('"%s" tag with discover option must contain one %s call.', $this->tagName, $this->createDiscoveredFunctionsString()),
90 1
                    $node->getTemplateLine()
91
                );
92
            }
93
94 3
            $condition = $this->createRouteExpression($this->scope->get('routingFunction'), $node->getTemplateLine());
0 ignored issues
show
Bug introduced by
It seems like $this->scope->get('routingFunction') can also be of type null; however, parameter $function of Yarhon\RouteGuardBundle\...createRouteExpression() does only seem to accept Twig\Node\Expression\FunctionExpression, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

94
            $condition = $this->createRouteExpression(/** @scrutinizer ignore-type */ $this->scope->get('routingFunction'), $node->getTemplateLine());
Loading history...
95 3
            $node->setNode('condition', $condition);
96
97 3
            $this->scope->set('insideTargetNode', false);
98 3
            $this->scope = $this->scope->leave();
99
100 3
            return $node;
101
        }
102
103 23
        if ($this->scope->get('insideTargetNode') && $this->isDiscoveredNode($node)) {
104 4
            if ($this->scope->has('routingFunction')) {
105 1
                throw new SyntaxError(
106 1
                    sprintf('"%s" tag with discover option must contain only one %s call.', $this->tagName, $this->createDiscoveredFunctionsString()),
107 1
                    $node->getTemplateLine()
108
                );
109
            }
110
111 4
            $this->scope->set('routingFunction', $node);
112
113 4
            $newNode = new NameExpression($this->tagVariableName, $node->getTemplateLine());
114 4
            $newNode->setAttribute('always_defined', true);
115
116 4
            return $newNode;
117
        }
118
119 23
        return $node;
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125 23
    public function getPriority()
126
    {
127 23
        return 0;
128
    }
129
130
    /**
131
     * @param Node $node
132
     *
133
     * @return bool
134
     */
135 23
    private function isTargetNode(Node $node)
136
    {
137 23
        return $node instanceof RouteNode && !$node->hasNode('condition');
138
    }
139
140
    /**
141
     * @param Node $node
142
     *
143
     * @return bool
144
     */
145 5
    private function isDiscoveredNode(Node $node)
146
    {
147 5
        return $node instanceof FunctionExpression && $this->discoveredFunctions->has($node->getAttribute('name'));
148
    }
149
150
    /**
151
     * @param FunctionExpression $function
152
     * @param int                $line
153
     *
154
     * @return RouteExpression
155
     *
156
     * @throws SyntaxError
157
     */
158 3
    private function createRouteExpression(FunctionExpression $function, $line)
159
    {
160 3
        $functionName = $function->getAttribute('name');
161 3
        $functionArguments = [];
162 3
        foreach ($function->getNode('arguments') as $argument) {
163 3
            $functionArguments[] = $argument;
164
        }
165
166 3
        list($arguments, $generateAs) = $this->discoveredFunctions->resolveArguments($functionName, $functionArguments);
167
168 3
        $expression = new RouteExpression(new Node($arguments), $line);
169 3
        $expression->setGenerateAs(...$generateAs);
0 ignored issues
show
Bug introduced by
$generateAs is expanded, but the parameter $referenceType of Yarhon\RouteGuardBundle\...ession::setGenerateAs() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
        $expression->setGenerateAs(/** @scrutinizer ignore-type */ ...$generateAs);
Loading history...
170
171 3
        return $expression;
172
    }
173
174
    /**
175
     * @return string
176
     */
177 2
    private function createDiscoveredFunctionsString()
178
    {
179 2
        $functions = $this->discoveredFunctions->getFunctions();
180
        $functions = array_map(function ($name) {
181 2
            return '"'.$name.'()"';
182 2
        }, $functions);
183
184 2
        return implode(' / ', $functions);
185
    }
186
}
187