From e4d701e2b33621d3a63165fd7c2ef5b541d52e79 Mon Sep 17 00:00:00 2001 From: Maxime Veber Date: Tue, 10 Jul 2018 10:00:59 +0200 Subject: [PATCH 1/2] Add support for ignore property exist test for interface 1. it makes no sens to check if an interface exists in case it's an interface 2. If the property is not recognized as one and there is no identifier, then api platform will not be able to call the DataProvider for a given item and interface as a resource is an incomplete feature. --- features/main/table_inheritance.feature | 35 +++++++++++++++++++ .../ExtractorPropertyMetadataFactory.php | 6 ++-- .../FileConfigurations/interface_resource.yml | 8 ++++- ...rceInterfaceImplementationDataProvider.php | 6 +++- .../OtherResources/ResourceInterface.php | 2 ++ .../ResourceInterfaceImplementation.php | 5 +++ .../Resources/config/api_resources.yml | 4 +++ .../ExtractorPropertyMetadataFactoryTest.php | 15 ++++++++ 8 files changed, 77 insertions(+), 4 deletions(-) diff --git a/features/main/table_inheritance.feature b/features/main/table_inheritance.feature index 54971c078aa..f1a12c15a3c 100644 --- a/features/main/table_inheritance.feature +++ b/features/main/table_inheritance.feature @@ -327,3 +327,38 @@ Feature: Table inheritance "required": ["hydra:member"] } """ + + Scenario: Get an interface resource item + When I send a "GET" request to "/resource_interfaces/some-id" + Then the response status code should be 200 + And the response should be in JSON + And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" + And the JSON should be valid according to this schema: + """ + { + "type": "object", + "properties": { + "context": { + "type": "string", + "pattern": "ResourceInterface$" + }, + "@id": { + "type": "string", + "pattern": "resource_interfaces$" + }, + "@type": { + "type": "string", + "pattern": "^ResourceInterface$" + }, + "foo": { + "type": "string", + "required": "true" + }, + "fooz": { + "type": "string", + "required": "true", + "pattern": "fooz" + } + } + } + """ diff --git a/src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php b/src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php index ee886f80e60..ecf31999fd8 100644 --- a/src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php +++ b/src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php @@ -48,9 +48,11 @@ public function create(string $resourceClass, string $property, array $options = } } + $isInterface = interface_exists($resourceClass); + if ( - !property_exists($resourceClass, $property) || - !$propertyMetadata = $this->extractor->getResources()[$resourceClass]['properties'][$property] ?? false + !property_exists($resourceClass, $property) && !$isInterface || + null === ($propertyMetadata = $this->extractor->getResources()[$resourceClass]['properties'][$property] ?? null) ) { return $this->handleNotFound($parentPropertyMetadata, $resourceClass, $property); } diff --git a/tests/Fixtures/FileConfigurations/interface_resource.yml b/tests/Fixtures/FileConfigurations/interface_resource.yml index 40c2b44b814..9f0afd51cfc 100644 --- a/tests/Fixtures/FileConfigurations/interface_resource.yml +++ b/tests/Fixtures/FileConfigurations/interface_resource.yml @@ -1,2 +1,8 @@ resources: - 'ApiPlatform\Core\Tests\Fixtures\DummyResourceInterface': ~ + 'ApiPlatform\Core\Tests\Fixtures\DummyResourceInterface': + properties: + something: + identifier: true + somethingElse: + writable: false + readable: true diff --git a/tests/Fixtures/TestBundle/DataProvider/ResourceInterfaceImplementationDataProvider.php b/tests/Fixtures/TestBundle/DataProvider/ResourceInterfaceImplementationDataProvider.php index 613ef8f5ec9..2804452b242 100644 --- a/tests/Fixtures/TestBundle/DataProvider/ResourceInterfaceImplementationDataProvider.php +++ b/tests/Fixtures/TestBundle/DataProvider/ResourceInterfaceImplementationDataProvider.php @@ -28,7 +28,11 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []) { - return (new ResourceInterfaceImplementation())->setFoo('single item'); + if ('some-id' === $id) { + return (new ResourceInterfaceImplementation())->setFoo('single item'); + } + + return null; } public function getCollection(string $resourceClass, string $operationName = null) diff --git a/tests/Fixtures/TestBundle/OtherResources/ResourceInterface.php b/tests/Fixtures/TestBundle/OtherResources/ResourceInterface.php index edd4162de5d..9335c41f4c4 100644 --- a/tests/Fixtures/TestBundle/OtherResources/ResourceInterface.php +++ b/tests/Fixtures/TestBundle/OtherResources/ResourceInterface.php @@ -16,4 +16,6 @@ interface ResourceInterface { public function getFoo(): string; + + public function getFooz(): string; } diff --git a/tests/Fixtures/TestBundle/OtherResources/ResourceInterfaceImplementation.php b/tests/Fixtures/TestBundle/OtherResources/ResourceInterfaceImplementation.php index e5e571dc27f..afec2000958 100644 --- a/tests/Fixtures/TestBundle/OtherResources/ResourceInterfaceImplementation.php +++ b/tests/Fixtures/TestBundle/OtherResources/ResourceInterfaceImplementation.php @@ -51,4 +51,9 @@ public function getBar(): ?string { return $this->bar; } + + public function getFooz(): string + { + return 'fooz'; + } } diff --git a/tests/Fixtures/TestBundle/Resources/config/api_resources.yml b/tests/Fixtures/TestBundle/Resources/config/api_resources.yml index d504f5e2b39..5bf4b7afadd 100644 --- a/tests/Fixtures/TestBundle/Resources/config/api_resources.yml +++ b/tests/Fixtures/TestBundle/Resources/config/api_resources.yml @@ -7,3 +7,7 @@ resources: collectionOperations: get: method: 'GET' + + properties: + foo: + identifier: true diff --git a/tests/Metadata/Property/Factory/ExtractorPropertyMetadataFactoryTest.php b/tests/Metadata/Property/Factory/ExtractorPropertyMetadataFactoryTest.php index e420be7e3de..82cd34f8f33 100644 --- a/tests/Metadata/Property/Factory/ExtractorPropertyMetadataFactoryTest.php +++ b/tests/Metadata/Property/Factory/ExtractorPropertyMetadataFactoryTest.php @@ -21,6 +21,7 @@ use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\PropertyMetadata; use ApiPlatform\Core\Metadata\Property\SubresourceMetadata; +use ApiPlatform\Core\Tests\Fixtures\DummyResourceInterface; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\FileConfigDummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy; use Doctrine\Common\Collections\ArrayCollection; @@ -237,4 +238,18 @@ public function testCreateWithMalformedYaml() (new ExtractorPropertyMetadataFactory(new YamlExtractor([$configPath])))->create(FileConfigDummy::class, 'foo'); } + + public function testItExtractPropertiesFromInterfaceResources() + { + $configPath = __DIR__.'/../../../Fixtures/FileConfigurations/interface_resource.yml'; + + $propertyMetadataFactory = new ExtractorPropertyMetadataFactory(new YamlExtractor([$configPath])); + $metadataSomething = $propertyMetadataFactory->create(DummyResourceInterface::class, 'something'); + $metadataSomethingElse = $propertyMetadataFactory->create(DummyResourceInterface::class, 'somethingElse'); + + $this->assertInstanceOf(PropertyMetadata::class, $metadataSomething); + $this->assertInstanceOf(PropertyMetadata::class, $metadataSomethingElse); + $this->assertTrue($metadataSomething->isIdentifier()); + $this->assertFalse($metadataSomethingElse->isWritable()); + } } From e05809e829edeb34fb35bf9c7d2f36c37d5cf3b0 Mon Sep 17 00:00:00 2001 From: "Nek (Maxime Veber)" Date: Sat, 6 Apr 2019 14:18:20 +0200 Subject: [PATCH 2/2] Removing id/context keys from interfaces resources It should work like this but sadly it does not ATM. This is some WIP and should not be tested for now. --- features/main/table_inheritance.feature | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/features/main/table_inheritance.feature b/features/main/table_inheritance.feature index f1a12c15a3c..3cf9c9e46f9 100644 --- a/features/main/table_inheritance.feature +++ b/features/main/table_inheritance.feature @@ -307,15 +307,11 @@ Feature: Table inheritance "items": { "type": "object", "properties": { - "@type": { - "type": "string", - "pattern": "^ResourceInterface$" - }, - "@id": { + "foo": { "type": "string", - "pattern": "^_:" + "required": "true" }, - "foo": { + "fooz": { "type": "string", "required": "true" } @@ -342,14 +338,6 @@ Feature: Table inheritance "type": "string", "pattern": "ResourceInterface$" }, - "@id": { - "type": "string", - "pattern": "resource_interfaces$" - }, - "@type": { - "type": "string", - "pattern": "^ResourceInterface$" - }, "foo": { "type": "string", "required": "true"