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

BuilderContext::buildDirectives()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
cc 3
eloc 12
nc 3
nop 0
1
<?php
2
3
namespace Digia\GraphQL\SchemaBuilder;
4
5
use Digia\GraphQL\Error\LanguageException;
6
use Digia\GraphQL\Language\Node\DirectiveDefinitionNode;
7
use Digia\GraphQL\Language\Node\DocumentNode;
8
use Digia\GraphQL\Language\Node\NamedTypeNode;
9
use Digia\GraphQL\Language\Node\OperationTypeDefinitionNode;
10
use Digia\GraphQL\Language\Node\SchemaDefinitionNode;
11
use Digia\GraphQL\Language\Node\TypeDefinitionNodeInterface;
12
use Digia\GraphQL\Language\Node\TypeNodeInterface;
13
use Digia\GraphQL\Type\Definition\Directive;
14
use Digia\GraphQL\Type\Definition\TypeInterface;
15
use function Digia\GraphQL\Util\arraySome;
16
17
class BuilderContext implements BuilderContextInterface
18
{
19
    /**
20
     * @var DocumentNode
21
     */
22
    protected $document;
23
24
    /**
25
     * @var ResolverRegistryInterface
26
     */
27
    protected $resolverRegistry;
28
29
    /**
30
     * @var DefinitionBuilderCreatorInterface
31
     */
32
    protected $definitionBuilderCreator;
33
34
    /**
35
     * @var DefinitionBuilderInterface
36
     */
37
    protected $definitionBuilder;
38
39
    /**
40
     * @var SchemaDefinitionNode|null
41
     */
42
    protected $schemaDefinition;
43
44
    /**
45
     * @var TypeInterface[]
46
     */
47
    protected $typeDefinitionMap;
48
49
    /**
50
     * @var DirectiveDefinitionNode[]
51
     */
52
    protected $directiveDefinitions;
53
54
    /**
55
     * @var OperationTypeDefinitionNode[]
56
     */
57
    protected $operationTypeDefinitions;
58
59
    /**
60
     * BuilderContext constructor.
61
     * @param DocumentNode                      $document
62
     * @param ResolverRegistryInterface         $resolverRegistry
63
     * @param DefinitionBuilderCreatorInterface $definitionBuilderCreator
64
     * @throws LanguageException
65
     */
66
    public function __construct(
67
        DocumentNode $document,
68
        ResolverRegistryInterface $resolverRegistry,
69
        DefinitionBuilderCreatorInterface $definitionBuilderCreator
70
    ) {
71
        $this->document                 = $document;
72
        $this->resolverRegistry         = $resolverRegistry;
73
        $this->definitionBuilderCreator = $definitionBuilderCreator;
74
    }
75
76
    /**
77
     * @throws LanguageException
78
     */
79
    public function boot(): void
80
    {
81
        $this->buildDefinitions();
82
83
        $this->definitionBuilder = $this->createDefinitionBuilder();
84
85
        if (null !== $this->schemaDefinition) {
86
            $this->buildOperationTypeDefinitions();
87
        }
88
    }
89
90
    /**
91
     * @return TypeInterface|null
92
     */
93
    public function buildQueryType(): ?TypeInterface
94
    {
95
        $definition = $this->operationTypeDefinitions['query'] ?? $this->typeDefinitionMap['Query'] ?? null;
96
        return null !== $definition ? $this->definitionBuilder->buildType($definition) : null;
0 ignored issues
show
Bug introduced by
It seems like $definition can also be of type Digia\GraphQL\Type\Definition\TypeInterface; however, parameter $node of Digia\GraphQL\SchemaBuil...rInterface::buildType() does only seem to accept Digia\GraphQL\Language\Node\NodeInterface, 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

96
        return null !== $definition ? $this->definitionBuilder->buildType(/** @scrutinizer ignore-type */ $definition) : null;
Loading history...
97
    }
98
99
    /**
100
     * @return TypeInterface|null
101
     */
102
    public function buildMutationType(): ?TypeInterface
103
    {
104
        $definition = $this->operationTypeDefinitions['mutation'] ?? $this->typeDefinitionMap['Mutation'] ?? null;
105
        return null !== $definition ? $this->definitionBuilder->buildType($definition) : null;
0 ignored issues
show
Bug introduced by
It seems like $definition can also be of type Digia\GraphQL\Type\Definition\TypeInterface; however, parameter $node of Digia\GraphQL\SchemaBuil...rInterface::buildType() does only seem to accept Digia\GraphQL\Language\Node\NodeInterface, 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

105
        return null !== $definition ? $this->definitionBuilder->buildType(/** @scrutinizer ignore-type */ $definition) : null;
Loading history...
106
    }
107
108
    /**
109
     * @return TypeInterface|null
110
     */
111
    public function buildSubscriptionType(): ?TypeInterface
112
    {
113
        $definition = $this->operationTypeDefinitions['subscription'] ?? $this->typeDefinitionMap['Subscription'] ?? null;
114
        return null !== $definition ? $this->definitionBuilder->buildType($definition) : null;
0 ignored issues
show
Bug introduced by
It seems like $definition can also be of type Digia\GraphQL\Type\Definition\TypeInterface; however, parameter $node of Digia\GraphQL\SchemaBuil...rInterface::buildType() does only seem to accept Digia\GraphQL\Language\Node\NodeInterface, 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

114
        return null !== $definition ? $this->definitionBuilder->buildType(/** @scrutinizer ignore-type */ $definition) : null;
Loading history...
115
    }
116
117
    /**
118
     * @return TypeInterface[]
119
     */
120
    public function buildTypes(): array
121
    {
122
        return \array_map(function (TypeDefinitionNodeInterface $definition) {
123
            return $this->definitionBuilder->buildType($definition);
124
        }, \array_values($this->typeDefinitionMap));
125
    }
126
127
    /**
128
     * @return Directive[]
129
     */
130
    public function buildDirectives(): array
131
    {
132
        $directives = \array_map(function (DirectiveDefinitionNode $definition) {
133
            return $this->definitionBuilder->buildDirective($definition);
134
        }, $this->directiveDefinitions);
135
136
        $specifiedDirectivesMap = [
137
            'skip'       => GraphQLSkipDirective(),
138
            'include'    => GraphQLIncludeDirective(),
139
            'deprecated' => GraphQLDeprecatedDirective(),
140
        ];
141
142
        foreach ($specifiedDirectivesMap as $name => $directive) {
143
            if (!arraySome($directives, function (Directive $directive) use ($name) {
144
                return $directive->getName() === $name;
145
            })) {
146
                $directives[] = $directive;
147
            }
148
        }
149
150
        return $directives;
151
    }
152
153
    /**
154
     * @return SchemaDefinitionNode|null
155
     */
156
    public function getSchemaDefinition(): ?SchemaDefinitionNode
157
    {
158
        return $this->schemaDefinition;
159
    }
160
161
    /**
162
     * @inheritdoc
163
     * @throws LanguageException
164
     */
165
    protected function buildDefinitions(): void
166
    {
167
        $schemaDefinition     = null;
168
        $typeDefinitionMap    = [];
169
        $directiveDefinitions = [];
170
171
        foreach ($this->document->getDefinitions() as $definition) {
172
            if ($definition instanceof SchemaDefinitionNode) {
173
                if (null !== $schemaDefinition) {
174
                    throw new LanguageException('Must provide only one schema definition.');
175
                }
176
177
                $schemaDefinition = $definition;
178
179
                continue;
180
            }
181
182
            if ($definition instanceof TypeDefinitionNodeInterface) {
183
                $typeName = $definition->getNameValue();
184
185
                if (isset($typeDefinitionMap[$typeName])) {
186
                    throw new LanguageException(sprintf('Type "%s" was defined more than once.', $typeName));
187
                }
188
189
                $typeDefinitionMap[$typeName] = $definition;
190
191
                continue;
192
            }
193
194
            if ($definition instanceof DirectiveDefinitionNode) {
195
                $directiveDefinitions[] = $definition;
196
197
                continue;
198
            }
199
        }
200
201
        $this->schemaDefinition     = $schemaDefinition;
202
        $this->typeDefinitionMap    = $typeDefinitionMap;
203
        $this->directiveDefinitions = $directiveDefinitions;
204
    }
205
206
    /**
207
     * @return DefinitionBuilderInterface
208
     */
209
    protected function createDefinitionBuilder(): DefinitionBuilderInterface
210
    {
211
        return $this->definitionBuilderCreator->create($this->typeDefinitionMap, null, $this->resolverRegistry);
212
    }
213
214
    /**
215
     * @throws LanguageException
216
     */
217
    protected function buildOperationTypeDefinitions(): void
218
    {
219
        $operationTypeDefinitions = [];
220
221
        foreach ($this->schemaDefinition->getOperationTypes() as $operationTypeDefinition) {
0 ignored issues
show
Bug introduced by
The method getOperationTypes() does not exist on null. ( Ignorable by Annotation )

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

221
        foreach ($this->schemaDefinition->/** @scrutinizer ignore-call */ getOperationTypes() as $operationTypeDefinition) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
222
            /** @var TypeNodeInterface|NamedTypeNode $operationType */
223
            $operationType = $operationTypeDefinition->getType();
224
            $typeName      = $operationType->getNameValue();
0 ignored issues
show
Bug introduced by
The method getNameValue() does not exist on Digia\GraphQL\Language\Node\TypeNodeInterface. It seems like you code against a sub-type of Digia\GraphQL\Language\Node\TypeNodeInterface such as Digia\GraphQL\Language\Node\NamedTypeNode. ( Ignorable by Annotation )

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

224
            /** @scrutinizer ignore-call */ 
225
            $typeName      = $operationType->getNameValue();
Loading history...
225
            $operation     = $operationTypeDefinition->getOperation();
226
227
            if (isset($operationTypeDefinitions[$typeName])) {
228
                throw new LanguageException(
229
                    \sprintf('Must provide only one %s type in schema.', $operation)
230
                );
231
            }
232
233
            if (!isset($this->typeDefinitionMap[$typeName])) {
234
                throw new LanguageException(
235
                    \sprintf('Specified %s type %s not found in document.', $operation, $typeName)
236
                );
237
            }
238
239
            $operationTypeDefinitions[$operation] = $operationType;
240
        }
241
242
        $this->operationTypeDefinitions = $operationTypeDefinitions;
243
    }
244
}
245