diff --git a/features/openapi/docs.feature b/features/openapi/docs.feature index 4f98c666751..980b896959a 100644 --- a/features/openapi/docs.feature +++ b/features/openapi/docs.feature @@ -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 @@ -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: """ { @@ -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": { diff --git a/src/Hydra/JsonSchema/SchemaFactory.php b/src/Hydra/JsonSchema/SchemaFactory.php index 75144baee28..f51af53e3d7 100644 --- a/src/Hydra/JsonSchema/SchemaFactory.php +++ b/src/Hydra/JsonSchema/SchemaFactory.php @@ -27,6 +27,7 @@ final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareInterface { private const BASE_PROP = [ + 'readOnly' => true, 'type' => 'string', ]; private const BASE_PROPS = [ @@ -35,6 +36,7 @@ final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareI ]; private const BASE_ROOT_PROPS = [ '@context' => [ + 'readOnly' => true, 'oneOf' => [ ['type' => 'string'], [ @@ -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') { diff --git a/tests/Hydra/JsonSchema/SchemaFactoryTest.php b/tests/Hydra/JsonSchema/SchemaFactoryTest.php index 109c0cc398b..b1a6029503d 100644 --- a/tests/Hydra/JsonSchema/SchemaFactoryTest.php +++ b/tests/Hydra/JsonSchema/SchemaFactoryTest.php @@ -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; @@ -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]); @@ -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 @@ -101,6 +94,7 @@ public function testHasRootDefinitionKeyBuildSchema(): void $this->assertArrayHasKey('@context', $properties); $this->assertEquals( [ + 'readOnly' => true, 'oneOf' => [ ['type' => 'string'], [ @@ -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 @@ -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 @@ -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'])); - } } diff --git a/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php b/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php index ea24404f75b..3ef06851574 100644 --- a/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php +++ b/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php @@ -76,9 +76,9 @@ public function testExecuteWithJsonldTypeInput(): void $this->tester->run(['command' => 'api:json-schema:generate', 'resource' => $this->entityClass, '--operation' => '_api_/dummies{._format}_post', '--format' => 'jsonld', '--type' => 'input']); $result = $this->tester->getDisplay(); - $this->assertStringContainsString('@id', $result); - $this->assertStringContainsString('@context', $result); - $this->assertStringContainsString('@type', $result); + $this->assertStringNotContainsString('@id', $result); + $this->assertStringNotContainsString('@context', $result); + $this->assertStringNotContainsString('@type', $result); } /** @@ -103,24 +103,24 @@ public function testArraySchemaWithReference(): void $result = $this->tester->getDisplay(); $json = json_decode($result, associative: true); - $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['tests'], [ + $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['tests'], [ 'type' => 'string', 'foo' => 'bar', ]); - $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['nonResourceTests'], [ + $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['nonResourceTests'], [ 'type' => 'array', 'items' => [ - '$ref' => '#/definitions/NonResourceTestEntity.jsonld-write.input', + '$ref' => '#/definitions/NonResourceTestEntity.jsonld-write', ], ]); - $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['description'], [ + $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['description'], [ 'maxLength' => 255, ]); - $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['type'], [ - '$ref' => '#/definitions/TestEntity.jsonld-write.input', + $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['type'], [ + '$ref' => '#/definitions/TestEntity.jsonld-write', ]); } @@ -130,14 +130,14 @@ public function testArraySchemaWithMultipleUnionTypesJsonLd(): void $result = $this->tester->getDisplay(); $json = json_decode($result, associative: true); - $this->assertEquals($json['definitions']['Nest.jsonld.output']['properties']['owner']['anyOf'], [ - ['$ref' => '#/definitions/Wren.jsonld.output'], - ['$ref' => '#/definitions/Robin.jsonld.output'], + $this->assertEquals($json['definitions']['Nest.jsonld']['properties']['owner']['anyOf'], [ + ['$ref' => '#/definitions/Wren.jsonld'], + ['$ref' => '#/definitions/Robin.jsonld'], ['type' => 'null'], ]); - $this->assertArrayHasKey('Wren.jsonld.output', $json['definitions']); - $this->assertArrayHasKey('Robin.jsonld.output', $json['definitions']); + $this->assertArrayHasKey('Wren.jsonld', $json['definitions']); + $this->assertArrayHasKey('Robin.jsonld', $json['definitions']); } public function testArraySchemaWithMultipleUnionTypesJsonApi(): void @@ -183,7 +183,7 @@ public function testArraySchemaWithTypeFactory(): void $result = $this->tester->getDisplay(); $json = json_decode($result, associative: true); - $this->assertEquals($json['definitions']['Foo.jsonld.output']['properties']['expiration'], ['type' => 'string', 'format' => 'date']); + $this->assertEquals($json['definitions']['Foo.jsonld']['properties']['expiration'], ['type' => 'string', 'format' => 'date']); } /** @@ -195,7 +195,7 @@ public function testWritableNonResourceRef(): void $result = $this->tester->getDisplay(); $json = json_decode($result, associative: true); - $this->assertEquals($json['definitions']['SaveProduct.jsonld.input']['properties']['codes']['items']['$ref'], '#/definitions/ProductCode.jsonld.input'); + $this->assertEquals($json['definitions']['SaveProduct.jsonld']['properties']['codes']['items']['$ref'], '#/definitions/ProductCode.jsonld'); } /** @@ -207,8 +207,8 @@ public function testOpenApiResourceRefIsNotOverwritten(): void $result = $this->tester->getDisplay(); $json = json_decode($result, associative: true); - $this->assertEquals('#/definitions/DummyFriend', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld.output']['properties']['itemDto']['$ref']); - $this->assertEquals('#/definitions/DummyDate', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld.output']['properties']['collectionDto']['items']['$ref']); + $this->assertEquals('#/definitions/DummyFriend', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld']['properties']['itemDto']['$ref']); + $this->assertEquals('#/definitions/DummyDate', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld']['properties']['collectionDto']['items']['$ref']); } /** @@ -220,7 +220,7 @@ public function testSubSchemaJsonLd(): void $result = $this->tester->getDisplay(); $json = json_decode($result, associative: true); - $this->assertArrayHasKey('@id', $json['definitions']['ThirdLevel.jsonld-friends.output']['properties']); + $this->assertArrayHasKey('@id', $json['definitions']['ThirdLevel.jsonld-friends']['properties']); } public function testJsonApiIncludesSchema(): void