Skip to content

Commit 8365310

Browse files
committed
Merge 3.3
2 parents fc94db0 + ea7d443 commit 8365310

File tree

10 files changed

+91
-104
lines changed

10 files changed

+91
-104
lines changed

CHANGELOG.md

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## v3.3.11
4+
5+
### Features
6+
7+
* [344b8b245](https://github.com/api-platform/core/commit/344b8b245ac2a77e0b22b69e7976456c024a5dcb) Revert "feat(jsonschema): make JSON-LD specific properties required (#6366)" (#6484)
8+
9+
## v3.3.10
10+
11+
### Bug fixes
12+
13+
* [6776231ed](https://github.com/api-platform/core/commit/6776231eddebb8dbb9efdc66dec29247172cf0ea) fix: remove useless deprecation (#6481)
14+
* [71dbfb1af](https://github.com/api-platform/core/commit/71dbfb1af029b4c9e7d53d9e5c2b38ff97ac68a7) fix: property called default in ApiProperty has incorrect type (#6471) (#6472)
15+
* [c3e2e5b82](https://github.com/api-platform/core/commit/c3e2e5b8298f187f34e091af0f0a58e671ae853c) fix(symfony): securityPostValidation when use_symfony_listeners (#6479)
16+
* [e3013d40d](https://github.com/api-platform/core/commit/e3013d40dc601ff580d2d69d3228c36af3f457b6) Revert "fix(jsonschema): make all required properties optional in PATCH opera…" (#6476)
17+
* [aeca0149d](https://github.com/api-platform/core/commit/aeca0149dc488ac0fefd90adaae4a65df49bab1a) fix(jsonschema): make JSON-LD specific properties required in the output schema (#6366)
18+
319
## v3.3.9
420

521
### Bug fixes
@@ -264,6 +280,12 @@ api_platform:
264280
form: ['multipart/form-data']
265281
```
266282

283+
## v3.2.26
284+
285+
### Bug fixes
286+
287+
* [6776231ed](https://github.com/api-platform/core/commit/6776231eddebb8dbb9efdc66dec29247172cf0ea) fix: remove useless deprecation (#6481)
288+
267289
## v3.2.25
268290

269291
### Bug fixes
@@ -2394,4 +2416,4 @@ Please read #2825 if you have issues with the behavior of Readable/Writable Link
23942416
## 1.0.0 beta 2
23952417

23962418
* Preserve indexes when normalizing and denormalizing associative arrays
2397-
* Allow setting default order for property when registering a `Doctrine\Orm\Filter\OrderFilter` instance
2419+
* Allow setting default order for property when registering a `Doctrine\Orm\Filter\OrderFilter` instance

features/authorization/deny.feature

+12
Original file line numberDiff line numberDiff line change
@@ -305,3 +305,15 @@ Feature: Authorization checking
305305
Then the response status code should be 200
306306
And the response should contain "ownerOnlyProperty"
307307
And the response should contain "attributeBasedProperty"
308+
309+
Scenario: Security post validation should be hit
310+
When I add "Content-Type" header equal to "application/ld+json"
311+
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
312+
And I send a "POST" request to "/issue_6446" with body:
313+
"""
314+
{
315+
"title": ""
316+
}
317+
"""
318+
Then the response status code should be 403
319+

features/openapi/docs.feature

+4-4
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ Feature: Documentation support
153153
And the JSON node "paths./related_dummies/{id}/related_to_dummy_friends.get.parameters" should have 6 elements
154154

155155
# Subcollection - check schema
156-
And the JSON node "paths./related_dummies/{id}/related_to_dummy_friends.get.responses.200.content.application/ld+json.schema.properties.hydra:member.items.$ref" should be equal to "#/components/schemas/RelatedToDummyFriend.jsonld-fakemanytomany.output"
156+
And the JSON node "paths./related_dummies/{id}/related_to_dummy_friends.get.responses.200.content.application/ld+json.schema.properties.hydra:member.items.$ref" should be equal to "#/components/schemas/RelatedToDummyFriend.jsonld-fakemanytomany"
157157

158158
# Deprecations
159159
And the JSON node "paths./dummies.get.deprecated" should be false
@@ -165,8 +165,8 @@ Feature: Documentation support
165165
And the JSON node "paths./deprecated_resources/{id}.patch.deprecated" should be true
166166

167167
# Formats
168-
And the OpenAPI class "Dummy.jsonld.output" exists
169-
And the "@id" property exists for the OpenAPI class "Dummy.jsonld.output"
168+
And the OpenAPI class "Dummy.jsonld" exists
169+
And the "@id" property exists for the OpenAPI class "Dummy.jsonld"
170170
And the JSON node "paths./dummies.get.responses.200.content.application/ld+json" should be equal to:
171171
"""
172172
{
@@ -176,7 +176,7 @@ Feature: Documentation support
176176
"hydra:member": {
177177
"type": "array",
178178
"items": {
179-
"$ref": "#/components/schemas/Dummy.jsonld.output"
179+
"$ref": "#/components/schemas/Dummy.jsonld"
180180
}
181181
},
182182
"hydra:totalItems": {

src/Documentation/Action/DocumentationAction.php

-3
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,6 @@ class: OpenApi::class,
100100
if ('html' === $format) {
101101
$operation = $operation->withProcessor('api_platform.swagger_ui.processor')->withWrite(true);
102102
}
103-
if ('json' === $format) {
104-
trigger_deprecation('api-platform/core', '3.2', 'The "json" format is too broad, use "jsonopenapi" instead.');
105-
}
106103

107104
return $this->processor->process($this->provider->provide($operation, [], $context), $operation, [], $context);
108105
}

src/Hydra/JsonSchema/SchemaFactory.php

+4-27
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareInterface
2828
{
2929
private const BASE_PROP = [
30+
'readOnly' => true,
3031
'type' => 'string',
3132
];
3233
private const BASE_PROPS = [
@@ -35,6 +36,7 @@ final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareI
3536
];
3637
private const BASE_ROOT_PROPS = [
3738
'@context' => [
39+
'readOnly' => true,
3840
'oneOf' => [
3941
['type' => 'string'],
4042
[
@@ -72,43 +74,18 @@ public function buildSchema(string $className, string $format = 'jsonld', string
7274
return $schema;
7375
}
7476

75-
if (($key = $schema->getRootDefinitionKey() ?? $schema->getItemsDefinitionKey()) !== null) {
76-
$postfix = '.'.$type;
77-
$definitions = $schema->getDefinitions();
78-
$definitions[$key.$postfix] = $definitions[$key];
79-
unset($definitions[$key]);
80-
81-
if (($schema['type'] ?? '') === 'array') {
82-
$schema['items']['$ref'] .= $postfix;
83-
} else {
84-
$schema['$ref'] .= $postfix;
85-
}
77+
if ('input' === $type) {
78+
return $schema;
8679
}
8780

8881
$definitions = $schema->getDefinitions();
8982
if ($key = $schema->getRootDefinitionKey()) {
9083
$definitions[$key]['properties'] = self::BASE_ROOT_PROPS + ($definitions[$key]['properties'] ?? []);
91-
if (Schema::TYPE_OUTPUT === $type) {
92-
foreach (array_keys(self::BASE_ROOT_PROPS) as $property) {
93-
$definitions[$key]['required'] ??= [];
94-
if (!\in_array($property, $definitions[$key]['required'], true)) {
95-
$definitions[$key]['required'][] = $property;
96-
}
97-
}
98-
}
9984

10085
return $schema;
10186
}
10287
if ($key = $schema->getItemsDefinitionKey()) {
10388
$definitions[$key]['properties'] = self::BASE_PROPS + ($definitions[$key]['properties'] ?? []);
104-
if (Schema::TYPE_OUTPUT === $type) {
105-
foreach (array_keys(self::BASE_PROPS) as $property) {
106-
$definitions[$key]['required'] ??= [];
107-
if (!\in_array($property, $definitions[$key]['required'], true)) {
108-
$definitions[$key]['required'][] = $property;
109-
}
110-
}
111-
}
11289
}
11390

11491
if (($schema['type'] ?? '') === 'array') {

src/Metadata/ApiProperty.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ final class ApiProperty
2828
* @param bool|null $writableLink https://api-platform.com/docs/core/serialization/#force-iri-with-relations-of-the-same-type-parentchilds-relations
2929
* @param bool|null $required https://api-platform.com/docs/admin/validation/#client-side-validation
3030
* @param bool|null $identifier https://api-platform.com/docs/core/identifiers/
31-
* @param string|null $default
3231
* @param mixed $example https://api-platform.com/docs/core/openapi/#using-the-openapi-and-swagger-contexts
3332
* @param string|null $deprecationReason https://api-platform.com/docs/core/deprecations/#deprecating-resource-classes-operations-and-properties
3433
* @param bool|null $fetchEager https://api-platform.com/docs/core/performance/#eager-loading
@@ -50,7 +49,7 @@ public function __construct(
5049
private ?bool $writableLink = null,
5150
private ?bool $required = null,
5251
private ?bool $identifier = null,
53-
private $default = null,
52+
private mixed $default = null,
5453
private mixed $example = null,
5554
/**
5655
* The `deprecationReason` option deprecates the current operation with a deprecation message.

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ private function registerSecurityConfiguration(ContainerBuilder $container, arra
962962

963963
$loader->load('state/security.xml');
964964

965-
if (interface_exists(ValidatorInterface::class) && !$config['use_symfony_listeners']) {
965+
if (interface_exists(ValidatorInterface::class)) {
966966
$loader->load('state/security_validator.xml');
967967
}
968968

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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\Tests\Fixtures\TestBundle\ApiResource\Issue6446;
15+
16+
use ApiPlatform\Metadata\Post;
17+
use Symfony\Component\Validator\Constraints\NotNull;
18+
19+
#[Post(uriTemplate: 'issue_6446', securityPostValidation: 'is_granted(\'ROLE_ADMIN\')')]
20+
class SecurityPostValidation
21+
{
22+
#[NotNull]
23+
public string $title;
24+
}

tests/Hydra/JsonSchema/SchemaFactoryTest.php

+3-47
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use ApiPlatform\Metadata\ApiResource;
2222
use ApiPlatform\Metadata\Get;
2323
use ApiPlatform\Metadata\GetCollection;
24-
use ApiPlatform\Metadata\Post;
2524
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2625
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
2726
use ApiPlatform\Metadata\Property\PropertyNameCollection;
@@ -50,7 +49,6 @@ protected function setUp(): void
5049

5150
$propertyNameCollectionFactory = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
5251
$propertyNameCollectionFactory->create(Dummy::class, ['enable_getter_setter_extraction' => true, 'schema_type' => Schema::TYPE_OUTPUT])->willReturn(new PropertyNameCollection());
53-
$propertyNameCollectionFactory->create(Dummy::class, ['enable_getter_setter_extraction' => true, 'schema_type' => Schema::TYPE_INPUT])->willReturn(new PropertyNameCollection());
5452
$propertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class);
5553

5654
$definitionNameFactory = new DefinitionNameFactory(['jsonapi' => true, 'jsonhal' => true, 'jsonld' => true]);
@@ -71,12 +69,7 @@ public function testBuildSchema(): void
7169
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class);
7270

7371
$this->assertTrue($resultSchema->isDefined());
74-
$this->assertSame('Dummy.jsonld.output', $resultSchema->getRootDefinitionKey());
75-
76-
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_INPUT, new Post());
77-
78-
$this->assertTrue($resultSchema->isDefined());
79-
$this->assertSame('Dummy.jsonld.input', $resultSchema->getRootDefinitionKey());
72+
$this->assertSame('Dummy.jsonld', $resultSchema->getRootDefinitionKey());
8073
}
8174

8275
public function testCustomFormatBuildSchema(): void
@@ -101,6 +94,7 @@ public function testHasRootDefinitionKeyBuildSchema(): void
10194
$this->assertArrayHasKey('@context', $properties);
10295
$this->assertEquals(
10396
[
97+
'readOnly' => true,
10498
'oneOf' => [
10599
['type' => 'string'],
106100
[
@@ -128,7 +122,7 @@ public function testHasRootDefinitionKeyBuildSchema(): void
128122
public function testSchemaTypeBuildSchema(): void
129123
{
130124
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, new GetCollection());
131-
$definitionName = 'Dummy.jsonld.output';
125+
$definitionName = 'Dummy.jsonld';
132126

133127
$this->assertNull($resultSchema->getRootDefinitionKey());
134128
// @noRector
@@ -157,12 +151,6 @@ public function testSchemaTypeBuildSchema(): void
157151
$this->assertArrayNotHasKey('@context', $properties);
158152
$this->assertArrayHasKey('@type', $properties);
159153
$this->assertArrayHasKey('@id', $properties);
160-
161-
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_INPUT, new Post());
162-
$definitionName = 'Dummy.jsonld.input';
163-
164-
$this->assertSame($definitionName, $resultSchema->getRootDefinitionKey());
165-
$this->assertFalse(isset($resultSchema['properties']));
166154
}
167155

168156
public function testHasHydraViewNavigationBuildSchema(): void
@@ -180,36 +168,4 @@ public function testHasHydraViewNavigationBuildSchema(): void
180168
$this->assertArrayHasKey('hydra:previous', $resultSchema['properties']['hydra:view']['properties']);
181169
$this->assertArrayHasKey('hydra:next', $resultSchema['properties']['hydra:view']['properties']);
182170
}
183-
184-
public function testRequiredBasePropertiesBuildSchema(): void
185-
{
186-
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class);
187-
$definitions = $resultSchema->getDefinitions();
188-
$rootDefinitionKey = $resultSchema->getRootDefinitionKey();
189-
190-
$this->assertTrue(isset($definitions[$rootDefinitionKey]));
191-
$this->assertTrue(isset($definitions[$rootDefinitionKey]['required']));
192-
$requiredProperties = $resultSchema['definitions'][$rootDefinitionKey]['required'];
193-
$this->assertContains('@context', $requiredProperties);
194-
$this->assertContains('@id', $requiredProperties);
195-
$this->assertContains('@type', $requiredProperties);
196-
197-
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, new GetCollection());
198-
$definitions = $resultSchema->getDefinitions();
199-
$itemsDefinitionKey = array_key_first($definitions->getArrayCopy());
200-
201-
$this->assertTrue(isset($definitions[$itemsDefinitionKey]));
202-
$this->assertTrue(isset($definitions[$itemsDefinitionKey]['required']));
203-
$requiredProperties = $resultSchema['definitions'][$itemsDefinitionKey]['required'];
204-
$this->assertNotContains('@context', $requiredProperties);
205-
$this->assertContains('@id', $requiredProperties);
206-
$this->assertContains('@type', $requiredProperties);
207-
208-
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_INPUT, new Post());
209-
$definitions = $resultSchema->getDefinitions();
210-
$itemsDefinitionKey = array_key_first($definitions->getArrayCopy());
211-
212-
$this->assertTrue(isset($definitions[$itemsDefinitionKey]));
213-
$this->assertFalse(isset($definitions[$itemsDefinitionKey]['required']));
214-
}
215171
}

0 commit comments

Comments
 (0)