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

api-platform / core / 5650127293

pending completion
5650127293

push

github

web-flow
fix: don't implement deprecated CacheableSupportsMethodInterface with Symfony 6.3+ (#5696)

* fix: don't implement deprecated CacheableSupportsMethodInterface

* fix: a check, and add tests

* fix ApiGatewayNormalizerTest

* more fixes

* fix more tests

* fix lowest

* only trigger the deprecation for Symfony 6.3

167 of 167 new or added lines in 23 files covered. (100.0%)

10865 of 18368 relevant lines covered (59.15%)

19.9 hits per line

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

14.29
/src/OpenApi/Serializer/ApiGatewayNormalizer.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\OpenApi\Serializer;
15

16
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
17
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface as BaseCacheableSupportsMethodInterface;
18
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
19
use Symfony\Component\Serializer\Serializer;
20

21
/**
22
 * Removes features unsupported by Amazon API Gateway.
23
 *
24
 * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html
25
 *
26
 * @internal
27
 *
28
 * @author Vincent Chalamon <vincentchalamon@gmail.com>
29
 */
30
final class ApiGatewayNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface
31
{
32
    public const API_GATEWAY = 'api_gateway';
33
    private array $defaultContext = [
34
        self::API_GATEWAY => false,
35
    ];
36

37
    public function __construct(private readonly NormalizerInterface $documentationNormalizer, $defaultContext = [])
38
    {
39
        $this->defaultContext = array_merge($this->defaultContext, $defaultContext);
54✔
40
    }
41

42
    /**
43
     * {@inheritdoc}
44
     *
45
     * @throws UnexpectedValueException
46
     */
47
    public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
48
    {
49
        $data = $this->documentationNormalizer->normalize($object, $format, $context);
6✔
50
        if (!\is_array($data)) {
6✔
51
            throw new UnexpectedValueException('Expected data to be an array');
×
52
        }
53

54
        if (!($context[self::API_GATEWAY] ?? $this->defaultContext[self::API_GATEWAY])) {
6✔
55
            return $data;
6✔
56
        }
57

58
        if (empty($data['basePath'])) {
×
59
            $data['basePath'] = '/';
×
60
        }
61

62
        foreach ($data['paths'] as $path => $operations) {
×
63
            foreach ($operations as $operation => $options) {
×
64
                if (isset($options['parameters'])) {
×
65
                    foreach ($options['parameters'] as $key => $parameter) {
×
66
                        if (!preg_match('/^[a-zA-Z0-9._$-]+$/', (string) $parameter['name'])) {
×
67
                            unset($data['paths'][$path][$operation]['parameters'][$key]);
×
68
                        }
69
                        if (isset($parameter['schema']['$ref']) && $this->isLocalRef($parameter['schema']['$ref'])) {
×
70
                            $data['paths'][$path][$operation]['parameters'][$key]['schema']['$ref'] = $this->normalizeRef($parameter['schema']['$ref']);
×
71
                        }
72
                    }
73
                    $data['paths'][$path][$operation]['parameters'] = array_values($data['paths'][$path][$operation]['parameters']);
×
74
                }
75
                if (isset($options['responses'])) {
×
76
                    foreach ($options['responses'] as $statusCode => $response) {
×
77
                        if (isset($response['schema']['items']['$ref']) && $this->isLocalRef($response['schema']['items']['$ref'])) {
×
78
                            $data['paths'][$path][$operation]['responses'][$statusCode]['schema']['items']['$ref'] = $this->normalizeRef($response['schema']['items']['$ref']);
×
79
                        }
80
                        if (isset($response['schema']['$ref']) && $this->isLocalRef($response['schema']['$ref'])) {
×
81
                            $data['paths'][$path][$operation]['responses'][$statusCode]['schema']['$ref'] = $this->normalizeRef($response['schema']['$ref']);
×
82
                        }
83
                    }
84
                }
85
            }
86
        }
87

88
        foreach ($data['components']['schemas'] as $definition => $options) {
×
89
            if (!isset($options['properties'])) {
×
90
                continue;
×
91
            }
92
            foreach ($options['properties'] as $property => $propertyOptions) {
×
93
                if (isset($propertyOptions['readOnly'])) {
×
94
                    unset($data['components']['schemas'][$definition]['properties'][$property]['readOnly']);
×
95
                }
96
                if (isset($propertyOptions['$ref']) && $this->isLocalRef($propertyOptions['$ref'])) {
×
97
                    $data['components']['schemas'][$definition]['properties'][$property]['$ref'] = $this->normalizeRef($propertyOptions['$ref']);
×
98
                }
99
                if (isset($propertyOptions['items']['$ref']) && $this->isLocalRef($propertyOptions['items']['$ref'])) {
×
100
                    $data['components']['schemas'][$definition]['properties'][$property]['items']['$ref'] = $this->normalizeRef($propertyOptions['items']['$ref']);
×
101
                }
102
            }
103
        }
104

105
        // $data['definitions'] is an instance of \ArrayObject
106
        foreach (array_keys($data['components']['schemas']) as $definition) {
×
107
            if (!preg_match('/^[0-9A-Za-z]+$/', (string) $definition)) {
×
108
                $data['components']['schemas'][preg_replace('/[^0-9A-Za-z]/', '', (string) $definition)] = $data['components']['schemas'][$definition];
×
109
                unset($data['components']['schemas'][$definition]);
×
110
            }
111
        }
112

113
        return $data;
×
114
    }
115

116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool
120
    {
121
        return $this->documentationNormalizer->supportsNormalization($data, $format);
6✔
122
    }
123

124
    public function getSupportedTypes($format): array
125
    {
126
        // @deprecated remove condition when support for symfony versions under 6.3 is dropped
127
        if (!method_exists($this->documentationNormalizer, 'getSupportedTypes')) {
48✔
128
            return ['*' => $this->documentationNormalizer instanceof BaseCacheableSupportsMethodInterface && $this->documentationNormalizer->hasCacheableSupportsMethod()];
×
129
        }
130

131
        return $this->documentationNormalizer->getSupportedTypes($format);
48✔
132
    }
133

134
    /**
135
     * {@inheritdoc}
136
     */
137
    public function hasCacheableSupportsMethod(): bool
138
    {
139
        if (method_exists(Serializer::class, 'getSupportedTypes')) {
×
140
            trigger_deprecation(
×
141
                'api-platform/core',
×
142
                '3.1',
×
143
                'The "%s()" method is deprecated, use "getSupportedTypes()" instead.',
×
144
                __METHOD__
×
145
            );
×
146
        }
147

148
        return $this->documentationNormalizer instanceof BaseCacheableSupportsMethodInterface && $this->documentationNormalizer->hasCacheableSupportsMethod();
×
149
    }
150

151
    private function isLocalRef(string $ref): bool
152
    {
153
        return str_starts_with($ref, '#/');
×
154
    }
155

156
    private function normalizeRef(string $ref): string
157
    {
158
        $refParts = explode('/', $ref);
×
159

160
        $schemaName = array_pop($refParts);
×
161
        $schemaName = preg_replace('/[^0-9A-Za-z]/', '', $schemaName);
×
162
        $refParts[] = $schemaName;
×
163

164
        return implode('/', $refParts);
×
165
    }
166
}
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