Passed
Pull Request — master (#19)
by Christoffer
02:06
created

SchemaBuilder::build()   C

Complexity

Conditions 14
Paths 82

Size

Total Lines 80
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 54
nc 82
nop 2
dl 0
loc 80
rs 5.0545
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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