Skip to content

Commit

Permalink
Merge 3.3
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Jul 20, 2024
2 parents fc94db0 + ea7d443 commit 8365310
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 104 deletions.
24 changes: 23 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## v3.3.11

### Features

* [344b8b245](https://github.com/api-platform/core/commit/344b8b245ac2a77e0b22b69e7976456c024a5dcb) Revert "feat(jsonschema): make JSON-LD specific properties required (#6366)" (#6484)

## v3.3.10

### Bug fixes

* [6776231ed](https://github.com/api-platform/core/commit/6776231eddebb8dbb9efdc66dec29247172cf0ea) fix: remove useless deprecation (#6481)
* [71dbfb1af](https://github.com/api-platform/core/commit/71dbfb1af029b4c9e7d53d9e5c2b38ff97ac68a7) fix: property called default in ApiProperty has incorrect type (#6471) (#6472)
* [c3e2e5b82](https://github.com/api-platform/core/commit/c3e2e5b8298f187f34e091af0f0a58e671ae853c) fix(symfony): securityPostValidation when use_symfony_listeners (#6479)
* [e3013d40d](https://github.com/api-platform/core/commit/e3013d40dc601ff580d2d69d3228c36af3f457b6) Revert "fix(jsonschema): make all required properties optional in PATCH opera…" (#6476)
* [aeca0149d](https://github.com/api-platform/core/commit/aeca0149dc488ac0fefd90adaae4a65df49bab1a) fix(jsonschema): make JSON-LD specific properties required in the output schema (#6366)

## v3.3.9

### Bug fixes
Expand Down Expand Up @@ -264,6 +280,12 @@ api_platform:
form: ['multipart/form-data']
```

## v3.2.26

### Bug fixes

* [6776231ed](https://github.com/api-platform/core/commit/6776231eddebb8dbb9efdc66dec29247172cf0ea) fix: remove useless deprecation (#6481)

## v3.2.25

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

* Preserve indexes when normalizing and denormalizing associative arrays
* Allow setting default order for property when registering a `Doctrine\Orm\Filter\OrderFilter` instance
* Allow setting default order for property when registering a `Doctrine\Orm\Filter\OrderFilter` instance
12 changes: 12 additions & 0 deletions features/authorization/deny.feature
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,15 @@ Feature: Authorization checking
Then the response status code should be 200
And the response should contain "ownerOnlyProperty"
And the response should contain "attributeBasedProperty"

Scenario: Security post validation should be hit
When I add "Content-Type" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "POST" request to "/issue_6446" with body:
"""
{
"title": ""
}
"""
Then the response status code should be 403

8 changes: 4 additions & 4 deletions features/openapi/docs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ Feature: Documentation support
And the JSON node "paths./related_dummies/{id}/related_to_dummy_friends.get.parameters" should have 6 elements

# Subcollection - check schema
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"
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"

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

# Formats
And the OpenAPI class "Dummy.jsonld.output" exists
And the "@id" property exists for the OpenAPI class "Dummy.jsonld.output"
And the OpenAPI class "Dummy.jsonld" exists
And the "@id" property exists for the OpenAPI class "Dummy.jsonld"
And the JSON node "paths./dummies.get.responses.200.content.application/ld+json" should be equal to:
"""
{
Expand All @@ -176,7 +176,7 @@ Feature: Documentation support
"hydra:member": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Dummy.jsonld.output"
"$ref": "#/components/schemas/Dummy.jsonld"
}
},
"hydra:totalItems": {
Expand Down
3 changes: 0 additions & 3 deletions src/Documentation/Action/DocumentationAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ class: OpenApi::class,
if ('html' === $format) {
$operation = $operation->withProcessor('api_platform.swagger_ui.processor')->withWrite(true);
}
if ('json' === $format) {
trigger_deprecation('api-platform/core', '3.2', 'The "json" format is too broad, use "jsonopenapi" instead.');
}

return $this->processor->process($this->provider->provide($operation, [], $context), $operation, [], $context);
}
Expand Down
31 changes: 4 additions & 27 deletions src/Hydra/JsonSchema/SchemaFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareInterface
{
private const BASE_PROP = [
'readOnly' => true,
'type' => 'string',
];
private const BASE_PROPS = [
Expand All @@ -35,6 +36,7 @@ final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareI
];
private const BASE_ROOT_PROPS = [
'@context' => [
'readOnly' => true,
'oneOf' => [
['type' => 'string'],
[
Expand Down Expand Up @@ -72,43 +74,18 @@ public function buildSchema(string $className, string $format = 'jsonld', string
return $schema;
}

if (($key = $schema->getRootDefinitionKey() ?? $schema->getItemsDefinitionKey()) !== null) {
$postfix = '.'.$type;
$definitions = $schema->getDefinitions();
$definitions[$key.$postfix] = $definitions[$key];
unset($definitions[$key]);

if (($schema['type'] ?? '') === 'array') {
$schema['items']['$ref'] .= $postfix;
} else {
$schema['$ref'] .= $postfix;
}
if ('input' === $type) {
return $schema;
}

$definitions = $schema->getDefinitions();
if ($key = $schema->getRootDefinitionKey()) {
$definitions[$key]['properties'] = self::BASE_ROOT_PROPS + ($definitions[$key]['properties'] ?? []);
if (Schema::TYPE_OUTPUT === $type) {
foreach (array_keys(self::BASE_ROOT_PROPS) as $property) {
$definitions[$key]['required'] ??= [];
if (!\in_array($property, $definitions[$key]['required'], true)) {
$definitions[$key]['required'][] = $property;
}
}
}

return $schema;
}
if ($key = $schema->getItemsDefinitionKey()) {
$definitions[$key]['properties'] = self::BASE_PROPS + ($definitions[$key]['properties'] ?? []);
if (Schema::TYPE_OUTPUT === $type) {
foreach (array_keys(self::BASE_PROPS) as $property) {
$definitions[$key]['required'] ??= [];
if (!\in_array($property, $definitions[$key]['required'], true)) {
$definitions[$key]['required'][] = $property;
}
}
}
}

if (($schema['type'] ?? '') === 'array') {
Expand Down
3 changes: 1 addition & 2 deletions src/Metadata/ApiProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ final class ApiProperty
* @param bool|null $writableLink https://api-platform.com/docs/core/serialization/#force-iri-with-relations-of-the-same-type-parentchilds-relations
* @param bool|null $required https://api-platform.com/docs/admin/validation/#client-side-validation
* @param bool|null $identifier https://api-platform.com/docs/core/identifiers/
* @param string|null $default
* @param mixed $example https://api-platform.com/docs/core/openapi/#using-the-openapi-and-swagger-contexts
* @param string|null $deprecationReason https://api-platform.com/docs/core/deprecations/#deprecating-resource-classes-operations-and-properties
* @param bool|null $fetchEager https://api-platform.com/docs/core/performance/#eager-loading
Expand All @@ -50,7 +49,7 @@ public function __construct(
private ?bool $writableLink = null,
private ?bool $required = null,
private ?bool $identifier = null,
private $default = null,
private mixed $default = null,
private mixed $example = null,
/**
* The `deprecationReason` option deprecates the current operation with a deprecation message.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ private function registerSecurityConfiguration(ContainerBuilder $container, arra

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

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6446;

use ApiPlatform\Metadata\Post;
use Symfony\Component\Validator\Constraints\NotNull;

#[Post(uriTemplate: 'issue_6446', securityPostValidation: 'is_granted(\'ROLE_ADMIN\')')]
class SecurityPostValidation
{
#[NotNull]
public string $title;
}
50 changes: 3 additions & 47 deletions tests/Hydra/JsonSchema/SchemaFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Metadata\Property\PropertyNameCollection;
Expand Down Expand Up @@ -50,7 +49,6 @@ protected function setUp(): void

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

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

$this->assertTrue($resultSchema->isDefined());
$this->assertSame('Dummy.jsonld.output', $resultSchema->getRootDefinitionKey());

$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_INPUT, new Post());

$this->assertTrue($resultSchema->isDefined());
$this->assertSame('Dummy.jsonld.input', $resultSchema->getRootDefinitionKey());
$this->assertSame('Dummy.jsonld', $resultSchema->getRootDefinitionKey());
}

public function testCustomFormatBuildSchema(): void
Expand All @@ -101,6 +94,7 @@ public function testHasRootDefinitionKeyBuildSchema(): void
$this->assertArrayHasKey('@context', $properties);
$this->assertEquals(
[
'readOnly' => true,
'oneOf' => [
['type' => 'string'],
[
Expand Down Expand Up @@ -128,7 +122,7 @@ public function testHasRootDefinitionKeyBuildSchema(): void
public function testSchemaTypeBuildSchema(): void
{
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, new GetCollection());
$definitionName = 'Dummy.jsonld.output';
$definitionName = 'Dummy.jsonld';

$this->assertNull($resultSchema->getRootDefinitionKey());
// @noRector
Expand Down Expand Up @@ -157,12 +151,6 @@ public function testSchemaTypeBuildSchema(): void
$this->assertArrayNotHasKey('@context', $properties);
$this->assertArrayHasKey('@type', $properties);
$this->assertArrayHasKey('@id', $properties);

$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_INPUT, new Post());
$definitionName = 'Dummy.jsonld.input';

$this->assertSame($definitionName, $resultSchema->getRootDefinitionKey());
$this->assertFalse(isset($resultSchema['properties']));
}

public function testHasHydraViewNavigationBuildSchema(): void
Expand All @@ -180,36 +168,4 @@ public function testHasHydraViewNavigationBuildSchema(): void
$this->assertArrayHasKey('hydra:previous', $resultSchema['properties']['hydra:view']['properties']);
$this->assertArrayHasKey('hydra:next', $resultSchema['properties']['hydra:view']['properties']);
}

public function testRequiredBasePropertiesBuildSchema(): void
{
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class);
$definitions = $resultSchema->getDefinitions();
$rootDefinitionKey = $resultSchema->getRootDefinitionKey();

$this->assertTrue(isset($definitions[$rootDefinitionKey]));
$this->assertTrue(isset($definitions[$rootDefinitionKey]['required']));
$requiredProperties = $resultSchema['definitions'][$rootDefinitionKey]['required'];
$this->assertContains('@context', $requiredProperties);
$this->assertContains('@id', $requiredProperties);
$this->assertContains('@type', $requiredProperties);

$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, new GetCollection());
$definitions = $resultSchema->getDefinitions();
$itemsDefinitionKey = array_key_first($definitions->getArrayCopy());

$this->assertTrue(isset($definitions[$itemsDefinitionKey]));
$this->assertTrue(isset($definitions[$itemsDefinitionKey]['required']));
$requiredProperties = $resultSchema['definitions'][$itemsDefinitionKey]['required'];
$this->assertNotContains('@context', $requiredProperties);
$this->assertContains('@id', $requiredProperties);
$this->assertContains('@type', $requiredProperties);

$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_INPUT, new Post());
$definitions = $resultSchema->getDefinitions();
$itemsDefinitionKey = array_key_first($definitions->getArrayCopy());

$this->assertTrue(isset($definitions[$itemsDefinitionKey]));
$this->assertFalse(isset($definitions[$itemsDefinitionKey]['required']));
}
}
Loading

0 comments on commit 8365310

Please sign in to comment.