Completed
Push — master ( c9c830...8d8462 )
by Vladimir
89:58 queued 86:21
created

SchemaExtender::extendInputFieldMap()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 7.0061

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 19
c 1
b 0
f 0
dl 0
loc 33
rs 8.8333
ccs 19
cts 20
cp 0.95
cc 7
nc 9
nop 1
crap 7.0061
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 49
    protected static function getExtensionASTNodes(NamedType $type) : ?array
60
    {
61 49
        if (! $type instanceof Type) {
62
            return null;
63
        }
64
65 49
        $name = $type->name;
66 49
        if ($type->extensionASTNodes !== null) {
67 49
            if (isset(static::$typeExtensionsMap[$name])) {
68 19
                return array_merge($type->extensionASTNodes, static::$typeExtensionsMap[$name]);
69
            }
70
71 47
            return $type->extensionASTNodes;
72
        }
73
74 43
        return static::$typeExtensionsMap[$name] ?? null;
75
    }
76
77
    /**
78
     * @throws Error
79
     */
80 29
    protected static function checkExtensionNode(Type $type, Node $node) : void
81
    {
82
        switch (true) {
83 29
            case $node instanceof ObjectTypeExtensionNode:
84 20
                if (! ($type instanceof ObjectType)) {
85 1
                    throw new Error(
86 1
                        'Cannot extend non-object type "' . $type->name . '".',
87 1
                        [$node]
88
                    );
89
                }
90 19
                break;
91 15
            case $node instanceof InterfaceTypeExtensionNode:
92 7
                if (! ($type instanceof InterfaceType)) {
93 1
                    throw new Error(
94 1
                        'Cannot extend non-interface type "' . $type->name . '".',
95 1
                        [$node]
96
                    );
97
                }
98 6
                break;
99 12
            case $node instanceof EnumTypeExtensionNode:
100 6
                if (! ($type instanceof EnumType)) {
101 1
                    throw new Error(
102 1
                        'Cannot extend non-enum type "' . $type->name . '".',
103 1
                        [$node]
104
                    );
105
                }
106 5
                break;
107 9
            case $node instanceof UnionTypeExtensionNode:
108 6
                if (! ($type instanceof UnionType)) {
109 1
                    throw new Error(
110 1
                        'Cannot extend non-union type "' . $type->name . '".',
111 1
                        [$node]
112
                    );
113
                }
114 5
                break;
115 7
            case $node instanceof InputObjectTypeExtensionNode:
116 6
                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 5
                break;
123
        }
124 28
    }
125
126 42
    protected static function extendCustomScalarType(CustomScalarType $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 42
    protected static function extendUnionType(UnionType $type) : UnionType
140
    {
141 42
        return new UnionType([
142 42
            'name' => $type->name,
143 42
            'description' => $type->description,
144
            'types' => static function () use ($type) {
145 41
                return static::extendPossibleTypes($type);
146 42
            },
147 42
            'astNode' => $type->astNode,
148 42
            'resolveType' => $type->config['resolveType'] ?? null,
149 42
            'extensionASTNodes' => static::getExtensionASTNodes($type),
150
        ]);
151
    }
152
153 42
    protected static function extendEnumType(EnumType $type) : EnumType
154
    {
155 42
        return new EnumType([
156 42
            'name' => $type->name,
157 42
            'description' => $type->description,
158 42
            'values' => static::extendValueMap($type),
159 41
            'astNode' => $type->astNode,
160 41
            'extensionASTNodes' => static::getExtensionASTNodes($type),
161
        ]);
162
    }
163
164 42
    protected static function extendInputObjectType(InputObjectType $type) : InputObjectType
165
    {
166 42
        return new InputObjectType([
167 42
            'name' => $type->name,
168 42
            'description' => $type->description,
169
            'fields' => static function () use ($type) {
170 42
                return static::extendInputFieldMap($type);
171 42
            },
172 42
            'astNode' => $type->astNode,
173 42
            'extensionASTNodes' => static::getExtensionASTNodes($type),
174
        ]);
175
    }
176
177
    /**
178
     * @return mixed[]
179
     */
180 42
    protected static function extendInputFieldMap(InputObjectType $type) : array
181
    {
182 42
        $newFieldMap = [];
183 42
        $oldFieldMap = $type->getFields();
184 42
        foreach ($oldFieldMap as $fieldName => $field) {
185 42
            $newFieldMap[$fieldName] = [
186 42
                'description' => $field->description,
187 42
                'type' => static::extendType($field->type),
188 42
                'astNode' => $field->astNode,
189
            ];
190
191 42
            if (! $field->defaultValueExists()) {
192 42
                continue;
193
            }
194
195
            $newFieldMap[$fieldName]['defaultValue'] = $field->defaultValue;
196
        }
197
198 42
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
199 42
        if ($extensions !== null) {
200 5
            foreach ($extensions as $extension) {
201 5
                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 4
                    $newFieldMap[$fieldName] = static::$astBuilder->buildInputField($field);
208
                }
209
            }
210
        }
211
212 42
        return $newFieldMap;
213
    }
214
215
    /**
216
     * @return mixed[]
217
     */
218 42
    protected static function extendValueMap(EnumType $type) : array
219
    {
220 42
        $newValueMap = [];
221
        /** @var EnumValueDefinition[] $oldValueMap */
222 42
        $oldValueMap = [];
223 42
        foreach ($type->getValues() as $value) {
224 42
            $oldValueMap[$value->name] = $value;
225
        }
226
227 42
        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 42
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
238 42
        if ($extensions !== null) {
239 5
            foreach ($extensions as $extension) {
240 5
                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 4
                    $newValueMap[$valueName] = static::$astBuilder->buildEnumValue($value);
246
                }
247
            }
248
        }
249
250 41
        return $newValueMap;
251
    }
252
253
    /**
254
     * @return ObjectType[]
255
     */
256 41
    protected static function extendPossibleTypes(UnionType $type) : array
257
    {
258
        $possibleTypes = array_map(static function ($type) {
259 41
            return static::extendNamedType($type);
260 41
        }, $type->getTypes());
261
262 41
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
263 41
        if ($extensions !== null) {
264 5
            foreach ($extensions as $extension) {
265 5
                foreach ($extension->types as $namedType) {
266 5
                    $possibleTypes[] = static::$astBuilder->buildType($namedType);
267
                }
268
            }
269
        }
270
271 41
        return $possibleTypes;
272
    }
273
274
    /**
275
     * @return InterfaceType[]
276
     */
277 45
    protected static function extendImplementedInterfaces(ObjectType $type) : array
278
    {
279
        $interfaces = array_map(static function (InterfaceType $interfaceType) {
280 42
            return static::extendNamedType($interfaceType);
281 45
        }, $type->getInterfaces());
282
283 45
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
284 45
        if ($extensions !== null) {
285
            /** @var ObjectTypeExtensionNode $extension */
286 19
            foreach ($extensions as $extension) {
287 19
                foreach ($extension->interfaces as $namedType) {
288 19
                    $interfaces[] = static::$astBuilder->buildType($namedType);
289
                }
290
            }
291
        }
292
293 45
        return $interfaces;
294
    }
295
296 46
    protected static function extendType($typeDef)
297
    {
298 46
        if ($typeDef instanceof ListOfType) {
299 42
            return Type::listOf(static::extendType($typeDef->ofType));
300
        }
301
302 46
        if ($typeDef instanceof NonNull) {
303 45
            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 46
        return static::extendNamedType($typeDef);
307
    }
308
309
    /**
310
     * @param FieldArgument[] $args
311
     *
312
     * @return mixed[]
313
     */
314 45
    protected static function extendArgs(array $args) : array
315
    {
316 45
        return Utils::keyValMap(
317 45
            $args,
318
            static function (FieldArgument $arg) {
319 45
                return $arg->name;
320 45
            },
321
            static function (FieldArgument $arg) {
322
                $def = [
323 45
                    'type'        => static::extendType($arg->getType()),
324 45
                    'description' => $arg->description,
325 45
                    'astNode'     => $arg->astNode,
326
                ];
327
328 45
                if ($arg->defaultValueExists()) {
329 44
                    $def['defaultValue'] = $arg->defaultValue;
330
                }
331
332 45
                return $def;
333 45
            }
334
        );
335
    }
336
337
    /**
338
     * @param InterfaceType|ObjectType $type
339
     *
340
     * @return mixed[]
341
     *
342
     * @throws Error
343
     */
344 45
    protected static function extendFieldMap($type) : array
345
    {
346 45
        $newFieldMap = [];
347 45
        $oldFieldMap = $type->getFields();
348
349 45
        foreach (array_keys($oldFieldMap) as $fieldName) {
350 45
            $field = $oldFieldMap[$fieldName];
351
352 45
            $newFieldMap[$fieldName] = [
353 45
                'name' => $fieldName,
354 45
                'description' => $field->description,
355 45
                'deprecationReason' => $field->deprecationReason,
356 45
                'type' => static::extendType($field->getType()),
357 45
                'args' => static::extendArgs($field->args),
358 45
                'astNode' => $field->astNode,
359 45
                'resolve' => $field->resolveFn,
360
            ];
361
        }
362
363 45
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
364 45
        if ($extensions !== null) {
365 21
            foreach ($extensions as $extension) {
366 21
                foreach ($extension->fields as $field) {
367 21
                    $fieldName = $field->name->value;
368 21
                    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 20
                    $newFieldMap[$fieldName] = static::$astBuilder->buildField($field);
373
                }
374
            }
375
        }
376
377 45
        return $newFieldMap;
378
    }
379
380 49
    protected static function extendObjectType(ObjectType $type) : ObjectType
381
    {
382 49
        return new ObjectType([
383 49
            'name' => $type->name,
384 49
            'description' => $type->description,
385
            'interfaces' => static function () use ($type) {
386 45
                return static::extendImplementedInterfaces($type);
387 49
            },
388
            'fields' => static function () use ($type) {
389 45
                return static::extendFieldMap($type);
390 49
            },
391 49
            'astNode' => $type->astNode,
392 49
            'extensionASTNodes' => static::getExtensionASTNodes($type),
393 49
            'isTypeOf' => $type->config['isTypeOf'] ?? null,
394
        ]);
395
    }
396
397 43
    protected static function extendInterfaceType(InterfaceType $type) : InterfaceType
398
    {
399 43
        return new InterfaceType([
400 43
            'name' => $type->name,
401 43
            'description' => $type->description,
402
            'fields' => static function () use ($type) {
403 42
                return static::extendFieldMap($type);
404 43
            },
405 43
            'astNode' => $type->astNode,
406 43
            'extensionASTNodes' => static::getExtensionASTNodes($type),
407 43
            'resolveType' => $type->config['resolveType'] ?? null,
408
        ]);
409
    }
410
411 49
    protected static function isSpecifiedScalarType(Type $type) : bool
412
    {
413 49
        return $type instanceof NamedType &&
414
            (
415 49
                $type->name === Type::STRING ||
416 49
                $type->name === Type::INT ||
417 49
                $type->name === Type::FLOAT ||
418 49
                $type->name === Type::BOOLEAN ||
419 49
                $type->name === Type::ID
420
            );
421
    }
422
423 49
    protected static function extendNamedType(Type $type)
424
    {
425 49
        if (Introspection::isIntrospectionType($type) || static::isSpecifiedScalarType($type)) {
426 46
            return $type;
427
        }
428
429 49
        $name = $type->name;
430 49
        if (! isset(static::$extendTypeCache[$name])) {
431 49
            if ($type instanceof CustomScalarType) {
432 42
                static::$extendTypeCache[$name] = static::extendCustomScalarType($type);
433 49
            } elseif ($type instanceof ObjectType) {
434 49
                static::$extendTypeCache[$name] = static::extendObjectType($type);
435 43
            } elseif ($type instanceof InterfaceType) {
436 43
                static::$extendTypeCache[$name] = static::extendInterfaceType($type);
437 43
            } elseif ($type instanceof UnionType) {
438 42
                static::$extendTypeCache[$name] = static::extendUnionType($type);
439 43
            } elseif ($type instanceof EnumType) {
440 42
                static::$extendTypeCache[$name] = static::extendEnumType($type);
441 42
            } elseif ($type instanceof InputObjectType) {
442 42
                static::$extendTypeCache[$name] = static::extendInputObjectType($type);
443
            }
444
        }
445
446 49
        return static::$extendTypeCache[$name];
447
    }
448
449
    /**
450
     * @return mixed|null
451
     */
452 49
    protected static function extendMaybeNamedType(?NamedType $type = null)
453
    {
454 49
        if ($type !== null) {
455 48
            return static::extendNamedType($type);
456
        }
457
458 48
        return null;
459
    }
460
461
    /**
462
     * @param DirectiveDefinitionNode[] $directiveDefinitions
463
     *
464
     * @return Directive[]
465
     */
466 45
    protected static function getMergedDirectives(Schema $schema, array $directiveDefinitions) : array
467
    {
468
        $existingDirectives = array_map(static function (Directive $directive) {
469 45
            return static::extendDirective($directive);
470 45
        }, $schema->getDirectives());
471
472 45
        Utils::invariant(count($existingDirectives) > 0, 'schema must have default directives');
473
474 45
        return array_merge(
475 45
            $existingDirectives,
476
            array_map(static function (DirectiveDefinitionNode $directive) {
477 6
                return static::$astBuilder->buildDirective($directive);
478 45
            }, $directiveDefinitions)
479
        );
480
    }
481
482 45
    protected static function extendDirective(Directive $directive) : Directive
483
    {
484 45
        return new Directive([
485 45
            'name' => $directive->name,
486 45
            'description' => $directive->description,
487 45
            'locations' => $directive->locations,
488 45
            'args' => static::extendArgs($directive->args),
489 45
            'astNode' => $directive->astNode,
490
        ]);
491
    }
492
493
    /**
494
     * @param mixed[]|null $options
495
     */
496 55
    public static function extend(Schema $schema, DocumentNode $documentAST, ?array $options = null) : Schema
497
    {
498 55
        if ($options === null || ! (isset($options['assumeValid']) || isset($options['assumeValidSDL']))) {
499 54
            DocumentValidator::assertValidSDLExtension($documentAST, $schema);
500
        }
501
502 54
        $typeDefinitionMap         = [];
503 54
        static::$typeExtensionsMap = [];
504 54
        $directiveDefinitions      = [];
505
        /** @var SchemaDefinitionNode|null $schemaDef */
506 54
        $schemaDef = null;
507
        /** @var SchemaTypeExtensionNode[] $schemaExtensions */
508 54
        $schemaExtensions = [];
509
510 54
        $definitionsCount = count($documentAST->definitions);
511 54
        for ($i = 0; $i < $definitionsCount; $i++) {
512
513
            /** @var Node $def */
514 54
            $def = $documentAST->definitions[$i];
515
516 54
            if ($def instanceof SchemaDefinitionNode) {
517 1
                $schemaDef = $def;
518 53
            } elseif ($def instanceof SchemaTypeExtensionNode) {
519 8
                $schemaExtensions[] = $def;
520 52
            } elseif ($def instanceof TypeDefinitionNode) {
521 20
                $typeName = isset($def->name) ? $def->name->value : null;
522
523
                try {
524 20
                    $type = $schema->getType($typeName);
525 1
                } catch (Error $error) {
526 1
                    $type = null;
527
                }
528
529 20
                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 19
                $typeDefinitionMap[$typeName] = $def;
533 37
            } elseif ($def instanceof TypeExtensionNode) {
534 30
                $extendedTypeName = isset($def->name) ? $def->name->value : null;
535 30
                $existingType     = $schema->getType($extendedTypeName);
536 30
                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 29
                static::checkExtensionNode($existingType, $def);
541
542 28
                $existingTypeExtensions                       = static::$typeExtensionsMap[$extendedTypeName] ?? null;
543 28
                static::$typeExtensionsMap[$extendedTypeName] = $existingTypeExtensions !== null ? array_merge($existingTypeExtensions, [$def]) : [$def];
544 8
            } elseif ($def instanceof DirectiveDefinitionNode) {
545 7
                $directiveName     = $def->name->value;
546 7
                $existingDirective = $schema->getDirective($directiveName);
547 7
                if ($existingDirective !== null) {
548 2
                    throw new Error('Directive "' . $directiveName . '" already exists in the schema. It cannot be redefined.', [$def]);
549
                }
550 6
                $directiveDefinitions[] = $def;
551
            }
552
        }
553
554 50
        if (count(static::$typeExtensionsMap) === 0 &&
555 50
            count($typeDefinitionMap) === 0 &&
556 50
            count($directiveDefinitions) === 0 &&
557 50
            count($schemaExtensions) === 0 &&
558 50
            $schemaDef === null
559
        ) {
560 1
            return $schema;
561
        }
562
563 49
        static::$astBuilder = new ASTDefinitionBuilder(
564 49
            $typeDefinitionMap,
565 49
            $options,
566
            static function (string $typeName) use ($schema) {
567
                /** @var ScalarType|ObjectType|InterfaceType|UnionType|EnumType|InputObjectType $existingType */
568 10
                $existingType = $schema->getType($typeName);
569 10
                if ($existingType !== null) {
570 9
                    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 49
            }
575
        );
576
577 49
        static::$extendTypeCache = [];
578
579
        $operationTypes = [
580 49
            'query' => static::extendMaybeNamedType($schema->getQueryType()),
581 49
            'mutation' => static::extendMaybeNamedType($schema->getMutationType()),
582 49
            'subscription' => static::extendMaybeNamedType($schema->getSubscriptionType()),
583
        ];
584
585 49
        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 49
        foreach ($schemaExtensions as $schemaExtension) {
599 8
            if (! $schemaExtension->operationTypes) {
600 2
                continue;
601
            }
602
603 7
            foreach ($schemaExtension->operationTypes as $operationType) {
604 7
                $operation = $operationType->operation;
605 7
                if (isset($operationTypes[$operation])) {
606 3
                    throw new Error('Must provide only one ' . $operation . ' type in schema.');
607
                }
608 6
                $operationTypes[$operation] = static::$astBuilder->buildType($operationType->type);
609
            }
610
        }
611
612 46
        $schemaExtensionASTNodes = count($schemaExtensions) > 0
613 5
            ? ($schema->extensionASTNodes
614 1
                ? array_merge($schema->extensionASTNodes, $schemaExtensions)
615 5
                : $schemaExtensions)
616 46
            : $schema->extensionASTNodes;
617
618 46
        $types = array_merge(
619
            array_map(static function ($type) {
620 46
                return static::extendType($type);
621 46
            }, array_values($schema->getTypeMap())),
622
            array_map(static function ($type) {
623 16
                return static::$astBuilder->buildType($type);
624 45
            }, array_values($typeDefinitionMap))
625
        );
626
627 45
        return new Schema([
628 45
            'query' => $operationTypes['query'],
629 45
            'mutation' => $operationTypes['mutation'],
630 45
            'subscription' => $operationTypes['subscription'],
631 45
            'types' => $types,
632 45
            'directives' => static::getMergedDirectives($schema, $directiveDefinitions),
633 45
            'astNode' => $schema->getAstNode(),
634 45
            'extensionASTNodes' => $schemaExtensionASTNodes,
635
        ]);
636
    }
637
}
638