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

api-platform / core / 3713134090

pending completion
3713134090

Pull #5254

github

GitHub
Merge b2ec54b3c into ac711530f
Pull Request #5254: [OpenApi] Add ApiResource::openapi and deprecate openapiContext

197 of 197 new or added lines in 5 files covered. (100.0%)

10372 of 12438 relevant lines covered (83.39%)

11.97 hits per line

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

62.07
/src/GraphQl/Serializer/ItemNormalizer.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\Api\IdentifiersExtractorInterface;
17
use ApiPlatform\Api\IriConverterInterface;
18
use ApiPlatform\Api\ResourceClassResolverInterface;
19
use ApiPlatform\Metadata\ApiProperty;
20
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
21
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
22
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
23
use ApiPlatform\Serializer\ItemNormalizer as BaseItemNormalizer;
24
use ApiPlatform\Symfony\Security\ResourceAccessCheckerInterface;
25
use ApiPlatform\Util\ClassInfoTrait;
26
use Psr\Log\LoggerInterface;
27
use Psr\Log\NullLogger;
28
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
29
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
30
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
31
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
32

33
/**
34
 * GraphQL normalizer.
35
 *
36
 * @author Kévin Dunglas <dunglas@gmail.com>
37
 */
38
final class ItemNormalizer extends BaseItemNormalizer
39
{
40
    use ClassInfoTrait;
41

42
    public const FORMAT = 'graphql';
43
    public const ITEM_RESOURCE_CLASS_KEY = '#itemResourceClass';
44
    public const ITEM_IDENTIFIERS_KEY = '#itemIdentifiers';
45

46
    public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, private readonly IdentifiersExtractorInterface $identifiersExtractor, ResourceClassResolverInterface $resourceClassResolver, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ClassMetadataFactoryInterface $classMetadataFactory = null, LoggerInterface $logger = null, ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory = null, ResourceAccessCheckerInterface $resourceAccessChecker = null)
47
    {
48
        parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory, $logger ?: new NullLogger(), $resourceMetadataCollectionFactory, $resourceAccessChecker);
30✔
49
    }
50

51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool
55
    {
56
        return self::FORMAT === $format && parent::supportsNormalization($data, $format, $context);
14✔
57
    }
58

59
    /**
60
     * {@inheritdoc}
61
     *
62
     * @param array<string, mixed> $context
63
     *
64
     * @throws UnexpectedValueException
65
     */
66
    public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
67
    {
68
        $resourceClass = $this->getObjectClass($object);
2✔
69

70
        if ($this->getOutputClass($context)) {
2✔
71
            $context['graphql_identifiers'] = [
×
72
                self::ITEM_RESOURCE_CLASS_KEY => $context['operation']->getClass(),
×
73
                self::ITEM_IDENTIFIERS_KEY => $this->identifiersExtractor->getIdentifiersFromItem($object, $context['operation'] ?? null),
×
74
            ];
×
75

76
            return parent::normalize($object, $format, $context);
×
77
        }
78

79
        unset($context['operation_name'], $context['operation']);
2✔
80
        $data = parent::normalize($object, $format, $context);
2✔
81
        if (!\is_array($data)) {
2✔
82
            throw new UnexpectedValueException('Expected data to be an array.');
×
83
        }
84

85
        if (isset($context['graphql_identifiers'])) {
2✔
86
            $data += $context['graphql_identifiers'];
×
87
        } elseif (!($context['no_resolver_data'] ?? false)) {
2✔
88
            $data[self::ITEM_RESOURCE_CLASS_KEY] = $resourceClass;
1✔
89
            $data[self::ITEM_IDENTIFIERS_KEY] = $this->identifiersExtractor->getIdentifiersFromItem($object, $context['operation'] ?? null);
1✔
90
        }
91

92
        return $data;
2✔
93
    }
94

95
    /**
96
     * {@inheritdoc}
97
     */
98
    protected function normalizeCollectionOfRelations(ApiProperty $propertyMetadata, iterable $attributeValue, string $resourceClass, ?string $format, array $context): array
99
    {
100
        // to-many are handled directly by the GraphQL resolver
101
        return [];
×
102
    }
103

104
    /**
105
     * {@inheritdoc}
106
     */
107
    public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool
108
    {
109
        return self::FORMAT === $format && parent::supportsDenormalization($data, $type, $format, $context);
4✔
110
    }
111

112
    /**
113
     * {@inheritdoc}
114
     */
115
    protected function getAllowedAttributes(string|object $classOrObject, array $context, bool $attributesAsString = false): array|bool
116
    {
117
        $allowedAttributes = parent::getAllowedAttributes($classOrObject, $context, $attributesAsString);
3✔
118

119
        if (($context['api_denormalize'] ?? false) && \is_array($allowedAttributes) && false !== ($indexId = array_search('id', $allowedAttributes, true))) {
3✔
120
            $allowedAttributes[] = '_id';
×
121
            array_splice($allowedAttributes, (int) $indexId, 1);
×
122
        }
123

124
        return $allowedAttributes;
3✔
125
    }
126

127
    /**
128
     * {@inheritdoc}
129
     */
130
    protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = []): void
131
    {
132
        if ('_id' === $attribute) {
1✔
133
            $attribute = 'id';
×
134
        }
135

136
        parent::setAttributeValue($object, $attribute, $value, $format, $context);
1✔
137
    }
138
}
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

© 2026 Coveralls, Inc