From 2987cce2607faf4dae85285714f6754024373809 Mon Sep 17 00:00:00 2001 From: Jachim Coudenys Date: Fri, 9 Jul 2021 14:45:49 +0200 Subject: [PATCH 01/13] feat: add a json schema builder for HAL (based on Hydra) --- .../Symfony/Bundle/Resources/config/hal.xml | 6 + src/Hal/JsonSchema/SchemaFactory.php | 157 ++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/Hal/JsonSchema/SchemaFactory.php diff --git a/src/Core/Bridge/Symfony/Bundle/Resources/config/hal.xml b/src/Core/Bridge/Symfony/Bundle/Resources/config/hal.xml index 5095e6b41ab..c7a5fbec648 100644 --- a/src/Core/Bridge/Symfony/Bundle/Resources/config/hal.xml +++ b/src/Core/Bridge/Symfony/Bundle/Resources/config/hal.xml @@ -54,6 +54,12 @@ + + + + + + diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php new file mode 100644 index 00000000000..ca14e872481 --- /dev/null +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -0,0 +1,157 @@ + + * + * 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\Core\Hal\JsonSchema; + +use ApiPlatform\Core\JsonSchema\Schema; +use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; +use ApiPlatform\Core\JsonSchema\SchemaFactoryInterface; + +/** + * Decorator factory which adds HAL properties to the JSON Schema document. + * + * @experimental + * + * @author Kévin Dunglas + * @author Jachim Coudenys + */ +final class SchemaFactory implements SchemaFactoryInterface +{ + private const BASE_PROPS = [ + '_links' => [ + 'type' => 'object', + 'properties' => [ + 'self' => [ + 'type' => 'object', + 'properties' => [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ] + ], + ], + ], + ], + ]; + + private $schemaFactory; + + public function __construct(SchemaFactoryInterface $schemaFactory) + { + $this->schemaFactory = $schemaFactory; + + if ($schemaFactory instanceof BaseSchemaFactory) { + $schemaFactory->addDistinctFormat('jsonhal'); + } + } + + /** + * {@inheritdoc} + */ + public function buildSchema(string $className, string $format = 'jsonhal', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false): Schema + { + $schema = $this->schemaFactory->buildSchema($className, $format, $type, $operationType, $operationName, $schema, $serializerContext, $forceCollection); + if ('jsonhal' !== $format) { + return $schema; + } + + $definitions = $schema->getDefinitions(); + if ($key = $schema->getRootDefinitionKey()) { + $definitions[$key]['properties'] = self::BASE_PROPS + ($definitions[$key]['properties'] ?? []); + + return $schema; + } + if ($key = $schema->getItemsDefinitionKey()) { + $definitions[$key]['properties'] = self::BASE_PROPS + ($definitions[$key]['properties'] ?? []); + } + + if (($schema['type'] ?? '') === 'array') { + $items = $schema['items']; + unset($schema['items']); + + $schema['type'] = 'object'; + $schema['properties'] = [ + '_embedded' => [ + 'type' => 'array', + 'items' => $items, + ], + 'totalItems' => [ + 'type' => 'integer', + 'minimum' => 0, + ], + 'itemsPerPage' => [ + 'type' => 'integer', + 'minimum' => 0, + ], + '_links' => [ + 'type' => 'object', + 'properties' => [ + 'self' => [ + 'type' => 'object', + 'properties' => [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ] + ], + ], + 'first' => [ + 'type' => 'object', + 'properties' => [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ] + ], + ], + 'last' => [ + 'type' => 'object', + 'properties' => [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ] + ], + ], + 'next' => [ + 'type' => 'object', + 'properties' => [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ] + ], + ], + 'previous' => [ + 'type' => 'object', + 'properties' => [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ] + ], + ], + ], + ], + ]; + $schema['required'] = [ + '_links', + '_embedded', + ]; + + return $schema; + } + + return $schema; + } +} From d1e05b0c41752d586477f74099d8c1f8b6403bbc Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Mon, 12 Jul 2021 10:38:47 +0200 Subject: [PATCH 02/13] extract href property in constant for hal schemafactory --- src/Hal/JsonSchema/SchemaFactory.php | 48 +++++++--------------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index ca14e872481..e5745a12005 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -27,18 +27,19 @@ */ final class SchemaFactory implements SchemaFactoryInterface { + private const HREF_PROP = [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ] + ]; private const BASE_PROPS = [ '_links' => [ 'type' => 'object', 'properties' => [ 'self' => [ 'type' => 'object', - 'properties' => [ - 'href' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ] - ], + 'properties' => self::HREF_PROP, ], ], ], @@ -98,48 +99,23 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin 'properties' => [ 'self' => [ 'type' => 'object', - 'properties' => [ - 'href' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ] - ], + 'properties' => self::HREF_PROP, ], 'first' => [ 'type' => 'object', - 'properties' => [ - 'href' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ] - ], + 'properties' => self::HREF_PROP, ], 'last' => [ 'type' => 'object', - 'properties' => [ - 'href' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ] - ], + 'properties' => self::HREF_PROP, ], 'next' => [ 'type' => 'object', - 'properties' => [ - 'href' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ] - ], + 'properties' => self::HREF_PROP, ], 'previous' => [ 'type' => 'object', - 'properties' => [ - 'href' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ] - ], + 'properties' => self::HREF_PROP, ], ], ], From df08ca7e6da92dc3e080ab05e3088519cb31db56 Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Mon, 12 Jul 2021 10:39:16 +0200 Subject: [PATCH 03/13] write tests for hal schema factory --- src/Hal/JsonSchema/SchemaFactory.php | 2 +- tests/Hal/JsonSchema/SchemaFactoryTest.php | 139 +++++++++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 tests/Hal/JsonSchema/SchemaFactoryTest.php diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index e5745a12005..6643f34f95a 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -31,7 +31,7 @@ final class SchemaFactory implements SchemaFactoryInterface 'href' => [ 'type' => 'string', 'format' => 'iri-reference', - ] + ], ]; private const BASE_PROPS = [ '_links' => [ diff --git a/tests/Hal/JsonSchema/SchemaFactoryTest.php b/tests/Hal/JsonSchema/SchemaFactoryTest.php new file mode 100644 index 00000000000..0830e29939c --- /dev/null +++ b/tests/Hal/JsonSchema/SchemaFactoryTest.php @@ -0,0 +1,139 @@ + + * + * 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\Core\Tests\Hal\JsonSchema; + +use ApiPlatform\Core\Api\OperationType; +use ApiPlatform\Core\Hydra\JsonSchema\SchemaFactory; +use ApiPlatform\Core\JsonLd\ContextBuilder; +use ApiPlatform\Core\JsonSchema\Schema; +use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; +use ApiPlatform\Core\JsonSchema\TypeFactoryInterface; +use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; +use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; +use ApiPlatform\Core\Metadata\Property\PropertyNameCollection; +use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; +use ApiPlatform\Core\Metadata\Resource\ResourceMetadata; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; +use ApiPlatform\Core\Tests\ProphecyTrait; +use PHPUnit\Framework\TestCase; + +class SchemaFactoryTest extends TestCase +{ + use ProphecyTrait; + + private $schemaFactory; + + protected function setUp(): void + { + $typeFactory = $this->prophesize(TypeFactoryInterface::class); + $resourceMetadataFactory = $this->prophesize(ResourceMetadataFactoryInterface::class); + $resourceMetadataFactory->create(Dummy::class)->willReturn(new ResourceMetadata(Dummy::class)); + $propertyNameCollectionFactory = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyNameCollectionFactory->create(Dummy::class, ['enable_getter_setter_extraction' => true])->willReturn(new PropertyNameCollection()); + $propertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class); + + $baseSchemaFactory = new BaseSchemaFactory( + $typeFactory->reveal(), + $resourceMetadataFactory->reveal(), + $propertyNameCollectionFactory->reveal(), + $propertyMetadataFactory->reveal() + ); + + $this->schemaFactory = new SchemaFactory($baseSchemaFactory); + } + + public function testBuildSchema(): void + { + $resultSchema = $this->schemaFactory->buildSchema(Dummy::class); + + $this->assertTrue($resultSchema->isDefined()); + $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonld', $resultSchema->getRootDefinitionKey()); + } + + public function testCustomFormatBuildSchema(): void + { + $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'json'); + + $this->assertTrue($resultSchema->isDefined()); + $this->assertEquals(str_replace('\\', '.', Dummy::class), $resultSchema->getRootDefinitionKey()); + } + + public function testHasRootDefinitionKeyBuildSchema(): void + { + $resultSchema = $this->schemaFactory->buildSchema(Dummy::class); + $definitions = $resultSchema->getDefinitions(); + $rootDefinitionKey = $resultSchema->getRootDefinitionKey(); + + $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonld', $rootDefinitionKey); + $this->assertArrayHasKey($rootDefinitionKey, $definitions); + $this->assertArrayHasKey('properties', $definitions[$rootDefinitionKey]); + $properties = $resultSchema['definitions'][$rootDefinitionKey]['properties']; + $this->assertArrayHasKey('@context', $properties); + $this->assertSame( + [ + 'readOnly' => true, + 'oneOf' => [ + ['type' => 'string'], + [ + 'type' => 'object', + 'properties' => [ + '@vocab' => [ + 'type' => 'string', + ], + 'hydra' => [ + 'type' => 'string', + 'enum' => [ContextBuilder::HYDRA_NS], + ], + ], + 'required' => ['@vocab', 'hydra'], + 'additionalProperties' => true, + ], + ], + ], + $properties['@context'] + ); + $this->assertArrayHasKey('@type', $properties); + $this->assertArrayHasKey('@id', $properties); + } + + public function testSchemaTypeBuildSchema(): void + { + $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, OperationType::COLLECTION); + $definitionName = str_replace('\\', '.', Dummy::class).'.jsonld'; + + $this->assertNull($resultSchema->getRootDefinitionKey()); + $this->assertArrayHasKey('properties', $resultSchema); + $this->assertArrayHasKey('hydra:member', $resultSchema['properties']); + $this->assertArrayHasKey('hydra:totalItems', $resultSchema['properties']); + $this->assertArrayHasKey('hydra:view', $resultSchema['properties']); + $this->assertArrayHasKey('hydra:search', $resultSchema['properties']); + $properties = $resultSchema['definitions'][$definitionName]['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); + + $this->assertNull($resultSchema->getRootDefinitionKey()); + $this->assertArrayHasKey('properties', $resultSchema); + $this->assertArrayHasKey('hydra:member', $resultSchema['properties']); + $this->assertArrayHasKey('hydra:totalItems', $resultSchema['properties']); + $this->assertArrayHasKey('hydra:view', $resultSchema['properties']); + $this->assertArrayHasKey('hydra:search', $resultSchema['properties']); + $properties = $resultSchema['definitions'][$definitionName]['properties']; + $this->assertArrayNotHasKey('@context', $properties); + $this->assertArrayHasKey('@type', $properties); + $this->assertArrayHasKey('@id', $properties); + } +} From 5e5860d8a78610c2088143de3d80890fea043500 Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Tue, 13 Jul 2021 09:12:20 +0200 Subject: [PATCH 04/13] add definition in tests --- .../Bundle/DependencyInjection/ApiPlatformExtensionTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Core/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Core/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php index 51248ac0566..33a7cd946fa 100644 --- a/tests/Core/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php +++ b/tests/Core/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php @@ -1266,6 +1266,7 @@ private function getBaseContainerBuilderProphecyWithoutDefaultMetadataLoading(ar { $hasSwagger = null === $configuration || true === $configuration['api_platform']['enable_swagger'] ?? false; $hasHydra = null === $configuration || isset($configuration['api_platform']['formats']['jsonld']); + $hasHal = null === $configuration || isset($configuration['api_platform']['formats']['jsonhal']); $containerBuilderProphecy = $this->getPartialContainerBuilderProphecy($configuration); @@ -1607,6 +1608,10 @@ private function getBaseContainerBuilderProphecyWithoutDefaultMetadataLoading(ar $definitions[] = 'api_platform.jsonld.normalizer.object'; } + if ($hasHal) { + $definitions[] = 'api_platform.hal.json_schema.schema_factory'; + } + // Ignore inlined services $containerBuilderProphecy->setDefinition(Argument::that(static function (string $arg) { return 0 === strpos($arg, '.'); From 45fdb6fe63969f3409715413f4b5f306cf0eb49f Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Wed, 14 Jul 2021 13:20:03 +0200 Subject: [PATCH 05/13] add distinct format --- src/Core/Hydra/JsonSchema/SchemaFactory.php | 10 ++++++---- src/Core/JsonSchema/SchemaFactoryInterface.php | 2 ++ src/Hal/JsonSchema/SchemaFactory.php | 12 ++++++++---- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Core/Hydra/JsonSchema/SchemaFactory.php b/src/Core/Hydra/JsonSchema/SchemaFactory.php index 4c5d3a1ba68..3ef6cec12c0 100644 --- a/src/Core/Hydra/JsonSchema/SchemaFactory.php +++ b/src/Core/Hydra/JsonSchema/SchemaFactory.php @@ -63,10 +63,7 @@ final class SchemaFactory implements SchemaFactoryInterface public function __construct(SchemaFactoryInterface $schemaFactory) { $this->schemaFactory = $schemaFactory; - - if ($schemaFactory instanceof BaseSchemaFactory) { - $schemaFactory->addDistinctFormat('jsonld'); - } + $schemaFactory->addDistinctFormat('jsonld'); } /** @@ -173,4 +170,9 @@ public function buildSchema(string $className, string $format = 'jsonld', string return $schema; } + + public function addDistinctFormat(string $format): void + { + $this->schemaFactory->addDistinctFormat($format); + } } diff --git a/src/Core/JsonSchema/SchemaFactoryInterface.php b/src/Core/JsonSchema/SchemaFactoryInterface.php index 0b14048b461..b0267c90830 100644 --- a/src/Core/JsonSchema/SchemaFactoryInterface.php +++ b/src/Core/JsonSchema/SchemaFactoryInterface.php @@ -26,4 +26,6 @@ interface SchemaFactoryInterface * Builds the JSON Schema document corresponding to the given PHP class. */ public function buildSchema(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false): Schema; + + public function addDistinctFormat(string $format): void; } diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index 6643f34f95a..31d3fa28896 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -50,10 +50,7 @@ final class SchemaFactory implements SchemaFactoryInterface public function __construct(SchemaFactoryInterface $schemaFactory) { $this->schemaFactory = $schemaFactory; - - if ($schemaFactory instanceof BaseSchemaFactory) { - $schemaFactory->addDistinctFormat('jsonhal'); - } + $schemaFactory->addDistinctFormat('jsonhal'); } /** @@ -130,4 +127,11 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin return $schema; } + + public function addDistinctFormat(string $format): void + { + $this->schemaFactory->addDistinctFormat($format); + } + + } From dc331a5d550795b2c81876e835a2b3226e5b7a84 Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Wed, 14 Jul 2021 13:41:48 +0200 Subject: [PATCH 06/13] decorated hal schema factory --- tests/Hal/JsonSchema/SchemaFactoryTest.php | 70 ++++++++++------------ 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/tests/Hal/JsonSchema/SchemaFactoryTest.php b/tests/Hal/JsonSchema/SchemaFactoryTest.php index 0830e29939c..9a5d41a724f 100644 --- a/tests/Hal/JsonSchema/SchemaFactoryTest.php +++ b/tests/Hal/JsonSchema/SchemaFactoryTest.php @@ -14,10 +14,10 @@ namespace ApiPlatform\Core\Tests\Hal\JsonSchema; use ApiPlatform\Core\Api\OperationType; -use ApiPlatform\Core\Hydra\JsonSchema\SchemaFactory; -use ApiPlatform\Core\JsonLd\ContextBuilder; +use ApiPlatform\Core\Hal\JsonSchema\SchemaFactory; use ApiPlatform\Core\JsonSchema\Schema; use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; +use ApiPlatform\Core\Hydra\JsonSchema\SchemaFactory as HydraSchemaFactory; use ApiPlatform\Core\JsonSchema\TypeFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; @@ -50,7 +50,9 @@ protected function setUp(): void $propertyMetadataFactory->reveal() ); - $this->schemaFactory = new SchemaFactory($baseSchemaFactory); + $hydraSchemaFactory = new HydraSchemaFactory($baseSchemaFactory); + + $this->schemaFactory = new SchemaFactory($hydraSchemaFactory); } public function testBuildSchema(): void @@ -58,7 +60,7 @@ public function testBuildSchema(): void $resultSchema = $this->schemaFactory->buildSchema(Dummy::class); $this->assertTrue($resultSchema->isDefined()); - $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonld', $resultSchema->getRootDefinitionKey()); + $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonhal', $resultSchema->getRootDefinitionKey()); } public function testCustomFormatBuildSchema(): void @@ -75,65 +77,53 @@ public function testHasRootDefinitionKeyBuildSchema(): void $definitions = $resultSchema->getDefinitions(); $rootDefinitionKey = $resultSchema->getRootDefinitionKey(); - $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonld', $rootDefinitionKey); + $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonhal', $rootDefinitionKey); $this->assertArrayHasKey($rootDefinitionKey, $definitions); $this->assertArrayHasKey('properties', $definitions[$rootDefinitionKey]); $properties = $resultSchema['definitions'][$rootDefinitionKey]['properties']; - $this->assertArrayHasKey('@context', $properties); + $this->assertArrayHasKey('_links', $properties); $this->assertSame( [ - 'readOnly' => true, - 'oneOf' => [ - ['type' => 'string'], - [ + 'type' => 'object', + 'properties' => [ + 'self' => [ 'type' => 'object', 'properties' => [ - '@vocab' => [ - 'type' => 'string', - ], - 'hydra' => [ + 'href' => [ 'type' => 'string', - 'enum' => [ContextBuilder::HYDRA_NS], - ], - ], - 'required' => ['@vocab', 'hydra'], - 'additionalProperties' => true, - ], + 'format' => 'iri-reference', + ] + ] + ] ], ], - $properties['@context'] + $properties['_links'] ); - $this->assertArrayHasKey('@type', $properties); - $this->assertArrayHasKey('@id', $properties); } public function testSchemaTypeBuildSchema(): void { - $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, OperationType::COLLECTION); - $definitionName = str_replace('\\', '.', Dummy::class).'.jsonld'; + $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonhal', Schema::TYPE_OUTPUT, OperationType::COLLECTION); + $definitionName = str_replace('\\', '.', Dummy::class).'.jsonhal'; $this->assertNull($resultSchema->getRootDefinitionKey()); $this->assertArrayHasKey('properties', $resultSchema); - $this->assertArrayHasKey('hydra:member', $resultSchema['properties']); - $this->assertArrayHasKey('hydra:totalItems', $resultSchema['properties']); - $this->assertArrayHasKey('hydra:view', $resultSchema['properties']); - $this->assertArrayHasKey('hydra:search', $resultSchema['properties']); + $this->assertArrayHasKey('_embedded', $resultSchema['properties']); + $this->assertArrayHasKey('totalItems', $resultSchema['properties']); + $this->assertArrayHasKey('itemsPerPage', $resultSchema['properties']); + $this->assertArrayHasKey('_links', $resultSchema['properties']); $properties = $resultSchema['definitions'][$definitionName]['properties']; - $this->assertArrayNotHasKey('@context', $properties); - $this->assertArrayHasKey('@type', $properties); - $this->assertArrayHasKey('@id', $properties); + $this->assertArrayHasKey('_links', $properties); - $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, null, null, null, null, true); + $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonhal', Schema::TYPE_OUTPUT, null, null, null, null, true); $this->assertNull($resultSchema->getRootDefinitionKey()); $this->assertArrayHasKey('properties', $resultSchema); - $this->assertArrayHasKey('hydra:member', $resultSchema['properties']); - $this->assertArrayHasKey('hydra:totalItems', $resultSchema['properties']); - $this->assertArrayHasKey('hydra:view', $resultSchema['properties']); - $this->assertArrayHasKey('hydra:search', $resultSchema['properties']); + $this->assertArrayHasKey('_embedded', $resultSchema['properties']); + $this->assertArrayHasKey('totalItems', $resultSchema['properties']); + $this->assertArrayHasKey('itemsPerPage', $resultSchema['properties']); + $this->assertArrayHasKey('_links', $resultSchema['properties']); $properties = $resultSchema['definitions'][$definitionName]['properties']; - $this->assertArrayNotHasKey('@context', $properties); - $this->assertArrayHasKey('@type', $properties); - $this->assertArrayHasKey('@id', $properties); + $this->assertArrayHasKey('_links', $properties); } } From 28278b638598d1f2b853fafa81d2ec8a679f3021 Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Wed, 14 Jul 2021 14:03:59 +0200 Subject: [PATCH 07/13] fix phpcs --- src/Core/Hydra/JsonSchema/SchemaFactory.php | 1 - src/Hal/JsonSchema/SchemaFactory.php | 3 --- tests/Hal/JsonSchema/SchemaFactoryTest.php | 8 ++++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Core/Hydra/JsonSchema/SchemaFactory.php b/src/Core/Hydra/JsonSchema/SchemaFactory.php index 3ef6cec12c0..8a8351592e5 100644 --- a/src/Core/Hydra/JsonSchema/SchemaFactory.php +++ b/src/Core/Hydra/JsonSchema/SchemaFactory.php @@ -15,7 +15,6 @@ use ApiPlatform\Core\JsonLd\ContextBuilder; use ApiPlatform\Core\JsonSchema\Schema; -use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; use ApiPlatform\Core\JsonSchema\SchemaFactoryInterface; /** diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index 31d3fa28896..3d9f8af1f75 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -14,7 +14,6 @@ namespace ApiPlatform\Core\Hal\JsonSchema; use ApiPlatform\Core\JsonSchema\Schema; -use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; use ApiPlatform\Core\JsonSchema\SchemaFactoryInterface; /** @@ -132,6 +131,4 @@ public function addDistinctFormat(string $format): void { $this->schemaFactory->addDistinctFormat($format); } - - } diff --git a/tests/Hal/JsonSchema/SchemaFactoryTest.php b/tests/Hal/JsonSchema/SchemaFactoryTest.php index 9a5d41a724f..e07ca57abe4 100644 --- a/tests/Hal/JsonSchema/SchemaFactoryTest.php +++ b/tests/Hal/JsonSchema/SchemaFactoryTest.php @@ -15,9 +15,9 @@ use ApiPlatform\Core\Api\OperationType; use ApiPlatform\Core\Hal\JsonSchema\SchemaFactory; +use ApiPlatform\Core\Hydra\JsonSchema\SchemaFactory as HydraSchemaFactory; use ApiPlatform\Core\JsonSchema\Schema; use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; -use ApiPlatform\Core\Hydra\JsonSchema\SchemaFactory as HydraSchemaFactory; use ApiPlatform\Core\JsonSchema\TypeFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; @@ -92,9 +92,9 @@ public function testHasRootDefinitionKeyBuildSchema(): void 'href' => [ 'type' => 'string', 'format' => 'iri-reference', - ] - ] - ] + ], + ], + ], ], ], $properties['_links'] From 663fe9162d009e34255817ce367c9d088f1bc8e7 Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Fri, 16 Jul 2021 16:04:57 +0200 Subject: [PATCH 08/13] remove unnecessary asserts --- tests/Core/Hydra/JsonSchema/SchemaFactoryTest.php | 1 - tests/Hal/JsonSchema/SchemaFactoryTest.php | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/Core/Hydra/JsonSchema/SchemaFactoryTest.php b/tests/Core/Hydra/JsonSchema/SchemaFactoryTest.php index 9a49f041016..d1626aed920 100644 --- a/tests/Core/Hydra/JsonSchema/SchemaFactoryTest.php +++ b/tests/Core/Hydra/JsonSchema/SchemaFactoryTest.php @@ -78,7 +78,6 @@ public function testHasRootDefinitionKeyBuildSchema(): void $definitions = $resultSchema->getDefinitions(); $rootDefinitionKey = $resultSchema->getRootDefinitionKey(); - $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonld', $rootDefinitionKey); $this->assertArrayHasKey($rootDefinitionKey, $definitions); $this->assertArrayHasKey('properties', $definitions[$rootDefinitionKey]); $properties = $resultSchema['definitions'][$rootDefinitionKey]['properties']; diff --git a/tests/Hal/JsonSchema/SchemaFactoryTest.php b/tests/Hal/JsonSchema/SchemaFactoryTest.php index e07ca57abe4..91373ab2c05 100644 --- a/tests/Hal/JsonSchema/SchemaFactoryTest.php +++ b/tests/Hal/JsonSchema/SchemaFactoryTest.php @@ -77,7 +77,6 @@ public function testHasRootDefinitionKeyBuildSchema(): void $definitions = $resultSchema->getDefinitions(); $rootDefinitionKey = $resultSchema->getRootDefinitionKey(); - $this->assertEquals(str_replace('\\', '.', Dummy::class).'.jsonhal', $rootDefinitionKey); $this->assertArrayHasKey($rootDefinitionKey, $definitions); $this->assertArrayHasKey('properties', $definitions[$rootDefinitionKey]); $properties = $resultSchema['definitions'][$rootDefinitionKey]['properties']; From 5c72a68cd57dae53291b70f19484f919a709df34 Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Fri, 16 Jul 2021 16:12:40 +0200 Subject: [PATCH 09/13] removed the addDistinctFormat from the SchemaFactoryInterface --- src/Core/Hydra/JsonSchema/SchemaFactory.php | 8 ++++++-- src/Core/JsonSchema/SchemaFactoryInterface.php | 2 -- src/Hal/JsonSchema/SchemaFactory.php | 12 +++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Core/Hydra/JsonSchema/SchemaFactory.php b/src/Core/Hydra/JsonSchema/SchemaFactory.php index 8a8351592e5..2a7445dde47 100644 --- a/src/Core/Hydra/JsonSchema/SchemaFactory.php +++ b/src/Core/Hydra/JsonSchema/SchemaFactory.php @@ -15,6 +15,7 @@ use ApiPlatform\Core\JsonLd\ContextBuilder; use ApiPlatform\Core\JsonSchema\Schema; +use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; use ApiPlatform\Core\JsonSchema\SchemaFactoryInterface; /** @@ -62,7 +63,8 @@ final class SchemaFactory implements SchemaFactoryInterface public function __construct(SchemaFactoryInterface $schemaFactory) { $this->schemaFactory = $schemaFactory; - $schemaFactory->addDistinctFormat('jsonld'); + + $this->addDistinctFormat('jsonld'); } /** @@ -172,6 +174,8 @@ public function buildSchema(string $className, string $format = 'jsonld', string public function addDistinctFormat(string $format): void { - $this->schemaFactory->addDistinctFormat($format); + if ($this->schemaFactory instanceof BaseSchemaFactory) { + $this->schemaFactory->addDistinctFormat($format); + } } } diff --git a/src/Core/JsonSchema/SchemaFactoryInterface.php b/src/Core/JsonSchema/SchemaFactoryInterface.php index b0267c90830..0b14048b461 100644 --- a/src/Core/JsonSchema/SchemaFactoryInterface.php +++ b/src/Core/JsonSchema/SchemaFactoryInterface.php @@ -26,6 +26,4 @@ interface SchemaFactoryInterface * Builds the JSON Schema document corresponding to the given PHP class. */ public function buildSchema(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false): Schema; - - public function addDistinctFormat(string $format): void; } diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index 3d9f8af1f75..70f1c67c3ef 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -44,12 +44,15 @@ final class SchemaFactory implements SchemaFactoryInterface ], ]; - private $schemaFactory; + private SchemaFactoryInterface $schemaFactory; public function __construct(SchemaFactoryInterface $schemaFactory) { $this->schemaFactory = $schemaFactory; - $schemaFactory->addDistinctFormat('jsonhal'); + + if (method_exists($schemaFactory, 'addDistinctFormat')) { + $schemaFactory->addDistinctFormat('jsonhal'); + } } /** @@ -126,9 +129,4 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin return $schema; } - - public function addDistinctFormat(string $format): void - { - $this->schemaFactory->addDistinctFormat($format); - } } From 85a710e35ba28dc7b478340d7101466757b6540f Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Fri, 16 Jul 2021 16:17:00 +0200 Subject: [PATCH 10/13] fix phpstan errors --- tests/Core/Api/FilterCollectionFactoryTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Core/Api/FilterCollectionFactoryTest.php b/tests/Core/Api/FilterCollectionFactoryTest.php index 7093a60da79..fb9ef5db643 100644 --- a/tests/Core/Api/FilterCollectionFactoryTest.php +++ b/tests/Core/Api/FilterCollectionFactoryTest.php @@ -41,8 +41,7 @@ public function testCreateFilterCollectionFromLocator() $filterLocatorProphecy->has('bar')->willReturn(false)->shouldBeCalled(); $filterCollection = (new FilterCollectionFactory(['foo', 'bar']))->createFilterCollectionFromLocator($filterLocatorProphecy->reveal()); - - $this->assertArrayNotHasKey('bar', $filterCollection); + $this->assertArrayNotHasKey('bar', $filterCollection->getArrayCopy()); $this->assertTrue(isset($filterCollection['foo'])); $this->assertInstanceOf(FilterInterface::class, $filterCollection['foo']); $this->assertEquals(new FilterCollection(['foo' => $filter]), $filterCollection); From f43a7ecea95ea0ff896181facf041c978c3657f2 Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Fri, 16 Jul 2021 16:19:36 +0200 Subject: [PATCH 11/13] no typed property --- src/Hal/JsonSchema/SchemaFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index 70f1c67c3ef..39e0cf02e61 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -44,7 +44,7 @@ final class SchemaFactory implements SchemaFactoryInterface ], ]; - private SchemaFactoryInterface $schemaFactory; + private $schemaFactory; public function __construct(SchemaFactoryInterface $schemaFactory) { From 053f6487a9115dbc3b15ef95dcfcb7c8556f402a Mon Sep 17 00:00:00 2001 From: Arne De Smedt Date: Mon, 19 Jul 2021 08:05:02 +0200 Subject: [PATCH 12/13] add distinct format method for hal schema factory --- src/Hal/JsonSchema/SchemaFactory.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index 39e0cf02e61..4b74f503eeb 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -50,9 +50,7 @@ public function __construct(SchemaFactoryInterface $schemaFactory) { $this->schemaFactory = $schemaFactory; - if (method_exists($schemaFactory, 'addDistinctFormat')) { - $schemaFactory->addDistinctFormat('jsonhal'); - } + $this->addDistinctFormat('jsonhal'); } /** @@ -129,4 +127,11 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin return $schema; } + + public function addDistinctFormat(string $format): void + { + if (method_exists($this->schemaFactory, 'addDistinctFormat')) { + $this->schemaFactory->addDistinctFormat($format); + } + } } From 3709adf73e3a1fe77321a58a16cda0d29f4f6dc6 Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Fri, 24 Sep 2021 17:55:15 +0200 Subject: [PATCH 13/13] fix: namespace --- src/{ => Core}/Hal/JsonSchema/SchemaFactory.php | 0 tests/Core/Api/FilterCollectionFactoryTest.php | 3 ++- tests/{ => Core}/Hal/JsonSchema/SchemaFactoryTest.php | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) rename src/{ => Core}/Hal/JsonSchema/SchemaFactory.php (100%) rename tests/{ => Core}/Hal/JsonSchema/SchemaFactoryTest.php (98%) diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Core/Hal/JsonSchema/SchemaFactory.php similarity index 100% rename from src/Hal/JsonSchema/SchemaFactory.php rename to src/Core/Hal/JsonSchema/SchemaFactory.php diff --git a/tests/Core/Api/FilterCollectionFactoryTest.php b/tests/Core/Api/FilterCollectionFactoryTest.php index fb9ef5db643..7093a60da79 100644 --- a/tests/Core/Api/FilterCollectionFactoryTest.php +++ b/tests/Core/Api/FilterCollectionFactoryTest.php @@ -41,7 +41,8 @@ public function testCreateFilterCollectionFromLocator() $filterLocatorProphecy->has('bar')->willReturn(false)->shouldBeCalled(); $filterCollection = (new FilterCollectionFactory(['foo', 'bar']))->createFilterCollectionFromLocator($filterLocatorProphecy->reveal()); - $this->assertArrayNotHasKey('bar', $filterCollection->getArrayCopy()); + + $this->assertArrayNotHasKey('bar', $filterCollection); $this->assertTrue(isset($filterCollection['foo'])); $this->assertInstanceOf(FilterInterface::class, $filterCollection['foo']); $this->assertEquals(new FilterCollection(['foo' => $filter]), $filterCollection); diff --git a/tests/Hal/JsonSchema/SchemaFactoryTest.php b/tests/Core/Hal/JsonSchema/SchemaFactoryTest.php similarity index 98% rename from tests/Hal/JsonSchema/SchemaFactoryTest.php rename to tests/Core/Hal/JsonSchema/SchemaFactoryTest.php index 91373ab2c05..d9b44eb7f7f 100644 --- a/tests/Hal/JsonSchema/SchemaFactoryTest.php +++ b/tests/Core/Hal/JsonSchema/SchemaFactoryTest.php @@ -24,10 +24,13 @@ use ApiPlatform\Core\Metadata\Property\PropertyNameCollection; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Resource\ResourceMetadata; -use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; use ApiPlatform\Core\Tests\ProphecyTrait; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy; use PHPUnit\Framework\TestCase; +/** + * @group legacy + */ class SchemaFactoryTest extends TestCase { use ProphecyTrait;