Passed
Pull Request — master (#124)
by Christoffer
02:15
created

SchemaBuilder::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
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\SchemaDefinitionNode;
10
use Digia\GraphQL\Language\Node\TypeDefinitionNodeInterface;
11
use Digia\GraphQL\Language\Node\TypeNodeInterface;
12
use Digia\GraphQL\Type\Definition\DirectiveInterface;
13
use Digia\GraphQL\Type\SchemaInterface;
14
use function Digia\GraphQL\Type\GraphQLSchema;
15
use function Digia\GraphQL\Util\arraySome;
16
17
class SchemaBuilder implements SchemaBuilderInterface
18
{
19
20
    /**
21
     * @var DefinitionBuilderInterface
22
     */
23
    protected $definitionBuilder;
24
25
    /**
26
     * SchemaBuilder constructor.
27
     *
28
     * @param DefinitionBuilderInterface $definitionBuilder
29
     */
30
    public function __construct(DefinitionBuilderInterface $definitionBuilder)
31
    {
32
        $this->definitionBuilder = $definitionBuilder;
33
    }
34
35
    /**
36
     * @inheritdoc
37
     */
38
    public function build(DocumentNode $document, array $resolverMap = [], array $options = []): SchemaInterface
39
    {
40
        $schemaDefinition     = null;
41
        $typeDefinitions      = [];
42
        $nodeMap              = [];
43
        $directiveDefinitions = [];
44
45
        $this->definitionBuilder->setResolverMap($resolverMap);
46
47
        foreach ($document->getDefinitions() as $definition) {
48
            if ($definition instanceof SchemaDefinitionNode) {
49
                if ($schemaDefinition) {
50
                    throw new LanguageException('Must provide only one schema definition.');
51
                }
52
                $schemaDefinition = $definition;
53
                continue;
54
            }
55
56
            if ($definition instanceof TypeDefinitionNodeInterface) {
57
                $typeName = $definition->getNameValue();
58
                if (isset($nodeMap[$typeName])) {
59
                    throw new LanguageException(sprintf('Type "%s" was defined more than once.', $typeName));
60
                }
61
                $typeDefinitions[]  = $definition;
62
                $nodeMap[$typeName] = $definition;
63
                continue;
64
            }
65
66
            if ($definition instanceof DirectiveDefinitionNode) {
67
                $directiveDefinitions[] = $definition;
68
                continue;
69
            }
70
        }
71
72
        $operationTypes = null !== $schemaDefinition ? getOperationTypes($schemaDefinition, $nodeMap) : [
73
            'query'        => $nodeMap['Query'] ?? null,
74
            'mutation'     => $nodeMap['Mutation'] ?? null,
75
            'subscription' => $nodeMap['Subscription'] ?? null,
76
        ];
77
78
        $this->definitionBuilder->setTypeDefinitionMap($nodeMap);
79
80
        $types = array_map(function (TypeDefinitionNodeInterface $definition) {
81
            return $this->definitionBuilder->buildType($definition);
82
        }, $typeDefinitions);
83
84
        $directives = array_map(function (DirectiveDefinitionNode $definition) {
85
            return $this->definitionBuilder->buildDirective($definition);
86
        }, $directiveDefinitions);
87
88
        if (!arraySome($directives, function (DirectiveInterface $directive) {
89
            return $directive->getName() === 'skip';
90
        })) {
91
            $directives[] = GraphQLSkipDirective();
92
        }
93
94
        if (!arraySome($directives, function (DirectiveInterface $directive) {
95
            return $directive->getName() === 'include';
96
        })) {
97
            $directives[] = GraphQLIncludeDirective();
98
        }
99
100
        if (!arraySome($directives, function (DirectiveInterface $directive) {
101
            return $directive->getName() === 'deprecated';
102
        })) {
103
            $directives[] = GraphQLDeprecatedDirective();
104
        }
105
106
        return GraphQLSchema([
107
            'query'        => isset($operationTypes['query'])
108
                ? $this->definitionBuilder->buildType($operationTypes['query'])
109
                : null,
110
            'mutation'     => isset($operationTypes['mutation'])
111
                ? $this->definitionBuilder->buildType($operationTypes['mutation'])
112
                : null,
113
            'subscription' => isset($operationTypes['subscription'])
114
                ? $this->definitionBuilder->buildType($operationTypes['subscription'])
115
                : null,
116
            'types'        => $types,
117
            'directives'   => $directives,
118
            'astNode'      => $schemaDefinition,
119
            'assumeValid'  => $options['assumeValid'] ?? false,
120
        ]);
121
    }
122
}
123
124
/**
125
 * @param SchemaDefinitionNode $schemaDefinition
126
 * @param array                $nodeMap
127
 * @return array
128
 * @throws LanguageException
129
 */
130
function getOperationTypes(SchemaDefinitionNode $schemaDefinition, array $nodeMap): array
131
{
132
    $operationTypes = [];
133
134
    foreach ($schemaDefinition->getOperationTypes() as $operationTypeDefinition) {
135
        /** @var TypeNodeInterface|NamedTypeNode $operationType */
136
        $operationType = $operationTypeDefinition->getType();
137
        $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

137
        /** @scrutinizer ignore-call */ 
138
        $typeName      = $operationType->getNameValue();
Loading history...
138
        $operation     = $operationTypeDefinition->getOperation();
139
140
        if (isset($operationTypes[$typeName])) {
141
            throw new LanguageException(sprintf('Must provide only one %s type in schema.', $operation));
142
        }
143
144
        if (!isset($nodeMap[$typeName])) {
145
            throw new LanguageException(sprintf('Specified %s type %s not found in document.', $operation, $typeName));
146
        }
147
148
        $operationTypes[$operation] = $operationType;
149
    }
150
151
    return $operationTypes;
152
}
153