Completed
Pull Request — master (#215)
by Christoffer
03:55
created

SchemaBuilder   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 130
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 130
rs 10
c 0
b 0
f 0
wmc 14

4 Methods

Rating   Name   Duplication   Size   Complexity  
A createContext() 0 16 1
A build() 0 15 1
B getOperationTypeDefinitions() 0 26 4
C createInfo() 0 42 8
1
<?php
2
3
namespace Digia\GraphQL\Schema\Building;
4
5
use Digia\GraphQL\Error\BuildingException;
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\SchemaDefinitionNode;
10
use Digia\GraphQL\Language\Node\TypeDefinitionNodeInterface;
11
use Digia\GraphQL\Language\Node\TypeNodeInterface;
12
use Digia\GraphQL\Schema\DefinitionBuilder;
13
use Digia\GraphQL\Schema\Resolver\ResolverRegistryInterface;
14
use Digia\GraphQL\Schema\Schema;
15
use Psr\SimpleCache\CacheInterface;
16
use function Digia\GraphQL\Type\newSchema;
17
use Psr\SimpleCache\InvalidArgumentException;
18
19
class SchemaBuilder implements SchemaBuilderInterface
20
{
21
    /**
22
     * @inheritdoc
23
     */
24
    public function build(
25
        DocumentNode $document,
26
        ResolverRegistryInterface $resolverRegistry,
27
        array $options = []
28
    ): Schema {
29
        $context = $this->createContext($document, $resolverRegistry, $options);
30
31
        return newSchema([
32
            'query'        => $context->buildQueryType(),
33
            'mutation'     => $context->buildMutationType(),
34
            'subscription' => $context->buildSubscriptionType(),
35
            'types'        => $context->buildTypes(),
36
            'directives'   => $context->buildDirectives(),
37
            'astNode'      => $context->getSchemaDefinition(),
38
            'assumeValid'  => $options['assumeValid'] ?? false,
39
        ]);
40
    }
41
42
    /**
43
     * @param DocumentNode              $document
44
     * @param ResolverRegistryInterface $resolverRegistry
45
     * @param array $options
46
     * @return BuildingContextInterface
47
     * @throws BuildingException
48
     * @throws InvalidArgumentException
49
     */
50
    protected function createContext(
51
        DocumentNode $document,
52
        ResolverRegistryInterface $resolverRegistry,
53
        array $options
54
    ): BuildingContextInterface {
55
        $info = $this->createInfo($document);
56
57
        $definitionBuilder = new DefinitionBuilder(
58
            $info->getTypeDefinitionMap(),
59
            $resolverRegistry,
60
            $options['types'] ?? [],
61
            $options['directives'] ?? [],
62
            null // use the default resolveType-function
63
        );
64
65
        return new BuildingContext($resolverRegistry, $definitionBuilder, $info);
66
    }
67
68
    /**
69
     * @param DocumentNode $document
70
     * @return BuildInfo
71
     * @throws BuildingException
72
     */
73
    protected function createInfo(DocumentNode $document): BuildInfo
74
    {
75
        $schemaDefinition     = null;
76
        $typeDefinitionMap    = [];
77
        $directiveDefinitions = [];
78
79
        foreach ($document->getDefinitions() as $definition) {
80
            if ($definition instanceof SchemaDefinitionNode) {
81
                if (null !== $schemaDefinition) {
82
                    throw new BuildingException('Must provide only one schema definition.');
83
                }
84
85
                $schemaDefinition = $definition;
86
87
                continue;
88
            }
89
90
            if ($definition instanceof TypeDefinitionNodeInterface) {
91
                $typeName = $definition->getNameValue();
92
93
                if (isset($typeDefinitionMap[$typeName])) {
94
                    throw new BuildingException(sprintf('Type "%s" was defined more than once.', $typeName));
95
                }
96
97
                $typeDefinitionMap[$typeName] = $definition;
98
99
                continue;
100
            }
101
102
            if ($definition instanceof DirectiveDefinitionNode) {
103
                $directiveDefinitions[] = $definition;
104
105
                continue;
106
            }
107
        }
108
109
        return new BuildInfo(
110
            $document,
111
            $typeDefinitionMap,
112
            $directiveDefinitions,
113
            null !== $schemaDefinition ? $this->getOperationTypeDefinitions($schemaDefinition, $typeDefinitionMap) : [],
114
            $schemaDefinition
115
        );
116
    }
117
118
    /**
119
     * @param SchemaDefinitionNode $node
120
     * @return array
121
     * @throws BuildingException
122
     */
123
    protected function getOperationTypeDefinitions(SchemaDefinitionNode $node, array $typeDefinitionMap): array
124
    {
125
        $definitions = [];
126
127
        foreach ($node->getOperationTypes() as $operationTypeDefinition) {
128
            /** @var TypeNodeInterface|NamedTypeNode $operationType */
129
            $operationType = $operationTypeDefinition->getType();
130
            $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

130
            /** @scrutinizer ignore-call */ 
131
            $typeName      = $operationType->getNameValue();
Loading history...
131
            $operation     = $operationTypeDefinition->getOperation();
132
133
            if (isset($definitions[$typeName])) {
134
                throw new BuildingException(
135
                    \sprintf('Must provide only one %s type in schema.', $operation)
136
                );
137
            }
138
139
            if (!isset($typeDefinitionMap[$typeName])) {
140
                throw new BuildingException(
141
                    \sprintf('Specified %s type %s not found in document.', $operation, $typeName)
142
                );
143
            }
144
145
            $definitions[$operation] = $operationType;
146
        }
147
148
        return $definitions;
149
    }
150
}
151