Failed Conditions
Push — master ( a4f39b...12ee90 )
by Vladimir
11:17
created

SchemaExtender::extendCustomScalarType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 10
rs 10
ccs 9
cts 9
cp 1
cc 1
nc 1
nop 1
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\EnumTypeExtensionNode;
11
use GraphQL\Language\AST\InputObjectTypeExtensionNode;
12
use GraphQL\Language\AST\InterfaceTypeExtensionNode;
13
use GraphQL\Language\AST\Node;
14
use GraphQL\Language\AST\ObjectTypeExtensionNode;
15
use GraphQL\Language\AST\SchemaDefinitionNode;
16
use GraphQL\Language\AST\SchemaTypeExtensionNode;
17
use GraphQL\Language\AST\TypeDefinitionNode;
18
use GraphQL\Language\AST\TypeExtensionNode;
19
use GraphQL\Language\AST\UnionTypeExtensionNode;
20
use GraphQL\Type\Definition\CustomScalarType;
21
use GraphQL\Type\Definition\Directive;
22
use GraphQL\Type\Definition\EnumType;
23
use GraphQL\Type\Definition\EnumValueDefinition;
24
use GraphQL\Type\Definition\FieldArgument;
25
use GraphQL\Type\Definition\InputObjectType;
26
use GraphQL\Type\Definition\InterfaceType;
27
use GraphQL\Type\Definition\ListOfType;
28
use GraphQL\Type\Definition\NamedType;
29
use GraphQL\Type\Definition\NonNull;
30
use GraphQL\Type\Definition\ObjectType;
31
use GraphQL\Type\Definition\ScalarType;
32
use GraphQL\Type\Definition\Type;
33
use GraphQL\Type\Definition\UnionType;
34
use GraphQL\Type\Introspection;
35
use GraphQL\Type\Schema;
36
use GraphQL\Validator\DocumentValidator;
37
use function array_keys;
38
use function array_map;
39
use function array_merge;
40
use function array_values;
41
use function count;
42
43
class SchemaExtender
44
{
45
    const SCHEMA_EXTENSION = 'SchemaExtension';
46
47
    /** @var Type[] */
48
    protected static $extendTypeCache;
49
50
    /** @var mixed[] */
51
    protected static $typeExtensionsMap;
52
53
    /** @var ASTDefinitionBuilder */
54
    protected static $astBuilder;
55
56
    /**
57
     * @return TypeExtensionNode[]|null
58
     */
59 59
    protected static function getExtensionASTNodes(NamedType $type) : ?array
60
    {
61 59
        if (! $type instanceof Type) {
62
            return null;
63
        }
64
65 59
        $name = $type->name;
66 59
        if ($type->extensionASTNodes !== null) {
67 58
            if (isset(static::$typeExtensionsMap[$name])) {
68 23
                return array_merge($type->extensionASTNodes, static::$typeExtensionsMap[$name]);
69
            }
70
71 55
            return $type->extensionASTNodes;
72
        }
73
74 52
        return static::$typeExtensionsMap[$name] ?? null;
75
    }
76
77
    /**
78
     * @throws Error
79
     */
80 38
    protected static function checkExtensionNode(Type $type, Node $node) : void
81
    {
82
        switch (true) {
83 38
            case $node instanceof ObjectTypeExtensionNode:
84 24
                if (! ($type instanceof ObjectType)) {
85 1
                    throw new Error(
86 1
                        'Cannot extend non-object type "' . $type->name . '".',
87 1
                        [$node]
88
                    );
89
                }
90 23
                break;
91 23
            case $node instanceof InterfaceTypeExtensionNode:
92 10
                if (! ($type instanceof InterfaceType)) {
93 1
                    throw new Error(
94 1
                        'Cannot extend non-interface type "' . $type->name . '".',
95 1
                        [$node]
96
                    );
97
                }
98 9
                break;
99 17
            case $node instanceof EnumTypeExtensionNode:
100 7
                if (! ($type instanceof EnumType)) {
101 1
                    throw new Error(
102 1
                        'Cannot extend non-enum type "' . $type->name . '".',
103 1
                        [$node]
104
                    );
105
                }
106 6
                break;
107 13
            case $node instanceof UnionTypeExtensionNode:
108 9
                if (! ($type instanceof UnionType)) {
109 1
                    throw new Error(
110 1
                        'Cannot extend non-union type "' . $type->name . '".',
111 1
                        [$node]
112
                    );
113
                }
114 8
                break;
115 8
            case $node instanceof InputObjectTypeExtensionNode:
116 7
                if (! ($type instanceof InputObjectType)) {
117 1
                    throw new Error(
118 1
                        'Cannot extend non-input object type "' . $type->name . '".',
119 1
                        [$node]
120
                    );
121
                }
122 6
                break;
123
        }
124 37
    }
125
126 42
    protected static function extendScalarType(ScalarType $type) : CustomScalarType
127
    {
128 42
        return new CustomScalarType([
129 42
            'name' => $type->name,
130 42
            'description' => $type->description,
131 42
            'astNode' => $type->astNode,
132 42
            'serialize' => $type->config['serialize'] ?? null,
133 42
            'parseValue' => $type->config['parseValue'] ?? null,
134 42
            'parseLiteral' => $type->config['parseLiteral'] ?? null,
135 42
            'extensionASTNodes' => static::getExtensionASTNodes($type),
136
        ]);
137
    }
138
139 45
    protected static function extendUnionType(UnionType $type) : UnionType
140
    {
141 45
        return new UnionType([
142 45
            'name' => $type->name,
143 45
            'description' => $type->description,
144
            'types' => static function () use ($type) {
145 44
                return static::extendPossibleTypes($type);
146 45
            },
147 45
            'astNode' => $type->astNode,
148 45
            'resolveType' => $type->config['resolveType'] ?? null,
149 45
            'extensionASTNodes' => static::getExtensionASTNodes($type),
150
        ]);
151
    }
152
153 43
    protected static function extendEnumType(EnumType $type) : EnumType
154
    {
155 43
        return new EnumType([
156 43
            'name' => $type->name,
157 43
            'description' => $type->description,
158 43
            'values' => static::extendValueMap($type),
159 42
            'astNode' => $type->astNode,
160 42
            'extensionASTNodes' => static::getExtensionASTNodes($type),
161
        ]);
162
    }
163
164 44
    protected static function extendInputObjectType(InputObjectType $type) : InputObjectType
165
    {
166 44
        return new InputObjectType([
167 44
            'name' => $type->name,
168 44
            'description' => $type->description,
169
            'fields' => static function () use ($type) {
170 44
                return static::extendInputFieldMap($type);
171 44
            },
172 44
            'astNode' => $type->astNode,
173 44
            'extensionASTNodes' => static::getExtensionASTNodes($type),
174
        ]);
175
    }
176
177
    /**
178
     * @return mixed[]
179
     */
180 44
    protected static function extendInputFieldMap(InputObjectType $type) : array
181
    {
182 44
        $newFieldMap = [];
183 44
        $oldFieldMap = $type->getFields();
184 44
        foreach ($oldFieldMap as $fieldName => $field) {
185 43
            $newFieldMap[$fieldName] = [
186 43
                'description' => $field->description,
187 43
                'type' => static::extendType($field->type),
188 43
                'astNode' => $field->astNode,
189
            ];
190
191 43
            if (! $field->defaultValueExists()) {
192 43
                continue;
193
            }
194
195
            $newFieldMap[$fieldName]['defaultValue'] = $field->defaultValue;
196
        }
197
198 44
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
199 44
        if ($extensions !== null) {
200 6
            foreach ($extensions as $extension) {
201 6
                foreach ($extension->fields as $field) {
202 5
                    $fieldName = $field->name->value;
203 5
                    if (isset($oldFieldMap[$fieldName])) {
204 1
                        throw new Error('Field "' . $type->name . '.' . $fieldName . '" already exists in the schema. It cannot also be defined in this type extension.', [$field]);
205
                    }
206
207 5
                    $newFieldMap[$fieldName] = static::$astBuilder->buildInputField($field);
208
                }
209
            }
210
        }
211
212 44
        return $newFieldMap;
213
    }
214
215
    /**
216
     * @return mixed[]
217
     */
218 43
    protected static function extendValueMap(EnumType $type) : array
219
    {
220 43
        $newValueMap = [];
221
        /** @var EnumValueDefinition[] $oldValueMap */
222 43
        $oldValueMap = [];
223 43
        foreach ($type->getValues() as $value) {
224 42
            $oldValueMap[$value->name] = $value;
225
        }
226
227 43
        foreach ($oldValueMap as $key => $value) {
228 42
            $newValueMap[$key] = [
229 42
                'name' => $value->name,
230 42
                'description' => $value->description,
231 42
                'value' => $value->value,
232 42
                'deprecationReason' => $value->deprecationReason,
233 42
                'astNode' => $value->astNode,
234
            ];
235
        }
236
237 43
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
238 43
        if ($extensions !== null) {
239 6
            foreach ($extensions as $extension) {
240 6
                foreach ($extension->values as $value) {
241 5
                    $valueName = $value->name->value;
242 5
                    if (isset($oldValueMap[$valueName])) {
243 1
                        throw new Error('Enum value "' . $type->name . '.' . $valueName . '" already exists in the schema. It cannot also be defined in this type extension.', [$value]);
244
                    }
245 5
                    $newValueMap[$valueName] = static::$astBuilder->buildEnumValue($value);
246
                }
247
            }
248
        }
249
250 42
        return $newValueMap;
251
    }
252
253
    /**
254
     * @return ObjectType[]
255
     */
256 44
    protected static function extendPossibleTypes(UnionType $type) : array
257
    {
258
        $possibleTypes = array_map(static function ($type) {
259 43
            return static::extendNamedType($type);
260 44
        }, $type->getTypes());
261
262 44
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
263 44
        if ($extensions !== null) {
264 8
            foreach ($extensions as $extension) {
265 8
                foreach ($extension->types as $namedType) {
266 8
                    $possibleTypes[] = static::$astBuilder->buildType($namedType);
267
                }
268
            }
269
        }
270
271 44
        return $possibleTypes;
272
    }
273
274
    /**
275
     * @return InterfaceType[]
276
     */
277 54
    protected static function extendImplementedInterfaces(ObjectType $type) : array
278
    {
279
        $interfaces = array_map(static function (InterfaceType $interfaceType) {
280 45
            return static::extendNamedType($interfaceType);
281 54
        }, $type->getInterfaces());
282
283 54
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
284 54
        if ($extensions !== null) {
285
            /** @var ObjectTypeExtensionNode $extension */
286 23
            foreach ($extensions as $extension) {
287 23
                foreach ($extension->interfaces as $namedType) {
288 23
                    $interfaces[] = static::$astBuilder->buildType($namedType);
289
                }
290
            }
291
        }
292
293 54
        return $interfaces;
294
    }
295
296 55
    protected static function extendType($typeDef)
297
    {
298 55
        if ($typeDef instanceof ListOfType) {
299 42
            return Type::listOf(static::extendType($typeDef->ofType));
300
        }
301
302 55
        if ($typeDef instanceof NonNull) {
303 55
            return Type::nonNull(static::extendType($typeDef->getWrappedType()));
0 ignored issues
show
Bug introduced by
It seems like static::extendType($typeDef->getWrappedType()) can also be of type GraphQL\Type\Definition\NonNull and GraphQL\Type\Definition\Type; however, parameter $wrappedType of GraphQL\Type\Definition\Type::nonNull() does only seem to accept GraphQL\Type\Definition\NullableType, 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

303
            return Type::nonNull(/** @scrutinizer ignore-type */ static::extendType($typeDef->getWrappedType()));
Loading history...
304
        }
305
306 55
        return static::extendNamedType($typeDef);
307
    }
308
309
    /**
310
     * @param FieldArgument[] $args
311
     *
312
     * @return mixed[]
313
     */
314 55
    protected static function extendArgs(array $args) : array
315
    {
316 55
        return Utils::keyValMap(
317 55
            $args,
318
            static function (FieldArgument $arg) {
319 55
                return $arg->name;
320 55
            },
321
            static function (FieldArgument $arg) {
322
                $def = [
323 55
                    'type'        => static::extendType($arg->getType()),
324 55
                    'description' => $arg->description,
325 55
                    'astNode'     => $arg->astNode,
326
                ];
327
328 55
                if ($arg->defaultValueExists()) {
329 54
                    $def['defaultValue'] = $arg->defaultValue;
330
                }
331
332 55
                return $def;
333 55
            }
334
        );
335
    }
336
337
    /**
338
     * @param InterfaceType|ObjectType $type
339
     *
340
     * @return mixed[]
341
     *
342
     * @throws Error
343
     */
344 54
    protected static function extendFieldMap($type) : array
345
    {
346 54
        $newFieldMap = [];
347 54
        $oldFieldMap = $type->getFields();
348
349 54
        foreach (array_keys($oldFieldMap) as $fieldName) {
350 54
            $field = $oldFieldMap[$fieldName];
351
352 54
            $newFieldMap[$fieldName] = [
353 54
                'name' => $fieldName,
354 54
                'description' => $field->description,
355 54
                'deprecationReason' => $field->deprecationReason,
356 54
                'type' => static::extendType($field->getType()),
357 54
                'args' => static::extendArgs($field->args),
358 54
                'astNode' => $field->astNode,
359 54
                'resolve' => $field->resolveFn,
360
            ];
361
        }
362
363 54
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
364 54
        if ($extensions !== null) {
365 25
            foreach ($extensions as $extension) {
366 25
                foreach ($extension->fields as $field) {
367 24
                    $fieldName = $field->name->value;
368 24
                    if (isset($oldFieldMap[$fieldName])) {
369 1
                        throw new Error('Field "' . $type->name . '.' . $fieldName . '" already exists in the schema. It cannot also be defined in this type extension.', [$field]);
370
                    }
371
372 24
                    $newFieldMap[$fieldName] = static::$astBuilder->buildField($field);
373
                }
374
            }
375
        }
376
377 54
        return $newFieldMap;
378
    }
379
380 58
    protected static function extendObjectType(ObjectType $type) : ObjectType
381
    {
382 58
        return new ObjectType([
383 58
            'name' => $type->name,
384 58
            'description' => $type->description,
385
            'interfaces' => static function () use ($type) {
386 54
                return static::extendImplementedInterfaces($type);
387 58
            },
388
            'fields' => static function () use ($type) {
389 54
                return static::extendFieldMap($type);
390 58
            },
391 58
            'astNode' => $type->astNode,
392 58
            'extensionASTNodes' => static::getExtensionASTNodes($type),
393 58
            'isTypeOf' => $type->config['isTypeOf'] ?? null,
394
        ]);
395
    }
396
397 46
    protected static function extendInterfaceType(InterfaceType $type) : InterfaceType
398
    {
399 46
        return new InterfaceType([
400 46
            'name' => $type->name,
401 46
            'description' => $type->description,
402
            'fields' => static function () use ($type) {
403 45
                return static::extendFieldMap($type);
404 46
            },
405 46
            'astNode' => $type->astNode,
406 46
            'extensionASTNodes' => static::getExtensionASTNodes($type),
407 46
            'resolveType' => $type->config['resolveType'] ?? null,
408
        ]);
409
    }
410
411 59
    protected static function isSpecifiedScalarType(Type $type) : bool
412
    {
413 59
        return $type instanceof NamedType &&
414
            (
415 59
                $type->name === Type::STRING ||
416 59
                $type->name === Type::INT ||
417 59
                $type->name === Type::FLOAT ||
418 59
                $type->name === Type::BOOLEAN ||
419 59
                $type->name === Type::ID
420
            );
421
    }
422
423 59
    protected static function extendNamedType(Type $type)
424
    {
425 59
        if (Introspection::isIntrospectionType($type) || static::isSpecifiedScalarType($type)) {
426 56
            return $type;
427
        }
428
429 59
        $name = $type->name;
430 59
        if (! isset(static::$extendTypeCache[$name])) {
431 59
            if ($type instanceof ScalarType) {
432 42
                static::$extendTypeCache[$name] = static::extendScalarType($type);
433 59
            } elseif ($type instanceof ObjectType) {
434 58
                static::$extendTypeCache[$name] = static::extendObjectType($type);
435 52
            } elseif ($type instanceof InterfaceType) {
436 46
                static::$extendTypeCache[$name] = static::extendInterfaceType($type);
437 49
            } elseif ($type instanceof UnionType) {
438 45
                static::$extendTypeCache[$name] = static::extendUnionType($type);
439 46
            } elseif ($type instanceof EnumType) {
440 43
                static::$extendTypeCache[$name] = static::extendEnumType($type);
441 44
            } elseif ($type instanceof InputObjectType) {
442 44
                static::$extendTypeCache[$name] = static::extendInputObjectType($type);
443
            }
444
        }
445
446 59
        return static::$extendTypeCache[$name];
447
    }
448
449
    /**
450
     * @return mixed|null
451
     */
452 59
    protected static function extendMaybeNamedType(?NamedType $type = null)
453
    {
454 59
        if ($type !== null) {
455 58
            return static::extendNamedType($type);
456
        }
457
458 58
        return null;
459
    }
460
461
    /**
462
     * @param DirectiveDefinitionNode[] $directiveDefinitions
463
     *
464
     * @return Directive[]
465
     */
466 55
    protected static function getMergedDirectives(Schema $schema, array $directiveDefinitions) : array
467
    {
468
        $existingDirectives = array_map(static function (Directive $directive) {
469 55
            return static::extendDirective($directive);
470 55
        }, $schema->getDirectives());
471
472 55
        Utils::invariant(count($existingDirectives) > 0, 'schema must have default directives');
473
474 55
        return array_merge(
475 55
            $existingDirectives,
476
            array_map(static function (DirectiveDefinitionNode $directive) {
477 9
                return static::$astBuilder->buildDirective($directive);
478 55
            }, $directiveDefinitions)
479
        );
480
    }
481
482 55
    protected static function extendDirective(Directive $directive) : Directive
483
    {
484 55
        return new Directive([
485 55
            'name' => $directive->name,
486 55
            'description' => $directive->description,
487 55
            'locations' => $directive->locations,
488 55
            'args' => static::extendArgs($directive->args),
489 55
            'astNode' => $directive->astNode,
490
        ]);
491
    }
492
493
    /**
494
     * @param mixed[]|null $options
495
     */
496 65
    public static function extend(Schema $schema, DocumentNode $documentAST, ?array $options = null) : Schema
497
    {
498 65
        if ($options === null || ! (isset($options['assumeValid']) || isset($options['assumeValidSDL']))) {
499 64
            DocumentValidator::assertValidSDLExtension($documentAST, $schema);
500
        }
501
502 64
        $typeDefinitionMap         = [];
503 64
        static::$typeExtensionsMap = [];
504 64
        $directiveDefinitions      = [];
505
        /** @var SchemaDefinitionNode|null $schemaDef */
506 64
        $schemaDef = null;
507
        /** @var SchemaTypeExtensionNode[] $schemaExtensions */
508 64
        $schemaExtensions = [];
509
510 64
        $definitionsCount = count($documentAST->definitions);
511 64
        for ($i = 0; $i < $definitionsCount; $i++) {
512
513
            /** @var Node $def */
514 64
            $def = $documentAST->definitions[$i];
515
516 64
            if ($def instanceof SchemaDefinitionNode) {
517 1
                $schemaDef = $def;
518 63
            } elseif ($def instanceof SchemaTypeExtensionNode) {
519 9
                $schemaExtensions[] = $def;
520 61
            } elseif ($def instanceof TypeDefinitionNode) {
521 21
                $typeName = isset($def->name) ? $def->name->value : null;
522
523
                try {
524 21
                    $type = $schema->getType($typeName);
525 2
                } catch (Error $error) {
526 2
                    $type = null;
527
                }
528
529 21
                if ($type) {
530 1
                    throw new Error('Type "' . $typeName . '" already exists in the schema. It cannot also be defined in this type definition.', [$def]);
531
                }
532 20
                $typeDefinitionMap[$typeName] = $def;
533 46
            } elseif ($def instanceof TypeExtensionNode) {
534 39
                $extendedTypeName = isset($def->name) ? $def->name->value : null;
535 39
                $existingType     = $schema->getType($extendedTypeName);
536 39
                if ($existingType === null) {
537 1
                    throw new Error('Cannot extend type "' . $extendedTypeName . '" because it does not exist in the existing schema.', [$def]);
538
                }
539
540 38
                static::checkExtensionNode($existingType, $def);
541
542 37
                $existingTypeExtensions                       = static::$typeExtensionsMap[$extendedTypeName] ?? null;
543 37
                static::$typeExtensionsMap[$extendedTypeName] = $existingTypeExtensions !== null ? array_merge($existingTypeExtensions, [$def]) : [$def];
544 11
            } elseif ($def instanceof DirectiveDefinitionNode) {
545 10
                $directiveName     = $def->name->value;
546 10
                $existingDirective = $schema->getDirective($directiveName);
547 10
                if ($existingDirective !== null) {
548 2
                    throw new Error('Directive "' . $directiveName . '" already exists in the schema. It cannot be redefined.', [$def]);
549
                }
550 9
                $directiveDefinitions[] = $def;
551
            }
552
        }
553
554 60
        if (count(static::$typeExtensionsMap) === 0 &&
555 60
            count($typeDefinitionMap) === 0 &&
556 60
            count($directiveDefinitions) === 0 &&
557 60
            count($schemaExtensions) === 0 &&
558 60
            $schemaDef === null
559
        ) {
560 1
            return $schema;
561
        }
562
563 59
        static::$astBuilder = new ASTDefinitionBuilder(
564 59
            $typeDefinitionMap,
565 59
            $options,
566
            static function (string $typeName) use ($schema) {
567
                /** @var ScalarType|ObjectType|InterfaceType|UnionType|EnumType|InputObjectType $existingType */
568 12
                $existingType = $schema->getType($typeName);
569 12
                if ($existingType !== null) {
570 11
                    return static::extendNamedType($existingType);
571
                }
572
573 1
                throw new Error('Unknown type: "' . $typeName . '". Ensure that this type exists either in the original schema, or is added in a type definition.', [$typeName]);
574 59
            }
575
        );
576
577 59
        static::$extendTypeCache = [];
578
579
        $operationTypes = [
580 59
            'query' => static::extendMaybeNamedType($schema->getQueryType()),
581 59
            'mutation' => static::extendMaybeNamedType($schema->getMutationType()),
582 59
            'subscription' => static::extendMaybeNamedType($schema->getSubscriptionType()),
583
        ];
584
585 59
        if ($schemaDef) {
586 1
            foreach ($schemaDef->operationTypes as $operationType) {
587 1
                $operation = $operationType->operation;
588 1
                $type      = $operationType->type;
589
590 1
                if (isset($operationTypes[$operation])) {
591
                    throw new Error('Must provide only one ' . $operation . ' type in schema.');
592
                }
593
594 1
                $operationTypes[$operation] = static::$astBuilder->buildType($type);
595
            }
596
        }
597
598 59
        foreach ($schemaExtensions as $schemaExtension) {
599 9
            if (! $schemaExtension->operationTypes) {
600 2
                continue;
601
            }
602
603 8
            foreach ($schemaExtension->operationTypes as $operationType) {
604 8
                $operation = $operationType->operation;
605 8
                if (isset($operationTypes[$operation])) {
606 3
                    throw new Error('Must provide only one ' . $operation . ' type in schema.');
607
                }
608 7
                $operationTypes[$operation] = static::$astBuilder->buildType($operationType->type);
609
            }
610
        }
611
612 56
        $schemaExtensionASTNodes = count($schemaExtensions) > 0
613 6
            ? ($schema->extensionASTNodes
614 2
                ? array_merge($schema->extensionASTNodes, $schemaExtensions)
615 6
                : $schemaExtensions)
616 56
            : $schema->extensionASTNodes;
617
618 56
        $types = array_merge(
619
            // Iterate through all types, getting the type definition for each, ensuring
620
            // that any type not directly referenced by a field will get created.
621
            array_map(static function ($type) {
622 56
                return static::extendNamedType($type);
623 56
            }, array_values($schema->getTypeMap())),
624
            // Do the same with new types.
625
            array_map(static function ($type) {
626 17
                return static::$astBuilder->buildType($type);
627 55
            }, array_values($typeDefinitionMap))
628
        );
629
630 55
        return new Schema([
631 55
            'query' => $operationTypes['query'],
632 55
            'mutation' => $operationTypes['mutation'],
633 55
            'subscription' => $operationTypes['subscription'],
634 55
            'types' => $types,
635 55
            'directives' => static::getMergedDirectives($schema, $directiveDefinitions),
636 55
            'astNode' => $schema->getAstNode(),
637 55
            'extensionASTNodes' => $schemaExtensionASTNodes,
638
        ]);
639
    }
640
}
641