FieldsBuilder::convertType()   B
last analyzed

Complexity

Conditions 11
Paths 30

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 13
c 1
b 0
f 0
nc 30
nop 9
dl 0
loc 25
rs 7.3166

How to fix   Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\GraphQl\Type;
15
16
use ApiPlatform\Core\DataProvider\Pagination;
17
use ApiPlatform\Core\Exception\ResourceClassNotFoundException;
18
use ApiPlatform\Core\GraphQl\Resolver\Factory\ResolverFactoryInterface;
19
use ApiPlatform\Core\GraphQl\Type\Definition\TypeInterface;
20
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
21
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
22
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
23
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
24
use Doctrine\Common\Inflector\Inflector;
25
use GraphQL\Type\Definition\InputObjectType;
26
use GraphQL\Type\Definition\NullableType;
27
use GraphQL\Type\Definition\Type as GraphQLType;
28
use GraphQL\Type\Definition\WrappingType;
29
use Psr\Container\ContainerInterface;
30
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
31
use Symfony\Component\PropertyInfo\Type;
32
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
33
34
/**
35
 * Builds the GraphQL fields.
36
 *
37
 * @experimental
38
 *
39
 * @author Alan Poulain <[email protected]>
40
 */
41
final class FieldsBuilder implements FieldsBuilderInterface
42
{
43
    private $propertyNameCollectionFactory;
44
    private $propertyMetadataFactory;
45
    private $resourceMetadataFactory;
46
    private $typesContainer;
47
    private $typeBuilder;
48
    private $typeConverter;
49
    private $itemResolverFactory;
50
    private $collectionResolverFactory;
51
    private $itemMutationResolverFactory;
52
    private $itemSubscriptionResolverFactory;
53
    private $filterLocator;
54
    private $pagination;
55
    private $nameConverter;
56
    private $nestingSeparator;
57
58
    public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, TypesContainerInterface $typesContainer, TypeBuilderInterface $typeBuilder, TypeConverterInterface $typeConverter, ResolverFactoryInterface $itemResolverFactory, ResolverFactoryInterface $collectionResolverFactory, ResolverFactoryInterface $itemMutationResolverFactory, ResolverFactoryInterface $itemSubscriptionResolverFactory, ContainerInterface $filterLocator, Pagination $pagination, ?NameConverterInterface $nameConverter, string $nestingSeparator)
59
    {
60
        $this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
61
        $this->propertyMetadataFactory = $propertyMetadataFactory;
62
        $this->resourceMetadataFactory = $resourceMetadataFactory;
63
        $this->typesContainer = $typesContainer;
64
        $this->typeBuilder = $typeBuilder;
65
        $this->typeConverter = $typeConverter;
66
        $this->itemResolverFactory = $itemResolverFactory;
67
        $this->collectionResolverFactory = $collectionResolverFactory;
68
        $this->itemMutationResolverFactory = $itemMutationResolverFactory;
69
        $this->itemSubscriptionResolverFactory = $itemSubscriptionResolverFactory;
70
        $this->filterLocator = $filterLocator;
71
        $this->pagination = $pagination;
72
        $this->nameConverter = $nameConverter;
73
        $this->nestingSeparator = $nestingSeparator;
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function getNodeQueryFields(): array
80
    {
81
        return [
82
            'type' => $this->typeBuilder->getNodeInterface(),
83
            'args' => [
84
                'id' => ['type' => GraphQLType::nonNull(GraphQLType::id())],
85
            ],
86
            'resolve' => ($this->itemResolverFactory)(),
87
        ];
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function getItemQueryFields(string $resourceClass, ResourceMetadata $resourceMetadata, string $queryName, array $configuration): array
94
    {
95
        $shortName = $resourceMetadata->getShortName();
96
        $fieldName = lcfirst('item_query' === $queryName ? $shortName : $queryName.$shortName);
97
98
        $deprecationReason = (string) $resourceMetadata->getGraphqlAttribute($queryName, 'deprecation_reason', '', true);
99
100
        if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, null, $deprecationReason, new Type(Type::BUILTIN_TYPE_OBJECT, true, $resourceClass), $resourceClass, false, $queryName, null, null)) {
101
            $args = $this->resolveResourceArgs($configuration['args'] ?? [], $queryName, $shortName);
0 ignored issues
show
Bug introduced by
It seems like $shortName can also be of type null; however, parameter $shortName of ApiPlatform\Core\GraphQl...::resolveResourceArgs() does only seem to accept string, 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

101
            $args = $this->resolveResourceArgs($configuration['args'] ?? [], $queryName, /** @scrutinizer ignore-type */ $shortName);
Loading history...
102
            $configuration['args'] = $args ?: $configuration['args'] ?? ['id' => ['type' => GraphQLType::nonNull(GraphQLType::id())]];
103
104
            return [$fieldName => array_merge($fieldConfiguration, $configuration)];
105
        }
106
107
        return [];
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function getCollectionQueryFields(string $resourceClass, ResourceMetadata $resourceMetadata, string $queryName, array $configuration): array
114
    {
115
        $shortName = $resourceMetadata->getShortName();
116
        $fieldName = lcfirst('collection_query' === $queryName ? $shortName : $queryName.$shortName);
117
118
        $deprecationReason = (string) $resourceMetadata->getGraphqlAttribute($queryName, 'deprecation_reason', '', true);
119
120
        if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, null, $deprecationReason, new Type(Type::BUILTIN_TYPE_OBJECT, false, null, true, null, new Type(Type::BUILTIN_TYPE_OBJECT, false, $resourceClass)), $resourceClass, false, $queryName, null, null)) {
121
            $args = $this->resolveResourceArgs($configuration['args'] ?? [], $queryName, $shortName);
0 ignored issues
show
Bug introduced by
It seems like $shortName can also be of type null; however, parameter $shortName of ApiPlatform\Core\GraphQl...::resolveResourceArgs() does only seem to accept string, 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

121
            $args = $this->resolveResourceArgs($configuration['args'] ?? [], $queryName, /** @scrutinizer ignore-type */ $shortName);
Loading history...
122
            $configuration['args'] = $args ?: $configuration['args'] ?? $fieldConfiguration['args'];
123
124
            return [Inflector::pluralize($fieldName) => array_merge($fieldConfiguration, $configuration)];
125
        }
126
127
        return [];
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    public function getMutationFields(string $resourceClass, ResourceMetadata $resourceMetadata, string $mutationName): array
134
    {
135
        $mutationFields = [];
136
        $shortName = $resourceMetadata->getShortName();
137
        $resourceType = new Type(Type::BUILTIN_TYPE_OBJECT, true, $resourceClass);
138
        $deprecationReason = $resourceMetadata->getGraphqlAttribute($mutationName, 'deprecation_reason', '', true);
139
140
        if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, ucfirst("{$mutationName}s a $shortName."), $deprecationReason, $resourceType, $resourceClass, false, null, $mutationName, null)) {
141
            $fieldConfiguration['args'] += ['input' => $this->getResourceFieldConfiguration(null, null, $deprecationReason, $resourceType, $resourceClass, true, null, $mutationName, null)];
142
        }
143
144
        $mutationFields[$mutationName.$resourceMetadata->getShortName()] = $fieldConfiguration ?? [];
145
146
        return $mutationFields;
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    public function getSubscriptionFields(string $resourceClass, ResourceMetadata $resourceMetadata, string $subscriptionName): array
153
    {
154
        $subscriptionFields = [];
155
        $shortName = $resourceMetadata->getShortName();
156
        $resourceType = new Type(Type::BUILTIN_TYPE_OBJECT, true, $resourceClass);
157
        $deprecationReason = $resourceMetadata->getGraphqlAttribute($subscriptionName, 'deprecation_reason', '', true);
158
159
        if ($fieldConfiguration = $this->getResourceFieldConfiguration(null, "Subscribes to the $subscriptionName event of a $shortName.", $deprecationReason, $resourceType, $resourceClass, false, null, null, $subscriptionName)) {
160
            $fieldConfiguration['args'] += ['input' => $this->getResourceFieldConfiguration(null, null, $deprecationReason, $resourceType, $resourceClass, true, null, null, $subscriptionName)];
161
        }
162
163
        if (!$fieldConfiguration) {
164
            return [];
165
        }
166
167
        $subscriptionFields[$subscriptionName.$resourceMetadata->getShortName().'Subscribe'] = $fieldConfiguration;
168
169
        return $subscriptionFields;
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function getResourceObjectTypeFields(?string $resourceClass, ResourceMetadata $resourceMetadata, bool $input, ?string $queryName, ?string $mutationName, ?string $subscriptionName, int $depth = 0, ?array $ioMetadata = null): array
176
    {
177
        $fields = [];
178
        $idField = ['type' => GraphQLType::nonNull(GraphQLType::id())];
179
        $clientMutationId = GraphQLType::string();
180
        $clientSubscriptionId = GraphQLType::string();
181
182
        if (null !== $ioMetadata && \array_key_exists('class', $ioMetadata) && null === $ioMetadata['class']) {
183
            if ($input) {
184
                return ['clientMutationId' => $clientMutationId];
185
            }
186
187
            return [];
188
        }
189
190
        if (null !== $subscriptionName && $input) {
191
            return [
192
                'id' => $idField,
193
                'clientSubscriptionId' => $clientSubscriptionId,
194
            ];
195
        }
196
197
        if ('delete' === $mutationName) {
198
            $fields = [
199
                'id' => $idField,
200
            ];
201
202
            if ($input) {
203
                $fields['clientMutationId'] = $clientMutationId;
204
            }
205
206
            return $fields;
207
        }
208
209
        if (!$input || 'create' !== $mutationName) {
210
            $fields['id'] = $idField;
211
        }
212
213
        ++$depth; // increment the depth for the call to getResourceFieldConfiguration.
214
215
        if (null !== $resourceClass) {
216
            foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $property) {
217
                $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $property, ['graphql_operation_name' => $subscriptionName ?? $mutationName ?? $queryName]);
218
                if (
219
                    null === ($propertyType = $propertyMetadata->getType())
220
                    || (!$input && false === $propertyMetadata->isReadable())
221
                    || ($input && null !== $mutationName && false === $propertyMetadata->isWritable())
222
                ) {
223
                    continue;
224
                }
225
226
                if ($fieldConfiguration = $this->getResourceFieldConfiguration($property, $propertyMetadata->getDescription(), $propertyMetadata->getAttribute('deprecation_reason', ''), $propertyType, $resourceClass, $input, $queryName, $mutationName, $subscriptionName, $depth)) {
227
                    $fields['id' === $property ? '_id' : $this->normalizePropertyName($property)] = $fieldConfiguration;
228
                }
229
            }
230
        }
231
232
        if (null !== $mutationName && $input) {
233
            $fields['clientMutationId'] = $clientMutationId;
234
        }
235
236
        return $fields;
237
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242
    public function resolveResourceArgs(array $args, string $operationName, string $shortName): array
243
    {
244
        foreach ($args as $id => $arg) {
245
            if (!isset($arg['type'])) {
246
                throw new \InvalidArgumentException(sprintf('The argument "%s" of the custom operation "%s" in %s needs a "type" option.', $id, $operationName, $shortName));
247
            }
248
249
            $args[$id]['type'] = $this->typeConverter->resolveType($arg['type']);
250
        }
251
252
        return $args;
253
    }
254
255
    /**
256
     * Get the field configuration of a resource.
257
     *
258
     * @see http://webonyx.github.io/graphql-php/type-system/object-types/
259
     */
260
    private function getResourceFieldConfiguration(?string $property, ?string $fieldDescription, string $deprecationReason, Type $type, string $rootResource, bool $input, ?string $queryName, ?string $mutationName, ?string $subscriptionName, int $depth = 0): ?array
261
    {
262
        try {
263
            $resourceClass = $this->typeBuilder->isCollection($type) && ($collectionValueType = $type->getCollectionValueType()) ? $collectionValueType->getClassName() : $type->getClassName();
264
265
            if (null === $graphqlType = $this->convertType($type, $input, $queryName, $mutationName, $subscriptionName, $resourceClass ?? '', $rootResource, $property, $depth)) {
0 ignored issues
show
introduced by
The condition null === $graphqlType = ...rce, $property, $depth) is always false.
Loading history...
266
                return null;
267
            }
268
269
            $graphqlWrappedType = $graphqlType instanceof WrappingType ? $graphqlType->getWrappedType() : $graphqlType;
270
            $isStandardGraphqlType = \in_array($graphqlWrappedType, GraphQLType::getStandardTypes(), true);
271
            if ($isStandardGraphqlType) {
272
                $resourceClass = '';
273
            }
274
275
            $resourceMetadata = null;
276
            if (!empty($resourceClass)) {
277
                try {
278
                    $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
279
                } catch (ResourceClassNotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
280
                }
281
            }
282
283
            // Check mercure attribute if it's a subscription at the root level.
284
            if ($subscriptionName && null === $property && (!$resourceMetadata || !$resourceMetadata->getAttribute('mercure', false))) {
285
                return null;
286
            }
287
288
            $args = [];
289
            if (!$input && null === $mutationName && null === $subscriptionName && !$isStandardGraphqlType && $this->typeBuilder->isCollection($type)) {
290
                if ($this->pagination->isGraphQlEnabled($resourceClass, $queryName)) {
291
                    $args = $this->getGraphQlPaginationArgs($resourceClass, $queryName);
0 ignored issues
show
Bug introduced by
It seems like $resourceClass can also be of type null; however, parameter $resourceClass of ApiPlatform\Core\GraphQl...GraphQlPaginationArgs() does only seem to accept string, 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

291
                    $args = $this->getGraphQlPaginationArgs(/** @scrutinizer ignore-type */ $resourceClass, $queryName);
Loading history...
Bug introduced by
It seems like $queryName can also be of type null; however, parameter $queryName of ApiPlatform\Core\GraphQl...GraphQlPaginationArgs() does only seem to accept string, 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

291
                    $args = $this->getGraphQlPaginationArgs($resourceClass, /** @scrutinizer ignore-type */ $queryName);
Loading history...
292
                }
293
294
                $args = $this->getFilterArgs($args, $resourceClass, $resourceMetadata, $rootResource, $property, $queryName, $mutationName, $depth);
295
            }
296
297
            if ($isStandardGraphqlType || $input) {
298
                $resolve = null;
299
            } elseif ($mutationName) {
300
                $resolve = ($this->itemMutationResolverFactory)($resourceClass, $rootResource, $mutationName);
301
            } elseif ($subscriptionName) {
302
                $resolve = ($this->itemSubscriptionResolverFactory)($resourceClass, $rootResource, $subscriptionName);
303
            } elseif ($this->typeBuilder->isCollection($type)) {
304
                $resolve = ($this->collectionResolverFactory)($resourceClass, $rootResource, $queryName);
305
            } else {
306
                $resolve = ($this->itemResolverFactory)($resourceClass, $rootResource, $queryName);
307
            }
308
309
            return [
310
                'type' => $graphqlType,
311
                'description' => $fieldDescription,
312
                'args' => $args,
313
                'resolve' => $resolve,
314
                'deprecationReason' => $deprecationReason,
315
            ];
316
        } catch (InvalidTypeException $e) {
317
            // just ignore invalid types
318
        }
319
320
        return null;
321
    }
322
323
    private function getGraphQlPaginationArgs(string $resourceClass, string $queryName): array
324
    {
325
        $paginationType = $this->pagination->getGraphQlPaginationType($resourceClass, $queryName);
326
327
        if ('cursor' === $paginationType) {
328
            return [
329
                'first' => [
330
                    'type' => GraphQLType::int(),
331
                    'description' => 'Returns the first n elements from the list.',
332
                ],
333
                'last' => [
334
                    'type' => GraphQLType::int(),
335
                    'description' => 'Returns the last n elements from the list.',
336
                ],
337
                'before' => [
338
                    'type' => GraphQLType::string(),
339
                    'description' => 'Returns the elements in the list that come before the specified cursor.',
340
                ],
341
                'after' => [
342
                    'type' => GraphQLType::string(),
343
                    'description' => 'Returns the elements in the list that come after the specified cursor.',
344
                ],
345
            ];
346
        }
347
348
        $paginationOptions = $this->pagination->getOptions();
349
350
        $args = [
351
            $paginationOptions['page_parameter_name'] => [
352
                'type' => GraphQLType::int(),
353
                'description' => 'Returns the current page.',
354
            ],
355
        ];
356
357
        if ($paginationOptions['client_items_per_page']) {
358
            $args[$paginationOptions['items_per_page_parameter_name']] = [
359
                'type' => GraphQLType::int(),
360
                'description' => 'Returns the number of items per page.',
361
            ];
362
        }
363
364
        return $args;
365
    }
366
367
    private function getFilterArgs(array $args, ?string $resourceClass, ?ResourceMetadata $resourceMetadata, string $rootResource, ?string $property, ?string $queryName, ?string $mutationName, int $depth): array
368
    {
369
        if (null === $resourceMetadata || null === $resourceClass) {
370
            return $args;
371
        }
372
373
        foreach ($resourceMetadata->getGraphqlAttribute($queryName, 'filters', [], true) as $filterId) {
0 ignored issues
show
Bug introduced by
It seems like $queryName can also be of type null; however, parameter $operationName of ApiPlatform\Core\Metadat...::getGraphqlAttribute() does only seem to accept string, 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

373
        foreach ($resourceMetadata->getGraphqlAttribute(/** @scrutinizer ignore-type */ $queryName, 'filters', [], true) as $filterId) {
Loading history...
374
            if (null === $this->filterLocator || !$this->filterLocator->has($filterId)) {
375
                continue;
376
            }
377
378
            foreach ($this->filterLocator->get($filterId)->getDescription($resourceClass) as $key => $value) {
379
                $nullable = isset($value['required']) ? !$value['required'] : true;
380
                $filterType = \in_array($value['type'], Type::$builtinTypes, true) ? new Type($value['type'], $nullable) : new Type('object', $nullable, $value['type']);
381
                $graphqlFilterType = $this->convertType($filterType, false, $queryName, $mutationName, null, $resourceClass, $rootResource, $property, $depth);
382
383
                if ('[]' === substr($key, -2)) {
384
                    $graphqlFilterType = GraphQLType::listOf($graphqlFilterType);
385
                    $key = substr($key, 0, -2).'_list';
386
                }
387
388
                /** @var string $key */
389
                $key = str_replace('.', $this->nestingSeparator, $key);
390
391
                parse_str($key, $parsed);
392
                if (\array_key_exists($key, $parsed) && \is_array($parsed[$key])) {
393
                    $parsed = [$key => ''];
394
                }
395
                array_walk_recursive($parsed, function (&$value) use ($graphqlFilterType) {
396
                    $value = $graphqlFilterType;
397
                });
398
                $args = $this->mergeFilterArgs($args, $parsed, $resourceMetadata, $key);
399
            }
400
        }
401
402
        return $this->convertFilterArgsToTypes($args);
403
    }
404
405
    private function mergeFilterArgs(array $args, array $parsed, ResourceMetadata $resourceMetadata = null, $original = ''): array
406
    {
407
        foreach ($parsed as $key => $value) {
408
            // Never override keys that cannot be merged
409
            if (isset($args[$key]) && !\is_array($args[$key])) {
410
                continue;
411
            }
412
413
            if (\is_array($value)) {
414
                $value = $this->mergeFilterArgs($args[$key] ?? [], $value);
415
                if (!isset($value['#name'])) {
416
                    $name = (false === $pos = strrpos($original, '[')) ? $original : substr($original, 0, (int) $pos);
417
                    $value['#name'] = ($resourceMetadata ? $resourceMetadata->getShortName() : '').'Filter_'.strtr($name, ['[' => '_', ']' => '', '.' => '__']);
418
                }
419
            }
420
421
            $args[$key] = $value;
422
        }
423
424
        return $args;
425
    }
426
427
    private function convertFilterArgsToTypes(array $args): array
428
    {
429
        foreach ($args as $key => $value) {
430
            if (strpos($key, '.')) {
431
                // Declare relations/nested fields in a GraphQL compatible syntax.
432
                $args[str_replace('.', $this->nestingSeparator, $key)] = $value;
433
                unset($args[$key]);
434
            }
435
        }
436
437
        foreach ($args as $key => $value) {
438
            if (!\is_array($value) || !isset($value['#name'])) {
439
                continue;
440
            }
441
442
            $name = $value['#name'];
443
444
            if ($this->typesContainer->has($name)) {
445
                $args[$key] = $this->typesContainer->get($name);
446
                continue;
447
            }
448
449
            unset($value['#name']);
450
451
            $filterArgType = new InputObjectType([
452
                'name' => $name,
453
                'fields' => $this->convertFilterArgsToTypes($value),
454
            ]);
455
456
            $this->typesContainer->set($name, $filterArgType);
457
458
            $args[$key] = $filterArgType;
459
        }
460
461
        return $args;
462
    }
463
464
    /**
465
     * Converts a built-in type to its GraphQL equivalent.
466
     *
467
     * @throws InvalidTypeException
468
     */
469
    private function convertType(Type $type, bool $input, ?string $queryName, ?string $mutationName, ?string $subscriptionName, string $resourceClass, string $rootResource, ?string $property, int $depth)
470
    {
471
        $graphqlType = $this->typeConverter->convertType($type, $input, $queryName, $mutationName, $subscriptionName, $resourceClass, $rootResource, $property, $depth);
472
473
        if (null === $graphqlType) {
474
            throw new InvalidTypeException(sprintf('The type "%s" is not supported.', $type->getBuiltinType()));
475
        }
476
477
        if (\is_string($graphqlType)) {
478
            if (!$this->typesContainer->has($graphqlType)) {
479
                throw new InvalidTypeException(sprintf('The GraphQL type %s is not valid. Valid types are: %s. Have you registered this type by implementing %s?', $graphqlType, implode(', ', array_keys($this->typesContainer->all())), TypeInterface::class));
480
            }
481
482
            $graphqlType = $this->typesContainer->get($graphqlType);
483
        }
484
485
        if ($this->typeBuilder->isCollection($type)) {
486
            $operationName = $queryName ?? $mutationName ?? $subscriptionName;
487
488
            return $this->pagination->isGraphQlEnabled($resourceClass, $operationName) && !$input ? $this->typeBuilder->getResourcePaginatedCollectionType($graphqlType, $resourceClass, $operationName) : GraphQLType::listOf($graphqlType);
0 ignored issues
show
Bug introduced by
It seems like $operationName can also be of type null; however, parameter $operationName of ApiPlatform\Core\GraphQl...ginatedCollectionType() does only seem to accept string, 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

488
            return $this->pagination->isGraphQlEnabled($resourceClass, $operationName) && !$input ? $this->typeBuilder->getResourcePaginatedCollectionType($graphqlType, $resourceClass, /** @scrutinizer ignore-type */ $operationName) : GraphQLType::listOf($graphqlType);
Loading history...
489
        }
490
491
        return !$graphqlType instanceof NullableType || $type->isNullable() || (null !== $mutationName && 'update' === $mutationName)
492
            ? $graphqlType
493
            : GraphQLType::nonNull($graphqlType);
494
    }
495
496
    private function normalizePropertyName(string $property): string
497
    {
498
        return null !== $this->nameConverter ? $this->nameConverter->normalize($property) : $property;
499
    }
500
}
501