From 90bb11cb8ffbffe86b9645967a36c16444acea7a Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Fri, 30 Oct 2020 21:15:30 +0100 Subject: [PATCH] fix: add base Hydra properties to collection items definition in JSON Schema --- src/Hydra/JsonSchema/SchemaFactory.php | 9 +++++-- src/JsonSchema/Schema.php | 26 +++++++++++++++++--- tests/Hydra/JsonSchema/SchemaFactoryTest.php | 12 +++++++++ tests/JsonSchema/SchemaTest.php | 13 ++++++++++ 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/Hydra/JsonSchema/SchemaFactory.php b/src/Hydra/JsonSchema/SchemaFactory.php index be016c9b559..41e68fdd348 100644 --- a/src/Hydra/JsonSchema/SchemaFactory.php +++ b/src/Hydra/JsonSchema/SchemaFactory.php @@ -31,10 +31,12 @@ final class SchemaFactory implements SchemaFactoryInterface 'type' => 'string', ]; private const BASE_PROPS = [ - '@context' => self::BASE_PROP, '@id' => self::BASE_PROP, '@type' => self::BASE_PROP, ]; + private const BASE_ROOT_PROPS = [ + '@context' => self::BASE_PROP, + ] + self::BASE_PROPS; private $schemaFactory; @@ -59,10 +61,13 @@ public function buildSchema(string $className, string $format = 'jsonld', string $definitions = $schema->getDefinitions(); if ($key = $schema->getRootDefinitionKey()) { - $definitions[$key]['properties'] = self::BASE_PROPS + ($definitions[$key]['properties'] ?? []); + $definitions[$key]['properties'] = self::BASE_ROOT_PROPS + ($definitions[$key]['properties'] ?? []); return $schema; } + if ($key = $schema->getItemsDefinitionKey()) { + $definitions[$key]['properties'] = self::BASE_PROPS + ($definitions[$key]['properties'] ?? []); + } if (($schema['type'] ?? '') === 'array') { // hydra:collection diff --git a/src/JsonSchema/Schema.php b/src/JsonSchema/Schema.php index 29a9add5ba8..c744869c448 100644 --- a/src/JsonSchema/Schema.php +++ b/src/JsonSchema/Schema.php @@ -100,11 +100,20 @@ public function getRootDefinitionKey(): ?string return null; } - // strlen('#/definitions/') = 14 - // strlen('#/components/schemas/') = 21 - $prefix = self::VERSION_OPENAPI === $this->version ? 21 : 14; + return $this->removeDefinitionKeyPrefix($this['$ref']); + } - return substr($this['$ref'], $prefix); + /** + * Returns the name of the items definition, if defined. + */ + public function getItemsDefinitionKey(): ?string + { + $ref = $this['items']['$ref'] ?? null; + if (null === $ref) { + return null; + } + + return $this->removeDefinitionKeyPrefix($ref); } /** @@ -114,4 +123,13 @@ public function isDefined(): bool { return isset($this['$ref']) || isset($this['type']); } + + private function removeDefinitionKeyPrefix(string $definitionKey): string + { + // strlen('#/definitions/') = 14 + // strlen('#/components/schemas/') = 21 + $prefix = self::VERSION_OPENAPI === $this->version ? 21 : 14; + + return substr($definitionKey, $prefix); + } } diff --git a/tests/Hydra/JsonSchema/SchemaFactoryTest.php b/tests/Hydra/JsonSchema/SchemaFactoryTest.php index 2a2e4a67de4..acbd7114e8d 100644 --- a/tests/Hydra/JsonSchema/SchemaFactoryTest.php +++ b/tests/Hydra/JsonSchema/SchemaFactoryTest.php @@ -77,6 +77,10 @@ public function testHasRootDefinitionKeyBuildSchema(): void $this->assertEquals(Dummy::class.':jsonld', $rootDefinitionKey); $this->assertArrayHasKey($rootDefinitionKey, $definitions); $this->assertArrayHasKey('properties', $definitions[$rootDefinitionKey]); + $properties = $resultSchema['definitions'][$rootDefinitionKey]['properties']; + $this->assertArrayHasKey('@context', $properties); + $this->assertArrayHasKey('@type', $properties); + $this->assertArrayHasKey('@id', $properties); } public function testSchemaTypeBuildSchema(): void @@ -89,6 +93,10 @@ public function testSchemaTypeBuildSchema(): void $this->assertArrayHasKey('hydra:totalItems', $resultSchema['properties']); $this->assertArrayHasKey('hydra:view', $resultSchema['properties']); $this->assertArrayHasKey('hydra:search', $resultSchema['properties']); + $properties = $resultSchema['definitions'][Dummy::class.':jsonld']['properties']; + $this->assertArrayNotHasKey('@context', $properties); + $this->assertArrayHasKey('@type', $properties); + $this->assertArrayHasKey('@id', $properties); $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, null, null, null, null, true); @@ -98,5 +106,9 @@ public function testSchemaTypeBuildSchema(): void $this->assertArrayHasKey('hydra:totalItems', $resultSchema['properties']); $this->assertArrayHasKey('hydra:view', $resultSchema['properties']); $this->assertArrayHasKey('hydra:search', $resultSchema['properties']); + $properties = $resultSchema['definitions'][Dummy::class.':jsonld']['properties']; + $this->assertArrayNotHasKey('@context', $properties); + $this->assertArrayHasKey('@type', $properties); + $this->assertArrayHasKey('@id', $properties); } } diff --git a/tests/JsonSchema/SchemaTest.php b/tests/JsonSchema/SchemaTest.php index f03a743d015..210291ceae1 100644 --- a/tests/JsonSchema/SchemaTest.php +++ b/tests/JsonSchema/SchemaTest.php @@ -31,6 +31,19 @@ public function testJsonSchemaVersion(string $version, string $ref): void $this->assertSame('Foo', $schema->getRootDefinitionKey()); } + /** + * @dataProvider versionProvider + */ + public function testCollectionJsonSchemaVersion(string $version, string $ref): void + { + $schema = new Schema($version); + $schema['items']['$ref'] = $ref; + + $this->assertInstanceOf(\ArrayObject::class, $schema); + $this->assertSame($version, $schema->getVersion()); + $this->assertSame('Foo', $schema->getItemsDefinitionKey()); + } + public function versionProvider(): iterable { yield [Schema::VERSION_JSON_SCHEMA, '#/definitions/Foo'];