GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

BuildSchema::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Utils;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Language\AST\DirectiveDefinitionNode;
9
use GraphQL\Language\AST\DocumentNode;
10
use GraphQL\Language\AST\EnumTypeDefinitionNode;
11
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
12
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
13
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
14
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
15
use GraphQL\Language\AST\SchemaDefinitionNode;
16
use GraphQL\Language\AST\TypeDefinitionNode;
17
use GraphQL\Language\AST\UnionTypeDefinitionNode;
18
use GraphQL\Language\Parser;
19
use GraphQL\Language\Source;
20
use GraphQL\Type\Definition\Directive;
21
use GraphQL\Type\Schema;
22
use GraphQL\Validator\DocumentValidator;
23
use function array_map;
24
use function sprintf;
25
26
/**
27
 * Build instance of `GraphQL\Type\Schema` out of type language definition (string or parsed AST)
28
 * See [section in docs](type-system/type-language.md) for details.
29
 */
30
class BuildSchema
31
{
32
    /** @var DocumentNode */
33
    private $ast;
34
35
    /** @var TypeDefinitionNode[] */
36
    private $nodeMap;
37
38
    /** @var callable|null */
39
    private $typeConfigDecorator;
40
41
    /** @var bool[] */
42
    private $options;
43
44
    /**
45
     * @param bool[] $options
46
     */
47 157
    public function __construct(DocumentNode $ast, ?callable $typeConfigDecorator = null, array $options = [])
48
    {
49 157
        $this->ast                 = $ast;
50 157
        $this->typeConfigDecorator = $typeConfigDecorator;
51 157
        $this->options             = $options;
52 157
    }
53
54
    /**
55
     * A helper function to build a GraphQLSchema directly from a source
56
     * document.
57
     *
58
     * @param DocumentNode|Source|string $source
59
     * @param bool[]                     $options
60
     *
61
     * @return Schema
62
     *
63
     * @api
64
     */
65 113
    public static function build($source, ?callable $typeConfigDecorator = null, array $options = [])
66
    {
67 113
        $doc = $source instanceof DocumentNode ? $source : Parser::parse($source);
68
69 113
        return self::buildAST($doc, $typeConfigDecorator, $options);
70
    }
71
72
    /**
73
     * This takes the ast of a schema document produced by the parse function in
74
     * GraphQL\Language\Parser.
75
     *
76
     * If no schema definition is provided, then it will look for types named Query
77
     * and Mutation.
78
     *
79
     * Given that AST it constructs a GraphQL\Type\Schema. The resulting schema
80
     * has no resolve methods, so execution will use default resolvers.
81
     *
82
     * Accepts options as a third argument:
83
     *
84
     *    - commentDescriptions:
85
     *        Provide true to use preceding comments as the description.
86
     *
87
     * @param bool[] $options
88
     *
89
     * @return Schema
90
     *
91
     * @throws Error
92
     *
93
     * @api
94
     */
95 157
    public static function buildAST(DocumentNode $ast, ?callable $typeConfigDecorator = null, array $options = [])
96
    {
97 157
        $builder = new self($ast, $typeConfigDecorator, $options);
98
99 157
        return $builder->buildSchema();
100
    }
101
102 157
    public function buildSchema()
103
    {
104 157
        $options = $this->options;
105 157
        if (empty($options['assumeValid']) && empty($options['assumeValidSDL'])) {
106 154
            DocumentValidator::assertValidSDL($this->ast);
107
        }
108
109 156
        $schemaDef     = null;
110 156
        $typeDefs      = [];
111 156
        $this->nodeMap = [];
112 156
        $directiveDefs = [];
113 156
        foreach ($this->ast->definitions as $definition) {
114
            switch (true) {
115 156
                case $definition instanceof SchemaDefinitionNode:
116 31
                    $schemaDef = $definition;
117 31
                    break;
118 156
                case $definition instanceof ScalarTypeDefinitionNode:
119 156
                case $definition instanceof ObjectTypeDefinitionNode:
120 96
                case $definition instanceof InterfaceTypeDefinitionNode:
121 70
                case $definition instanceof EnumTypeDefinitionNode:
122 61
                case $definition instanceof UnionTypeDefinitionNode:
123 49
                case $definition instanceof InputObjectTypeDefinitionNode:
124 140
                    $typeName = $definition->name->value;
125 140
                    if (! empty($this->nodeMap[$typeName])) {
126 1
                        throw new Error(sprintf('Type "%s" was defined more than once.', $typeName));
127
                    }
128 140
                    $typeDefs[]               = $definition;
129 140
                    $this->nodeMap[$typeName] = $definition;
130 140
                    break;
131 31
                case $definition instanceof DirectiveDefinitionNode:
132 29
                    $directiveDefs[] = $definition;
133 156
                    break;
134
            }
135
        }
136
137 155
        $operationTypes = $schemaDef !== null
138 30
            ? $this->getOperationTypes($schemaDef)
139
            : [
140 146
                'query'        => isset($this->nodeMap['Query']) ? 'Query' : null,
141 132
                'mutation'     => isset($this->nodeMap['Mutation']) ? 'Mutation' : null,
142 132
                'subscription' => isset($this->nodeMap['Subscription']) ? 'Subscription' : null,
143
            ];
144
145 146
        $DefinitionBuilder = new ASTDefinitionBuilder(
146 146
            $this->nodeMap,
147 146
            $this->options,
148
            static function ($typeName) {
149 5
                throw new Error('Type "' . $typeName . '" not found in document.');
150 146
            },
151 146
            $this->typeConfigDecorator
152
        );
153
154 146
        $directives = array_map(
155
            static function ($def) use ($DefinitionBuilder) {
156 28
                return $DefinitionBuilder->buildDirective($def);
157 146
            },
158 146
            $directiveDefs
159
        );
160
161
        // If specified directives were not explicitly declared, add them.
162 146
        $directivesByName = Utils::groupBy(
163 146
            $directives,
164
            static function (Directive $directive) : string {
165 28
                return $directive->name;
166 146
            }
167
        );
168 146
        if (! isset($directivesByName['skip'])) {
169 145
            $directives[] = Directive::skipDirective();
170
        }
171 146
        if (! isset($directivesByName['include'])) {
172 145
            $directives[] = Directive::includeDirective();
173
        }
174 146
        if (! isset($directivesByName['deprecated'])) {
175 145
            $directives[] = Directive::deprecatedDirective();
176
        }
177
178
        // Note: While this could make early assertions to get the correctly
179
        // typed values below, that would throw immediately while type system
180
        // validation with validateSchema() will produce more actionable results.
181
182 146
        return new Schema([
183 146
            'query'        => isset($operationTypes['query'])
184 127
                ? $DefinitionBuilder->buildType($operationTypes['query'])
185
                : null,
186 146
            'mutation'     => isset($operationTypes['mutation'])
187 7
                ? $DefinitionBuilder->buildType($operationTypes['mutation'])
188
                : null,
189 146
            'subscription' => isset($operationTypes['subscription'])
190 5
                ? $DefinitionBuilder->buildType($operationTypes['subscription'])
191
                : null,
192
            'typeLoader'   => static function ($name) use ($DefinitionBuilder) {
193 15
                return $DefinitionBuilder->buildType($name);
194 146
            },
195 146
            'directives'   => $directives,
196 146
            'astNode'      => $schemaDef,
197
            'types'        => function () use ($DefinitionBuilder) {
198 112
                $types = [];
199
                /** @var ScalarTypeDefinitionNode|ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode|UnionTypeDefinitionNode|EnumTypeDefinitionNode|InputObjectTypeDefinitionNode $def */
200 112
                foreach ($this->nodeMap as $name => $def) {
201 112
                    $types[] = $DefinitionBuilder->buildType($def->name->value);
202
                }
203
204 112
                return $types;
205 146
            },
206
        ]);
207
    }
208
209
    /**
210
     * @param SchemaDefinitionNode $schemaDef
211
     *
212
     * @return string[]
213
     *
214
     * @throws Error
215
     */
216 30
    private function getOperationTypes($schemaDef)
217
    {
218 30
        $opTypes = [];
219
220 30
        foreach ($schemaDef->operationTypes as $operationType) {
221 30
            $typeName  = $operationType->type->name->value;
222 30
            $operation = $operationType->operation;
223
224 30
            if (isset($opTypes[$operation])) {
225 3
                throw new Error(sprintf('Must provide only one %s type in schema.', $operation));
226
            }
227
228 30
            if (! isset($this->nodeMap[$typeName])) {
229 6
                throw new Error(sprintf('Specified %s type "%s" not found in document.', $operation, $typeName));
230
            }
231
232 26
            $opTypes[$operation] = $typeName;
233
        }
234
235 21
        return $opTypes;
236
    }
237
}
238