Completed
Pull Request — master (#23)
by Christoffer
01:57
created

AcceptVisitorTrait   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 215
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 215
rs 10
c 0
b 0
f 0
wmc 17

6 Methods

Rating   Name   Duplication   Size   Complexity  
A addOneToPath() 0 3 1
C accept() 0 33 7
A acceptVisitor() 0 7 2
A visitNodes() 0 20 4
A visitNode() 0 9 2
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
7
trait AcceptVisitorTrait
8
{
9
10
    /**
11
     * @var array
12
     */
13
    protected static $kindToNodesToVisitMap = [
14
        'Name' => [],
15
16
        'Document' => ['definitions'],
17
        'OperationDefinition' => [
18
            'name',
19
            'variableDefinitions',
20
            'directives',
21
            'selectionSet',
22
        ],
23
        'VariableDefinition' => ['variable', 'type', 'defaultValue'],
24
        'Variable' => ['name'],
25
        'SelectionSet' => ['selections'],
26
        'Field' => ['alias', 'name', 'arguments', 'directives', 'selectionSet'],
27
        'Argument' => ['name', 'value'],
28
29
        'FragmentSpread' => ['name', 'directives'],
30
        'InlineFragment' => ['typeCondition', 'directives', 'selectionSet'],
31
        'FragmentDefinition' => [
32
            'name',
33
            // Note: fragment variable definitions are experimental and may be changed or removed in the future.
34
            'variableDefinitions',
35
            'typeCondition',
36
            'directives',
37
            'selectionSet',
38
        ],
39
40
        'IntValue' => [],
41
        'FloatValue' => [],
42
        'StringValue' => [],
43
        'BooleanValue' => [],
44
        'NullValue' => [],
45
        'EnumValue' => [],
46
        'ListValue' => ['values'],
47
        'ObjectValue' => ['fields'],
48
        'ObjectField' => ['name', 'value'],
49
50
        'Directive' => ['name', 'arguments'],
51
52
        'NamedType' => ['name'],
53
        'ListType' => ['type'],
54
        'NonNullType' => ['type'],
55
56
        'SchemaDefinition' => ['directives', 'operationTypes'],
57
        'OperationTypeDefinition' => ['type'],
58
59
        'ScalarTypeDefinition' => ['description', 'name', 'directives'],
60
        'ObjectTypeDefinition' => [
61
            'description',
62
            'name',
63
            'interfaces',
64
            'directives',
65
            'fields',
66
        ],
67
        'FieldDefinition' => ['description', 'name', 'arguments', 'type', 'directives'],
68
        'InputValueDefinition' => [
69
            'description',
70
            'name',
71
            'type',
72
            'defaultValue',
73
            'directives',
74
        ],
75
        'InterfaceTypeDefinition' => ['description', 'name', 'directives', 'fields'],
76
        'UnionTypeDefinition' => ['description', 'name', 'directives', 'types'],
77
        'EnumTypeDefinition' => ['description', 'name', 'directives', 'values'],
78
        'EnumValueDefinition' => ['description', 'name', 'directives'],
79
        'InputObjectTypeDefinition' => ['description', 'name', 'directives', 'fields'],
80
81
        'ScalarTypeExtension' => ['name', 'directives'],
82
        'ObjectTypeExtension' => ['name', 'interfaces', 'directives', 'fields'],
83
        'InterfaceTypeExtension' => ['name', 'directives', 'fields'],
84
        'UnionTypeExtension' => ['name', 'directives', 'types'],
85
        'EnumTypeExtension' => ['name', 'directives', 'values'],
86
        'InputObjectTypeExtension' => ['name', 'directives', 'fields'],
87
88
        'DirectiveDefinition' => ['description', 'name', 'arguments', 'locations'],
89
    ];
90
91
    /**
92
     * @var VisitorInterface
93
     */
94
    protected $visitor;
95
96
    /**
97
     * @var array
98
     */
99
    protected $path;
100
101
    /**
102
     * @var array
103
     */
104
    protected $edited = [];
105
106
    /**
107
     * @return string
108
     */
109
    abstract public function getKind(): string;
110
111
    /**
112
     * @param VisitorInterface $visitor
113
     * @param string|null $key
114
     * @return array|null
115
     */
116
    public function accept(VisitorInterface $visitor, ?string $key = null, array $path = []): ?array
117
    {
118
        $this->visitor = $visitor;
119
        $this->path = $path;
120
121
        /** @noinspection PhpParamsInspection */
122
        if (null === ($enterResult = $visitor->enterNode($this->toArray(), $key, $this->path))) {
0 ignored issues
show
Bug introduced by
It seems like toArray() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

122
        if (null === ($enterResult = $visitor->enterNode($this->/** @scrutinizer ignore-call */ toArray(), $key, $this->path))) {
Loading history...
123
            return null;
124
        }
125
126
        $this->edited = $enterResult;
127
128
        foreach (self::$kindToNodesToVisitMap[$this->getKind()] as $name) {
129
            // We have to remove children ensure that we do not include nodes in the result
130
            // even though we return null from either enterNode or leaveNode.
131
            unset($this->edited[$name]);
132
133
            /** @var NodeInterface|NodeInterface[] $nodeOrNodes */
134
            $nodeOrNodes = $this->{$name};
135
136
            if (\is_array($nodeOrNodes) && !empty($nodeOrNodes)) {
137
                $this->visitNodes($nodeOrNodes, $name);
138
            } elseif ($nodeOrNodes instanceof AcceptVisitorInterface) {
139
                $this->visitNode($nodeOrNodes, $name);
140
            }
141
        }
142
143
        /** @noinspection PhpParamsInspection */
144
        if (null === ($leaveResult = $visitor->leaveNode($this->toArray(), $key, $this->path))) {
145
            return null;
146
        }
147
148
        return array_merge($leaveResult, $this->edited);
149
    }
150
151
    /**
152
     * @param NodeInterface[] $nodes
153
     * @param string $key
154
     */
155
    protected function visitNodes(array $nodes, string $key)
156
    {
157
        $this->addOneToPath($key);
158
159
        $index = 0;
160
161
        foreach ($nodes as $node) {
162
            if ($node instanceof AcceptVisitorInterface) {
163
                $this->addOneToPath($index);
164
165
                if (null !== ($result = $this->acceptVisitor($node, $index))) {
166
                    $this->edited[$key][$index] = $result;
167
                    $index++;
168
                }
169
170
                $this->removeOneFromPath();
171
            }
172
        }
173
174
        $this->removeOneFromPath();
175
    }
176
177
    /**
178
     * @param NodeInterface $node
179
     * @param null|string $key
180
     */
181
    protected function visitNode(NodeInterface $node, ?string $key = null)
182
    {
183
        $this->addOneToPath($key);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type null; however, parameter $key of Digia\GraphQL\Language\A...orTrait::addOneToPath() does only seem to accept string, 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

183
        $this->addOneToPath(/** @scrutinizer ignore-type */ $key);
Loading history...
184
185
        if (null !== ($result = $this->acceptVisitor($node, $key))) {
186
            $this->edited[$key] = $result;
187
        }
188
189
        $this->removeOneFromPath();
190
    }
191
192
    /**
193
     * @param NodeInterface|AcceptVisitorInterface $node
194
     * @param string|null $key
195
     * @param array $path
196
     * @return array|null
197
     */
198
    protected function acceptVisitor(NodeInterface $node, ?string $key): ?array
199
    {
200
        if (null === ($result = $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

200
        if (null === ($result = $node->/** @scrutinizer ignore-call */ accept($this->visitor, $key, $this->path))) {
Loading history...
201
            return null;
202
        }
203
204
        return $result;
205
    }
206
207
    /**
208
     * Appends a key to the path.
209
     * @param string $key
210
     */
211
    protected function addOneToPath(string $key)
212
    {
213
        $this->path[] = $key;
214
    }
215
216
    /**
217
     * Removes the last item from the path.
218
     */
219
    protected function removeOneFromPath()
220
    {
221
        $this->path = \array_slice($this->path, 0, count($this->path) - 1);
222
    }
223
}
224