Skip to content

Commit

Permalink
Merge ea29302 into e867d07
Browse files Browse the repository at this point in the history
  • Loading branch information
ttskch committed May 13, 2024
2 parents e867d07 + ea29302 commit bd64c0b
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 19 deletions.
2 changes: 1 addition & 1 deletion 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"
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"

# Deprecations
And the JSON node "paths./dummies.get.deprecated" should be false
Expand Down
20 changes: 20 additions & 0 deletions src/Hydra/JsonSchema/SchemaFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,38 @@ public function buildSchema(string $className, string $format = 'jsonld', string
return $schema;
}

if (($key = $schema->getRootDefinitionKey() ?? $schema->getItemsDefinitionKey()) !== null) {
$postfix = '.'.$type;
$typedKey = $key.$postfix;
$definitions = $schema->getDefinitions();
$definitions[$typedKey] = $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'] ?? []);
foreach (array_keys(self::BASE_ROOT_PROPS) as $property) {
$definitions[$key]['required'] = array_unique([...($definitions[$key]['required'] ?? []), $property]);
}

return $schema;
}
if ($key = $schema->getItemsDefinitionKey()) {
$definitions[$key]['properties'] = self::BASE_PROPS + ($definitions[$key]['properties'] ?? []);
foreach (array_keys(self::BASE_PROPS) as $property) {
$definitions[$key]['required'] = array_unique([...($definitions[$key]['required'] ?? []), $property]);
}
}

if (($schema['type'] ?? '') === 'array') {
Expand Down
55 changes: 53 additions & 2 deletions tests/Hydra/JsonSchema/SchemaFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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 @@ -49,6 +50,7 @@ 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 @@ -69,7 +71,12 @@ public function testBuildSchema(): void
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class);

$this->assertTrue($resultSchema->isDefined());
$this->assertSame('Dummy.jsonld', $resultSchema->getRootDefinitionKey());
$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());
}

public function testCustomFormatBuildSchema(): void
Expand Down Expand Up @@ -122,7 +129,7 @@ public function testHasRootDefinitionKeyBuildSchema(): void
public function testSchemaTypeBuildSchema(): void
{
$resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, new GetCollection());
$definitionName = 'Dummy.jsonld';
$definitionName = 'Dummy.jsonld.output';

$this->assertNull($resultSchema->getRootDefinitionKey());
// @noRector
Expand Down Expand Up @@ -151,6 +158,12 @@ 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 @@ -168,4 +181,42 @@ 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();

// @noRector
$this->assertTrue(isset($definitions[$rootDefinitionKey]));
// @noRector
$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());

// @noRector
$this->assertTrue(isset($definitions[$itemsDefinitionKey]));
// @noRector
$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());

// @noRector
$this->assertTrue(isset($definitions[$itemsDefinitionKey]));
// @noRector
$this->assertFalse(isset($definitions[$itemsDefinitionKey]['required']));
}
}
32 changes: 16 additions & 16 deletions tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']['properties']['tests'], [
$this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['tests'], [
'type' => 'string',
'foo' => 'bar',
]);

$this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['nonResourceTests'], [
$this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['nonResourceTests'], [
'type' => 'array',
'items' => [
'$ref' => '#/definitions/NonResourceTestEntity.jsonld-write',
'$ref' => '#/definitions/NonResourceTestEntity.jsonld-write.input',
],
]);

$this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['description'], [
$this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['description'], [
'maxLength' => 255,
]);

$this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['type'], [
'$ref' => '#/definitions/TestEntity.jsonld-write',
$this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['type'], [
'$ref' => '#/definitions/TestEntity.jsonld-write.input',
]);
}

Expand All @@ -130,14 +130,14 @@ public function testArraySchemaWithMultipleUnionTypesJsonLd(): void
$result = $this->tester->getDisplay();
$json = json_decode($result, associative: true);

$this->assertEquals($json['definitions']['Nest.jsonld']['properties']['owner']['anyOf'], [
['$ref' => '#/definitions/Wren.jsonld'],
['$ref' => '#/definitions/Robin.jsonld'],
$this->assertEquals($json['definitions']['Nest.jsonld.output']['properties']['owner']['anyOf'], [
['$ref' => '#/definitions/Wren.jsonld.output'],
['$ref' => '#/definitions/Robin.jsonld.output'],
['type' => 'null'],
]);

$this->assertArrayHasKey('Wren.jsonld', $json['definitions']);
$this->assertArrayHasKey('Robin.jsonld', $json['definitions']);
$this->assertArrayHasKey('Wren.jsonld.output', $json['definitions']);
$this->assertArrayHasKey('Robin.jsonld.output', $json['definitions']);
}

public function testArraySchemaWithMultipleUnionTypesJsonApi(): void
Expand Down Expand Up @@ -183,7 +183,7 @@ public function testArraySchemaWithTypeFactory(): void
$result = $this->tester->getDisplay();
$json = json_decode($result, associative: true);

$this->assertEquals($json['definitions']['Foo.jsonld']['properties']['expiration'], ['type' => 'string', 'format' => 'date']);
$this->assertEquals($json['definitions']['Foo.jsonld.output']['properties']['expiration'], ['type' => 'string', 'format' => 'date']);
}

/**
Expand All @@ -195,7 +195,7 @@ public function testWritableNonResourceRef(): void
$result = $this->tester->getDisplay();
$json = json_decode($result, associative: true);

$this->assertEquals($json['definitions']['SaveProduct.jsonld']['properties']['codes']['items']['$ref'], '#/definitions/ProductCode.jsonld');
$this->assertEquals($json['definitions']['SaveProduct.jsonld.input']['properties']['codes']['items']['$ref'], '#/definitions/ProductCode.jsonld.input');
}

/**
Expand All @@ -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']['properties']['itemDto']['$ref']);
$this->assertEquals('#/definitions/DummyDate', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld']['properties']['collectionDto']['items']['$ref']);
$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']);
}

/**
Expand All @@ -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']['properties']);
$this->assertArrayHasKey('@id', $json['definitions']['ThirdLevel.jsonld-friends.output']['properties']);
}

public function testJsonApiIncludesSchema(): void
Expand Down

0 comments on commit bd64c0b

Please sign in to comment.