• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 15133993414

20 May 2025 09:30AM UTC coverage: 26.313% (-1.2%) from 27.493%
15133993414

Pull #7161

github

web-flow
Merge e2c03d45f into 5459ba375
Pull Request #7161: fix(metadata): infer parameter string type from schema

0 of 2 new or added lines in 1 file covered. (0.0%)

11019 existing lines in 363 files now uncovered.

12898 of 49018 relevant lines covered (26.31%)

34.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.12
/src/GraphQl/Serializer/SerializerContextBuilder.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
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\GraphQl\Serializer;
15

16
use ApiPlatform\Metadata\GraphQl\Mutation;
17
use ApiPlatform\Metadata\GraphQl\Operation;
18
use ApiPlatform\Metadata\GraphQl\Subscription;
19
use GraphQL\Type\Definition\ResolveInfo;
20
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
21
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
22
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
23
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
24

25
/**
26
 * Builds the context used by the Symfony Serializer.
27
 *
28
 * @author Alan Poulain <contact@alanpoulain.eu>
29
 */
30
final class SerializerContextBuilder implements SerializerContextBuilderInterface
31
{
32
    public function __construct(private readonly ?NameConverterInterface $nameConverter)
33
    {
UNCOV
34
    }
534✔
35

36
    public function create(?string $resourceClass, Operation $operation, array $resolverContext, bool $normalization): array
37
    {
UNCOV
38
        $context = ['resource_class' => $resourceClass, 'operation_name' => $operation->getName(), 'graphql_operation_name' => $operation->getName()];
123✔
39

UNCOV
40
        if (isset($resolverContext['fields'])) {
123✔
41
            $context['no_resolver_data'] = true;
1✔
42
        }
43

UNCOV
44
        $context['operation'] = $operation;
123✔
UNCOV
45
        if ($operation->getInput()) {
123✔
46
            $context['input'] = $operation->getInput();
5✔
47
        }
UNCOV
48
        if ($operation->getOutput()) {
123✔
49
            $context['output'] = $operation->getOutput();
4✔
50
        }
UNCOV
51
        $context = $normalization ? array_merge($operation->getNormalizationContext() ?? [], $context) : array_merge($operation->getDenormalizationContext() ?? [], $context);
123✔
52

UNCOV
53
        if ($normalization) {
123✔
UNCOV
54
            $context['attributes'] = $this->fieldsToAttributes($resourceClass, $operation, $resolverContext, $context);
123✔
55
        }
56

57
        // to keep the cache computation smaller, we have "operation_name" and "iri" anyways
UNCOV
58
        $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'root_operation';
123✔
UNCOV
59
        $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'operation';
123✔
UNCOV
60
        $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'object';
123✔
UNCOV
61
        $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'data';
123✔
UNCOV
62
        $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'property_metadata';
123✔
UNCOV
63
        $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'circular_reference_limit_counters';
123✔
UNCOV
64
        $context[AbstractObjectNormalizer::EXCLUDE_FROM_CACHE_KEY][] = 'debug_trace_id';
123✔
65

UNCOV
66
        return $context;
123✔
67
    }
68

69
    /**
70
     * Retrieves fields, recursively replaces the "_id" key (the raw id) by "id" (the name of the property expected by the Serializer) and flattens edge and node structures (pagination).
71
     */
72
    private function fieldsToAttributes(?string $resourceClass, Operation $operation, array $resolverContext, array $context): array
73
    {
UNCOV
74
        if (isset($resolverContext['fields'])) {
123✔
75
            $fields = $resolverContext['fields'];
1✔
76
        } else {
77
            /** @var ResolveInfo $info */
UNCOV
78
            $info = $resolverContext['info'];
122✔
UNCOV
79
            $fields = $info->getFieldSelection(\PHP_INT_MAX);
122✔
80
        }
81

UNCOV
82
        $attributes = $this->replaceIdKeys($fields['edges']['node'] ?? $fields['collection'] ?? $fields, $resourceClass, $context);
123✔
83

UNCOV
84
        if ($operation instanceof Subscription || $operation instanceof Mutation) {
123✔
UNCOV
85
            $wrapFieldName = lcfirst($operation->getShortName());
34✔
86

UNCOV
87
            return $attributes[$wrapFieldName] ?? [];
34✔
88
        }
89

UNCOV
90
        return $attributes;
95✔
91
    }
92

93
    private function replaceIdKeys(array $fields, ?string $resourceClass, array $context): array
94
    {
UNCOV
95
        $denormalizedFields = [];
123✔
96

UNCOV
97
        foreach ($fields as $key => $value) {
123✔
UNCOV
98
            if ('_id' === $key) {
123✔
99
                $denormalizedFields['id'] = $fields['_id'];
4✔
100

101
                continue;
4✔
102
            }
103

UNCOV
104
            $denormalizedFields[$this->denormalizePropertyName((string) $key, $resourceClass, $context)] = \is_array($value) ? $this->replaceIdKeys($value, $resourceClass, $context) : $value;
122✔
105
        }
106

UNCOV
107
        return $denormalizedFields;
123✔
108
    }
109

110
    private function denormalizePropertyName(string $property, ?string $resourceClass, array $context): string
111
    {
UNCOV
112
        if (null === $this->nameConverter) {
122✔
113
            return $property;
×
114
        }
UNCOV
115
        if ($this->nameConverter instanceof AdvancedNameConverterInterface || $this->nameConverter instanceof MetadataAwareNameConverter) {
122✔
UNCOV
116
            return $this->nameConverter->denormalize($property, $resourceClass, null, $context);
122✔
117
        }
118

119
        return $this->nameConverter->denormalize($property);
×
120
    }
121
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc