Skip to content

Commit 24de121

Browse files
committed
!fix(openapi): allowReserved, allowEmtpyValue defaults to null
1 parent b06274d commit 24de121

File tree

6 files changed

+82
-38
lines changed

6 files changed

+82
-38
lines changed

src/OpenApi/Factory/OpenApiFactory.php

+47-7
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,15 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
279279
continue;
280280
}
281281

282-
$parameter = new Parameter($parameterName, 'path', $uriVariable->getDescription() ?? "$resourceShortName identifier", $uriVariable->getRequired() ?? true, false, false, $uriVariable->getSchema() ?? ['type' => 'string']);
282+
$parameter = new Parameter(
283+
$parameterName,
284+
'path',
285+
$uriVariable->getDescription() ?? "$resourceShortName identifier",
286+
$uriVariable->getRequired() ?? true,
287+
false,
288+
null,
289+
$uriVariable->getSchema() ?? ['type' => 'string'],
290+
);
283291

284292
if ($linkParameter = $uriVariable->getOpenApi()) {
285293
$parameter = $this->mergeParameter($parameter, $linkParameter);
@@ -329,7 +337,15 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
329337
}
330338

331339
$in = $p instanceof HeaderParameterInterface ? 'header' : 'query';
332-
$defaultParameter = new Parameter($key, $in, $p->getDescription() ?? "$resourceShortName $key", $p->getRequired() ?? false, false, false, $p->getSchema() ?? ['type' => 'string']);
340+
$defaultParameter = new Parameter(
341+
$key,
342+
$in,
343+
$p->getDescription() ?? "$resourceShortName $key",
344+
$p->getRequired() ?? false,
345+
false,
346+
null,
347+
$p->getSchema() ?? ['type' => 'string'],
348+
);
333349

334350
$linkParameter = $p->getOpenApi();
335351
if (null === $linkParameter) {
@@ -752,15 +768,15 @@ private function getFilterParameter(string $name, array $description, string $sh
752768
$description['description'] ?? '',
753769
$description['required'] ?? false,
754770
$description['openapi']['deprecated'] ?? false,
755-
$description['openapi']['allowEmptyValue'] ?? true,
771+
$description['openapi']['allowEmptyValue'] ?? null,
756772
$schema,
757773
'array' === $schema['type'] && \in_array(
758774
$description['type'],
759775
[$arrayValueType, $objectValueType],
760776
true
761777
) ? 'deepObject' : 'form',
762778
$description['openapi']['explode'] ?? ('array' === $schema['type']),
763-
$description['openapi']['allowReserved'] ?? false,
779+
$description['openapi']['allowReserved'] ?? null,
764780
$description['openapi']['example'] ?? null,
765781
isset(
766782
$description['openapi']['examples']
@@ -777,7 +793,15 @@ private function getPaginationParameters(CollectionOperationInterface|HttpOperat
777793
$parameters = [];
778794

779795
if ($operation->getPaginationEnabled() ?? $this->paginationOptions->isPaginationEnabled()) {
780-
$parameters[] = new Parameter($this->paginationOptions->getPaginationPageParameterName(), 'query', 'The collection page number', false, false, true, ['type' => 'integer', 'default' => 1]);
796+
$parameters[] = new Parameter(
797+
$this->paginationOptions->getPaginationPageParameterName(),
798+
'query',
799+
'The collection page number',
800+
false,
801+
false,
802+
null,
803+
['type' => 'integer', 'default' => 1],
804+
);
781805

782806
if ($operation->getPaginationClientItemsPerPage() ?? $this->paginationOptions->getClientItemsPerPage()) {
783807
$schema = [
@@ -790,12 +814,28 @@ private function getPaginationParameters(CollectionOperationInterface|HttpOperat
790814
$schema['maximum'] = $maxItemsPerPage;
791815
}
792816

793-
$parameters[] = new Parameter($this->paginationOptions->getItemsPerPageParameterName(), 'query', 'The number of items per page', false, false, true, $schema);
817+
$parameters[] = new Parameter(
818+
$this->paginationOptions->getItemsPerPageParameterName(),
819+
'query',
820+
'The number of items per page',
821+
false,
822+
false,
823+
null,
824+
$schema,
825+
);
794826
}
795827
}
796828

797829
if ($operation->getPaginationClientEnabled() ?? $this->paginationOptions->isPaginationClientEnabled()) {
798-
$parameters[] = new Parameter($this->paginationOptions->getPaginationClientEnabledParameterName(), 'query', 'Enable or disable pagination', false, false, true, ['type' => 'boolean']);
830+
$parameters[] = new Parameter(
831+
$this->paginationOptions->getPaginationClientEnabledParameterName(),
832+
'query',
833+
'Enable or disable pagination',
834+
false,
835+
false,
836+
null,
837+
['type' => 'boolean'],
838+
);
799839
}
800840

801841
return $parameters;

src/OpenApi/Model/Parameter.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class Parameter
1717
{
1818
use ExtensionTrait;
1919

20-
public function __construct(private string $name, private string $in, private string $description = '', private bool $required = false, private bool $deprecated = false, private bool $allowEmptyValue = false, private array $schema = [], private ?string $style = null, private bool $explode = false, private bool $allowReserved = false, private $example = null, private ?\ArrayObject $examples = null, private ?\ArrayObject $content = null)
20+
public function __construct(private string $name, private string $in, private string $description = '', private bool $required = false, private bool $deprecated = false, private ?bool $allowEmptyValue = null, private array $schema = [], private ?string $style = null, private bool $explode = false, private ?bool $allowReserved = null, private $example = null, private ?\ArrayObject $examples = null, private ?\ArrayObject $content = null)
2121
{
2222
if (null === $style) {
2323
if ('query' === $in || 'cookie' === $in) {
@@ -53,12 +53,12 @@ public function getDeprecated(): bool
5353
return $this->deprecated;
5454
}
5555

56-
public function canAllowEmptyValue(): bool
56+
public function canAllowEmptyValue(): ?bool
5757
{
5858
return $this->allowEmptyValue;
5959
}
6060

61-
public function getAllowEmptyValue(): bool
61+
public function getAllowEmptyValue(): ?bool
6262
{
6363
return $this->allowEmptyValue;
6464
}
@@ -83,12 +83,12 @@ public function getExplode(): bool
8383
return $this->explode;
8484
}
8585

86-
public function canAllowReserved(): bool
86+
public function canAllowReserved(): ?bool
8787
{
8888
return $this->allowReserved;
8989
}
9090

91-
public function getAllowReserved(): bool
91+
public function getAllowReserved(): ?bool
9292
{
9393
return $this->allowReserved;
9494
}

src/OpenApi/Tests/Factory/OpenApiFactoryTest.php

+21-23
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ public function testInvoke(): void
170170
in: 'query',
171171
description: 'Test modified collection page number',
172172
required: false,
173-
allowEmptyValue: true,
174173
schema: ['type' => 'integer', 'default' => 1],
175174
),
176175
],
@@ -268,7 +267,7 @@ public function testInvoke(): void
268267

269268
$baseOperation = (new HttpOperation())->withTypes(['http://schema.example.com/Dummy'])->withInputFormats(self::OPERATION_FORMATS['input_formats'])->withOutputFormats(self::OPERATION_FORMATS['output_formats'])->withClass(Dummy::class)->withShortName('Parameter')->withDescription('This is a dummy');
270269
$parameterResource = (new ApiResource())->withOperations(new Operations([
271-
'uriVariableSchema' => (new Get(uriTemplate: '/uri_variable_uuid', uriVariables: ['id' => new Link(schema: ['type' => 'string', 'format' => 'uuid'], description: 'hello', required: true, openApi: new Parameter('id', 'path', allowEmptyValue: true))]))->withOperation($baseOperation),
270+
'uriVariableSchema' => (new Get(uriTemplate: '/uri_variable_uuid', uriVariables: ['id' => new Link(schema: ['type' => 'string', 'format' => 'uuid'], description: 'hello', required: true, openApi: new Parameter('id', 'path'))]))->withOperation($baseOperation),
272271
'parameters' => (new Put(uriTemplate: '/parameters', parameters: [
273272
'foo' => new HeaderParameter(description: 'hi', schema: ['type' => 'string', 'format' => 'uuid']),
274273
]))->withOperation($baseOperation),
@@ -477,7 +476,7 @@ public function testInvoke(): void
477476
'type' => 'string',
478477
'required' => true,
479478
'strategy' => 'exact',
480-
'openapi' => new Parameter(in: 'query', name: 'name', example: 'bar', deprecated: true, allowEmptyValue: true, allowReserved: true, explode: true),
479+
'openapi' => new Parameter(in: 'query', name: 'name', example: 'bar', deprecated: true, allowReserved: true, explode: true),
481480
]]),
482481
'f2' => new DummyFilter(['ha' => [
483482
'property' => 'foo',
@@ -690,16 +689,16 @@ public function testInvoke(): void
690689
'Retrieves the collection of Dummy resources.',
691690
null,
692691
[
693-
new Parameter('page', 'query', 'Test modified collection page number', false, false, true, [
692+
new Parameter('page', 'query', 'Test modified collection page number', false, false, null, [
694693
'type' => 'integer',
695694
'default' => 1,
696695
]),
697-
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, true, [
696+
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
698697
'type' => 'integer',
699698
'default' => 30,
700699
'minimum' => 0,
701700
]),
702-
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, true, [
701+
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
703702
'type' => 'boolean',
704703
]),
705704
]
@@ -935,29 +934,29 @@ public function testInvoke(): void
935934
'Retrieves the collection of Dummy resources.',
936935
null,
937936
[
938-
new Parameter('page', 'query', 'The collection page number', false, false, true, [
937+
new Parameter('page', 'query', 'The collection page number', false, false, null, [
939938
'type' => 'integer',
940939
'default' => 1,
941940
]),
942-
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, true, [
941+
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
943942
'type' => 'integer',
944943
'default' => 30,
945944
'minimum' => 0,
946945
]),
947-
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, true, [
946+
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
948947
'type' => 'boolean',
949948
]),
950-
new Parameter('name', 'query', '', true, true, true, [
949+
new Parameter('name', 'query', '', true, true, null, [
951950
'type' => 'string',
952951
], 'form', true, true, 'bar'),
953-
new Parameter('ha', 'query', '', false, false, false, [
952+
new Parameter('ha', 'query', '', false, false, null, [
954953
'type' => 'integer',
955954
]),
956-
new Parameter('toto', 'query', '', true, false, false, [
955+
new Parameter('toto', 'query', '', true, false, null, [
957956
'type' => 'array',
958957
'items' => ['type' => 'string'],
959958
], 'deepObject', true),
960-
new Parameter('order[name]', 'query', '', false, false, false, [
959+
new Parameter('order[name]', 'query', '', false, false, null, [
961960
'type' => 'string',
962961
'enum' => ['asc', 'desc'],
963962
]),
@@ -981,17 +980,17 @@ public function testInvoke(): void
981980
'Retrieves the collection of Dummy resources.',
982981
null,
983982
[
984-
new Parameter('page', 'query', 'The collection page number', false, false, true, [
983+
new Parameter('page', 'query', 'The collection page number', false, false, null, [
985984
'type' => 'integer',
986985
'default' => 1,
987986
]),
988-
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, true, [
987+
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
989988
'type' => 'integer',
990989
'default' => 20,
991990
'minimum' => 0,
992991
'maximum' => 80,
993992
]),
994-
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, true, [
993+
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
995994
'type' => 'boolean',
996995
]),
997996
]
@@ -1186,16 +1185,16 @@ public function testInvoke(): void
11861185
'Retrieves the collection of Dummy resources.',
11871186
null,
11881187
[
1189-
new Parameter('page', 'query', 'The collection page number', false, false, true, [
1188+
new Parameter('page', 'query', 'The collection page number', false, false, null, [
11901189
'type' => 'integer',
11911190
'default' => 1,
11921191
]),
1193-
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, true, [
1192+
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
11941193
'type' => 'integer',
11951194
'default' => 30,
11961195
'minimum' => 0,
11971196
]),
1198-
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, true, [
1197+
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
11991198
'type' => 'boolean',
12001199
]),
12011200
]
@@ -1233,7 +1232,6 @@ public function testInvoke(): void
12331232
), $emptyRequestBodyPath->getPost());
12341233

12351234
$parameter = $paths->getPath('/uri_variable_uuid')->getGet()->getParameters()[0];
1236-
$this->assertTrue($parameter->getAllowEmptyValue());
12371235
$this->assertEquals(['type' => 'string', 'format' => 'uuid'], $parameter->getSchema());
12381236

12391237
$parameter = $paths->getPath('/parameters')->getPut()->getParameters()[0];
@@ -1265,16 +1263,16 @@ public function testInvoke(): void
12651263
'Retrieves the collection of Dummy resources.',
12661264
null,
12671265
[
1268-
new Parameter('page', 'query', 'The collection page number', false, false, true, [
1266+
new Parameter('page', 'query', 'The collection page number', false, false, null, [
12691267
'type' => 'integer',
12701268
'default' => 1,
12711269
]),
1272-
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, true, [
1270+
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
12731271
'type' => 'integer',
12741272
'default' => 30,
12751273
'minimum' => 0,
12761274
]),
1277-
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, true, [
1275+
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
12781276
'type' => 'boolean',
12791277
]),
12801278
],

tests/Fixtures/TestBundle/Document/User.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* @author Théo FIDRY <[email protected]>
3535
* @author Kévin Dunglas <[email protected]>
3636
*/
37-
#[ApiResource(openapi: false, operations: [new Get(), new Put(), new Delete(), new Put(input: RecoverPasswordInput::class, output: RecoverPasswordOutput::class, uriTemplate: 'users/recover/{id}'), new Post(), new GetCollection(), new Post(uriTemplate: '/users/password_reset_request', messenger: 'input', input: PasswordResetRequest::class, output: PasswordResetRequestResult::class, normalizationContext: ['groups' => ['user_password_reset_request']], denormalizationContext: ['groups' => ['user_password_reset_request']])], normalizationContext: ['groups' => ['user', 'user-read']], denormalizationContext: ['groups' => ['user', 'user-write']])]
37+
#[ApiResource(operations: [new Get(), new Put(), new Delete(), new Put(input: RecoverPasswordInput::class, output: RecoverPasswordOutput::class, uriTemplate: 'users/recover/{id}'), new Post(), new GetCollection(), new Post(uriTemplate: '/users/password_reset_request', messenger: 'input', input: PasswordResetRequest::class, output: PasswordResetRequestResult::class, normalizationContext: ['groups' => ['user_password_reset_request']], denormalizationContext: ['groups' => ['user_password_reset_request']])], normalizationContext: ['groups' => ['user', 'user-read']], denormalizationContext: ['groups' => ['user', 'user-write']])]
3838
#[ODM\Document(collection: 'user_test')]
3939
class User implements UserInterface, PasswordAuthenticatedUserInterface
4040
{

tests/Fixtures/TestBundle/Entity/User.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@
4444
normalizationContext: ['groups' => ['user_password_reset_request']],
4545
denormalizationContext: ['groups' => ['user_password_reset_request']]
4646
),
47-
new Put(input: RecoverPasswordInput::class, output: RecoverPasswordOutput::class, uriTemplate: 'users/recover/{id}', processor: RecoverPasswordProcessor::class),
47+
new Put(
48+
input: RecoverPasswordInput::class,
49+
output: RecoverPasswordOutput::class,
50+
uriTemplate: 'users/recover/{id}',
51+
processor: RecoverPasswordProcessor::class,
52+
openapi: false, // ambigous path
53+
),
4854
new Get(),
4955
new Put(),
5056
new Delete(),

tests/Fixtures/TestBundle/Entity/WrappedResponseEntity.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use Doctrine\ORM\Mapping as ORM;
2020
use Symfony\Component\Serializer\Annotation\Groups;
2121

22-
#[ApiResource(operations: [new Get(openapi: false, normalizationContext: ['groups' => ['read']], output: CustomOutputEntityWrapperDto::class
22+
#[ApiResource(operations: [new Get(normalizationContext: ['groups' => ['read']], output: CustomOutputEntityWrapperDto::class
2323
)])]
2424
#[ORM\Entity]
2525
class WrappedResponseEntity

0 commit comments

Comments
 (0)