Skip to content

Commit d30d707

Browse files
committed
Merge 3.3
2 parents 0d5f356 + 6daec82 commit d30d707

34 files changed

+302
-79
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## v3.3.7
4+
5+
### Bug fixes
6+
7+
* [0ed1b637a](https://github.com/api-platform/core/commit/0ed1b637a84d0860c2e014e2473b52d17de9276b) fix(metadata): wrong schema generated if openapicontext set on array (#6431)
8+
* [57f930c65](https://github.com/api-platform/core/commit/57f930c65cb067b1727488ba6db6188c6c5a01c6) fix(openapi): parameters can disable openapi (#6440)
9+
* [69b4d35b9](https://github.com/api-platform/core/commit/69b4d35b9764e36dab0484e1a7332886e1de9b2c) fix(state): provider as ParameterProviderInterface (#6430)
10+
* [842091ddf](https://github.com/api-platform/core/commit/842091ddf5b41c7a0d76bfbcddccff2920a84c35) fix(jsonschema): make all required properties optional in PATCH operation with 'json' format (#6394)
11+
* [af34e72ed](https://github.com/api-platform/core/commit/af34e72ed6bb0d5f7235fcc9c2a6c7810ba4f9c2) fix(openapi): yaml openapi export should have numeric keys as string (#6436)
12+
* [b42e25f2d](https://github.com/api-platform/core/commit/b42e25f2dcb5e0c1759c9482c08c9929ef86dc90) fix(state): parameter decorates main chain (#6434)
13+
* [c922ba3f5](https://github.com/api-platform/core/commit/c922ba3f5cf6117e85548697a982fb1cbe3dde2e) fix(symfony): check method for readonly routes (#6437)
14+
315
## v3.3.6
416

517
### Bug fixes
@@ -223,6 +235,12 @@ api_platform:
223235
form: ['multipart/form-data']
224236
```
225237

238+
## v3.2.25
239+
240+
### Bug fixes
241+
242+
* [0ed1b637a](https://github.com/api-platform/core/commit/0ed1b637a84d0860c2e014e2473b52d17de9276b) fix(metadata): wrong schema generated if openapicontext set on array (#6431)
243+
226244
## v3.2.24
227245

228246
### Bug fixes

src/JsonSchema/Metadata/Property/Factory/SchemaPropertyMetadataFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ public function create(string $resourceClass, string $property, array $options =
100100
$propertySchema['example'] = $propertySchema['default'];
101101
}
102102

103-
// never override the following keys if at least one is already set
103+
// never override the following keys if at least one is already set or if there's a custom openapi context
104104
if ([] === $types
105105
|| ($propertySchema['type'] ?? $propertySchema['$ref'] ?? $propertySchema['anyOf'] ?? $propertySchema['allOf'] ?? $propertySchema['oneOf'] ?? false)
106+
|| ($propertyMetadata->getOpenapiContext() ?? false)
106107
) {
107108
return $propertyMetadata->withSchema($propertySchema);
108109
}

src/JsonSchema/SchemaFactory.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use ApiPlatform\Metadata\CollectionOperationInterface;
1919
use ApiPlatform\Metadata\HttpOperation;
2020
use ApiPlatform\Metadata\Operation;
21+
use ApiPlatform\Metadata\Patch;
2122
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2223
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
2324
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
@@ -33,6 +34,9 @@
3334
final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareInterface
3435
{
3536
use ResourceMetadataTrait;
37+
38+
private const PATCH_SCHEMA_POSTFIX = '.patch';
39+
3640
private ?TypeFactoryInterface $typeFactory = null;
3741
private ?SchemaFactoryInterface $schemaFactory = null;
3842
// Edge case where the related resource is not readable (for example: NotExposed) but we have groups to read the whole related object
@@ -88,6 +92,12 @@ public function buildSchema(string $className, string $format = 'json', string $
8892
return $schema;
8993
}
9094

95+
$isJsonMergePatch = 'json' === $format && $operation instanceof Patch && Schema::TYPE_INPUT === $type;
96+
97+
if ($isJsonMergePatch) {
98+
$definitionName .= self::PATCH_SCHEMA_POSTFIX;
99+
}
100+
91101
if (!isset($schema['$ref']) && !isset($schema['type'])) {
92102
$ref = Schema::VERSION_OPENAPI === $version ? '#/components/schemas/'.$definitionName : '#/definitions/'.$definitionName;
93103
if ($forceCollection || ('POST' !== $method && $operation instanceof CollectionOperationInterface)) {
@@ -136,7 +146,7 @@ public function buildSchema(string $className, string $format = 'json', string $
136146
}
137147

138148
$normalizedPropertyName = $this->nameConverter ? $this->nameConverter->normalize($propertyName, $inputOrOutputClass, $format, $serializerContext) : $propertyName;
139-
if ($propertyMetadata->isRequired()) {
149+
if ($propertyMetadata->isRequired() && !$isJsonMergePatch) {
140150
$definition['required'][] = $normalizedPropertyName;
141151
}
142152

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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\JsonSchema\Tests\Fixtures;
15+
16+
use ApiPlatform\Metadata\ApiProperty;
17+
use ApiPlatform\Metadata\ApiResource;
18+
19+
/*
20+
* This file is part of the API Platform project.
21+
*
22+
* (c) Kévin Dunglas <[email protected]>
23+
*
24+
* For the full copyright and license information, please view the LICENSE
25+
* file that was distributed with this source code.
26+
*/
27+
28+
#[ApiResource]
29+
class DummyWithCustomOpenApiContext
30+
{
31+
#[ApiProperty(openapiContext: ['type' => 'object', 'properties' => ['alpha' => ['type' => 'integer']]])]
32+
public $acme;
33+
}

src/JsonSchema/Tests/Metadata/Property/Factory/SchemaPropertyMetadataFactoryTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\JsonSchema\Tests\Metadata\Property\Factory;
1515

1616
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
17+
use ApiPlatform\JsonSchema\Tests\Fixtures\DummyWithCustomOpenApiContext;
1718
use ApiPlatform\JsonSchema\Tests\Fixtures\DummyWithEnum;
1819
use ApiPlatform\JsonSchema\Tests\Fixtures\Enum\IntEnumAsIdentifier;
1920
use ApiPlatform\Metadata\ApiProperty;
@@ -34,4 +35,18 @@ public function testEnum(): void
3435
$apiProperty = $schemaPropertyMetadataFactory->create(DummyWithEnum::class, 'intEnumAsIdentifier');
3536
$this->assertEquals(['type' => ['integer', 'null'], 'enum' => [1, 2, null]], $apiProperty->getSchema());
3637
}
38+
39+
public function testWithCustomOpenApiContext(): void
40+
{
41+
$resourceClassResolver = $this->createMock(ResourceClassResolverInterface::class);
42+
$apiProperty = new ApiProperty(
43+
builtinTypes: [new Type(builtinType: 'object', nullable: true, class: IntEnumAsIdentifier::class)],
44+
openapiContext: ['type' => 'object', 'properties' => ['alpha' => ['type' => 'integer']]],
45+
);
46+
$decorated = $this->createMock(PropertyMetadataFactoryInterface::class);
47+
$decorated->expects($this->once())->method('create')->with(DummyWithCustomOpenApiContext::class, 'acme')->willReturn($apiProperty);
48+
$schemaPropertyMetadataFactory = new SchemaPropertyMetadataFactory($resourceClassResolver, $decorated);
49+
$apiProperty = $schemaPropertyMetadataFactory->create(DummyWithCustomOpenApiContext::class, 'acme');
50+
$this->assertEquals([], $apiProperty->getSchema());
51+
}
3752
}

src/Metadata/Parameter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ abstract class Parameter
3232
public function __construct(
3333
protected ?string $key = null,
3434
protected ?array $schema = null,
35-
protected ?OpenApi\Model\Parameter $openApi = null,
35+
protected OpenApi\Model\Parameter|bool|null $openApi = null, // TODO: use false as type instead of bool
3636
protected mixed $provider = null,
3737
protected mixed $filter = null,
3838
protected ?string $property = null,
@@ -57,7 +57,7 @@ public function getSchema(): ?array
5757
return $this->schema;
5858
}
5959

60-
public function getOpenApi(): ?OpenApi\Model\Parameter
60+
public function getOpenApi(): OpenApi\Model\Parameter|bool|null
6161
{
6262
return $this->openApi;
6363
}

src/Metadata/Resource/Factory/ParameterResourceMetadataCollectionFactory.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ private function setDefaults(string $key, Parameter $parameter, string $resource
142142
}
143143
}
144144

145-
$schema = $parameter->getSchema() ?? $parameter->getOpenApi()?->getSchema();
145+
$schema = $parameter->getSchema() ?? (($openApi = $parameter->getOpenApi()) ? $openApi->getSchema() : null);
146146

147147
// Only add validation if the Symfony Validator is installed
148148
if (interface_exists(ValidatorInterface::class) && !$parameter->getConstraints()) {
149-
$parameter = $this->addSchemaValidation($parameter, $schema, $parameter->getRequired() ?? $description['required'] ?? false, $parameter->getOpenApi());
149+
$parameter = $this->addSchemaValidation($parameter, $schema, $parameter->getRequired() ?? $description['required'] ?? false, $parameter->getOpenApi() ?: null);
150150
}
151151

152152
return $parameter;

src/OpenApi/Command/OpenApiCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
5757
'spec_version' => $input->getOption('spec-version'),
5858
]);
5959
$content = $input->getOption('yaml')
60-
? Yaml::dump($data, 10, 2, Yaml::DUMP_OBJECT_AS_MAP | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE | Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)
60+
? Yaml::dump($data, 10, 2, Yaml::DUMP_OBJECT_AS_MAP | Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE | Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK | Yaml::DUMP_NUMERIC_KEY_AS_STRING)
6161
: (json_encode($data, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES) ?: '');
6262

6363
$filename = $input->getOption('output');

src/OpenApi/Factory/OpenApiFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,10 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
309309

310310
$openapiParameters = $openapiOperation->getParameters();
311311
foreach ($operation->getParameters() ?? [] as $key => $p) {
312+
if (false === $p->getOpenApi()) {
313+
continue;
314+
}
315+
312316
$in = $p instanceof HeaderParameterInterface ? 'header' : 'query';
313317
$parameter = new Parameter($key, $in, $p->getDescription() ?? "$resourceShortName $key", $p->getRequired() ?? false, false, false, $p->getSchema() ?? ['type' => 'string']);
314318

src/OpenApi/Model/PathItem.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ final class PathItem
1919

2020
public static array $methods = ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE'];
2121

22-
public function __construct(private ?string $ref = null, private ?string $summary = null, private ?string $description = null, private ?Operation $get = null, private ?Operation $put = null, private ?Operation $post = null, private ?Operation $delete = null, private ?Operation $options = null, private ?Operation $head = null, private ?Operation $patch = null, private ?Operation $trace = null, private ?array $servers = null, private array $parameters = [])
22+
public function __construct(private ?string $ref = null, private ?string $summary = null, private ?string $description = null, private ?Operation $get = null, private ?Operation $put = null, private ?Operation $post = null, private ?Operation $delete = null, private ?Operation $options = null, private ?Operation $head = null, private ?Operation $patch = null, private ?Operation $trace = null, private ?array $servers = null, private ?array $parameters = null)
2323
{
2424
}
2525

@@ -184,7 +184,7 @@ public function withServers(?array $servers = null): self
184184
return $clone;
185185
}
186186

187-
public function withParameters(array $parameters): self
187+
public function withParameters(?array $parameters = null): self
188188
{
189189
$clone = clone $this;
190190
$clone->parameters = $parameters;

0 commit comments

Comments
 (0)