• 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

93.48
/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;
18
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
19

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

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

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

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

57
        if (empty($data['basePath'])) {
1✔
58
            $data['basePath'] = '/';
1✔
59
        }
60

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

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

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

112
        return $data;
1✔
113
    }
114

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

123
    /**
124
     * {@inheritdoc}
125
     */
126
    public function hasCacheableSupportsMethod(): bool
127
    {
128
        return $this->documentationNormalizer instanceof CacheableSupportsMethodInterface && $this->documentationNormalizer->hasCacheableSupportsMethod();
24✔
129
    }
130

131
    private function isLocalRef(string $ref): bool
132
    {
133
        return str_starts_with($ref, '#/');
1✔
134
    }
135

136
    private function normalizeRef(string $ref): string
137
    {
138
        $refParts = explode('/', $ref);
1✔
139

140
        $schemaName = array_pop($refParts);
1✔
141
        $schemaName = preg_replace('/[^0-9A-Za-z]/', '', $schemaName);
1✔
142
        $refParts[] = $schemaName;
1✔
143

144
        return implode('/', $refParts);
1✔
145
    }
146
}
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