Passed
Pull Request — master (#23)
by Christoffer
02:09
created

AcceptVisitorTrait   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 199
rs 10
c 0
b 0
f 0
wmc 15

5 Methods

Rating   Name   Duplication   Size   Complexity  
A addOneToPath() 0 3 1
D accept() 0 37 9
A visitNodes() 0 17 3
A visitNode() 0 9 1
A removeOneFromPath() 0 3 1
1
<?php
2
3
namespace Digia\GraphQL\Language\AST\Visitor;
4
5
use Digia\GraphQL\Language\AST\Node\NodeInterface;
6
use Digia\GraphQL\Util\SerializationInterface;
7
8
trait AcceptVisitorTrait
9
{
10
11
    /**
12
     * @var VisitorInterface
13
     */
14
    protected $visitor;
15
16
    /**
17
     * @var array
18
     */
19
    protected $path;
20
21
    /**
22
     * @var NodeInterface|null
23
     */
24
    protected $newNode;
25
26
    /**
27
     * @param VisitorInterface $visitor
28
     * @param string|null $key
29
     * @param array $path
30
     * @return NodeInterface|SerializationInterface|null
31
     */
32
    public function accept(VisitorInterface $visitor, ?string $key = null, array $path = []): ?NodeInterface
33
    {
34
        // TODO: Benchmark
35
        $this->newNode = clone $this;
0 ignored issues
show
Documentation Bug introduced by
It seems like clone $this of type Digia\GraphQL\Language\A...itor\AcceptVisitorTrait is incompatible with the declared type null|Digia\GraphQL\Language\AST\Node\NodeInterface of property $newNode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
36
37
        $this->visitor = $visitor;
38
        $this->path = $path;
39
40
        if (null === ($this->newNode = $visitor->enterNode($this->newNode, $key, $this->path))) {
0 ignored issues
show
Bug introduced by
$this->newNode of type Digia\GraphQL\Language\A...itor\AcceptVisitorTrait is incompatible with the type Digia\GraphQL\Language\AST\Node\NodeInterface expected by parameter $node of Digia\GraphQL\Language\A...rInterface::enterNode(). ( Ignorable by Annotation )

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

40
        if (null === ($this->newNode = $visitor->enterNode(/** @scrutinizer ignore-type */ $this->newNode, $key, $this->path))) {
Loading history...
41
            return null;
42
        }
43
44
        foreach (self::$kindToNodesToVisitMap[$this->kind] as $name) {
0 ignored issues
show
Bug Best Practice introduced by
The property kind does not exist on Digia\GraphQL\Language\A...itor\AcceptVisitorTrait. Did you maybe forget to declare it?
Loading history...
45
            /** @var NodeInterface|NodeInterface[] $nodeOrNodes */
46
            $nodeOrNodes = $this->{$name};
47
48
            if (null === $nodeOrNodes || empty($nodeOrNodes)) {
49
                continue;
50
            }
51
52
            $newNodeOrNodes = \is_array($nodeOrNodes)
53
                ? $this->visitNodes($nodeOrNodes, $name)
54
                : $this->visitNode($nodeOrNodes, $name);
55
56
            if (null === $newNodeOrNodes || empty($newNodeOrNodes)) {
57
                continue;
58
            }
59
60
            $setter = 'set' . ucfirst($name);
61
            $this->newNode->{$setter}($newNodeOrNodes);
62
        }
63
64
        if (null === ($this->newNode = $visitor->leaveNode($this->newNode, $key, $this->path))) {
65
            return null;
66
        }
67
68
        return $this->newNode;
69
    }
70
71
    /**
72
     * @param NodeInterface[] $nodes
73
     * @param string $key
74
     * @return NodeInterface[]
75
     */
76
    protected function visitNodes(array $nodes, string $key): array
77
    {
78
        $this->addOneToPath($key);
79
80
        $index = 0;
81
        $newNodes = [];
82
83
        foreach ($nodes as $node) {
84
            if (null !== ($newNode = $this->visitNode($node, $index))) {
85
                $newNodes[$index] = $newNode;
86
                $index++;
87
            }
88
        }
89
90
        $this->removeOneFromPath();
91
92
        return $newNodes;
93
    }
94
95
    /**
96
     * @param NodeInterface|AcceptVisitorTrait $node
97
     * @param string $key
98
     * @return NodeInterface|null
99
     */
100
    protected function visitNode(NodeInterface $node, string $key): ?NodeInterface
101
    {
102
        $this->addOneToPath($key);
103
104
        $newNode = $node->accept($this->visitor, $key, $this->path);
0 ignored issues
show
Bug introduced by
The method accept() does not exist on Digia\GraphQL\Language\AST\Node\NodeInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Digia\GraphQL\Language\A...DefinitionNodeInterface or Digia\GraphQL\Language\A...eExtensionNodeInterface or Digia\GraphQL\Language\AST\Node\ValueNodeInterface or Digia\GraphQL\Language\A...\SelectionNodeInterface or Digia\GraphQL\Language\AST\Node\TypeNodeInterface or Digia\GraphQL\Language\A...DefinitionNodeInterface or Digia\GraphQL\Language\A...DefinitionNodeInterface or Digia\GraphQL\Language\A...DefinitionNodeInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

104
        /** @scrutinizer ignore-call */ 
105
        $newNode = $node->accept($this->visitor, $key, $this->path);
Loading history...
105
106
        $this->removeOneFromPath();
107
108
        return $newNode;
109
    }
110
111
    /**
112
     * Appends a key to the path.
113
     * @param string $key
114
     */
115
    protected function addOneToPath(string $key)
116
    {
117
        $this->path[] = $key;
118
    }
119
120
    /**
121
     * Removes the last item from the path.
122
     */
123
    protected function removeOneFromPath()
124
    {
125
        $this->path = \array_slice($this->path, 0, count($this->path) - 1);
126
    }
127
128
    /**
129
     * @var array
130
     */
131
    protected static $kindToNodesToVisitMap = [
132
        'Name' => [],
133
134
        'Document' => ['definitions'],
135
        'OperationDefinition' => [
136
            'name',
137
            'variableDefinitions',
138
            'directives',
139
            'selectionSet',
140
        ],
141
        'VariableDefinition' => ['variable', 'type', 'defaultValue'],
142
        'Variable' => ['name'],
143
        'SelectionSet' => ['selections'],
144
        'Field' => ['alias', 'name', 'arguments', 'directives', 'selectionSet'],
145
        'Argument' => ['name', 'value'],
146
147
        'FragmentSpread' => ['name', 'directives'],
148
        'InlineFragment' => ['typeCondition', 'directives', 'selectionSet'],
149
        'FragmentDefinition' => [
150
            'name',
151
            // Note: fragment variable definitions are experimental and may be changed or removed in the future.
152
            'variableDefinitions',
153
            'typeCondition',
154
            'directives',
155
            'selectionSet',
156
        ],
157
158
        'IntValue' => [],
159
        'FloatValue' => [],
160
        'StringValue' => [],
161
        'BooleanValue' => [],
162
        'NullValue' => [],
163
        'EnumValue' => [],
164
        'ListValue' => ['values'],
165
        'ObjectValue' => ['fields'],
166
        'ObjectField' => ['name', 'value'],
167
168
        'Directive' => ['name', 'arguments'],
169
170
        'NamedType' => ['name'],
171
        'ListType' => ['type'],
172
        'NonNullType' => ['type'],
173
174
        'SchemaDefinition' => ['directives', 'operationTypes'],
175
        'OperationTypeDefinition' => ['type'],
176
177
        'ScalarTypeDefinition' => ['description', 'name', 'directives'],
178
        'ObjectTypeDefinition' => [
179
            'description',
180
            'name',
181
            'interfaces',
182
            'directives',
183
            'fields',
184
        ],
185
        'FieldDefinition' => ['description', 'name', 'arguments', 'type', 'directives'],
186
        'InputValueDefinition' => [
187
            'description',
188
            'name',
189
            'type',
190
            'defaultValue',
191
            'directives',
192
        ],
193
        'InterfaceTypeDefinition' => ['description', 'name', 'directives', 'fields'],
194
        'UnionTypeDefinition' => ['description', 'name', 'directives', 'types'],
195
        'EnumTypeDefinition' => ['description', 'name', 'directives', 'values'],
196
        'EnumValueDefinition' => ['description', 'name', 'directives'],
197
        'InputObjectTypeDefinition' => ['description', 'name', 'directives', 'fields'],
198
199
        'ScalarTypeExtension' => ['name', 'directives'],
200
        'ObjectTypeExtension' => ['name', 'interfaces', 'directives', 'fields'],
201
        'InterfaceTypeExtension' => ['name', 'directives', 'fields'],
202
        'UnionTypeExtension' => ['name', 'directives', 'types'],
203
        'EnumTypeExtension' => ['name', 'directives', 'values'],
204
        'InputObjectTypeExtension' => ['name', 'directives', 'fields'],
205
206
        'DirectiveDefinition' => ['description', 'name', 'arguments', 'locations'],
207
    ];
208
}
209