diff --git a/features/bootstrap/DoctrineContext.php b/features/bootstrap/DoctrineContext.php index cd03b6024d3..f143276c982 100644 --- a/features/bootstrap/DoctrineContext.php +++ b/features/bootstrap/DoctrineContext.php @@ -74,6 +74,8 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyOffer; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyProduct; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyProperty; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritanceNotApiResourceChild; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritanceNotApiResourceChild as DummyTableInheritanceNotApiResourceChildDocument; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\EmbeddableDummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\EmbeddedDummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\FileConfigDummy; @@ -165,6 +167,17 @@ public function thereAreDummyObjects(int $nb) $this->manager->flush(); } + /** + * @When some dummy table inheritance data but not api resource child are created + */ + public function someDummyTableInheritanceDataButNotApiResourceChildAreCreated() + { + $dummy = $this->buildDummyTableInheritanceNotApiResourceChild(); + $dummy->setName('Foobarbaz inheritance'); + $this->manager->persist($dummy); + $this->manager->flush(); + } + /** * @Given there are :nb foo objects with fake names */ @@ -1272,6 +1285,14 @@ private function buildDummy() return $this->isOrm() ? new Dummy() : new DummyDocument(); } + /** + * @return DummyTableInheritanceNotApiResourceChild|DummyTableInheritanceNotApiResourceChildDocument + */ + private function buildDummyTableInheritanceNotApiResourceChild() + { + return $this->isOrm() ? new DummyTableInheritanceNotApiResourceChild() : new DummyTableInheritanceNotApiResourceChildDocument(); + } + /** * @return DummyAggregateOffer|DummyAggregateOfferDocument */ diff --git a/features/main/table_inheritance.feature b/features/main/table_inheritance.feature index fbcf9e58a51..72b64bed1d0 100644 --- a/features/main/table_inheritance.feature +++ b/features/main/table_inheritance.feature @@ -20,15 +20,18 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceChild$" + "pattern": "^DummyTableInheritanceChild$", + "required": "true" }, "@context": { "type": "string", - "pattern": "^/contexts/DummyTableInheritanceChild$" + "pattern": "^/contexts/DummyTableInheritanceChild$", + "required": "true" }, "@id": { "type": "string", - "pattern": "^/dummy_table_inheritance_children/1$" + "pattern": "^/dummy_table_inheritance_children/1$", + "required": "true" }, "name": { "type": "string", @@ -61,7 +64,8 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceChild$" + "pattern": "^DummyTableInheritanceChild$", + "required": "true" }, "name": { "type": "string", @@ -81,6 +85,40 @@ Feature: Table inheritance """ @createSchema + Scenario: Some children not api resources are created in the app + When some dummy table inheritance data but not api resource child are created + And I send a "GET" request to "/dummy_table_inheritances" + 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": { + "hydra:member": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "pattern": "^DummyTableInheritance(Child)?$", + "required": "true" + }, + "name": { + "type": "string", + "required": "true" + } + } + }, + "minItems": 1 + } + }, + "required": ["hydra:member"] + } + """ + Scenario: Create a table inherited resource When I add "Content-Type" header equal to "application/ld+json" And I send a "POST" request to "/dummy_table_inheritance_children" with body: @@ -97,15 +135,18 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceChild$" + "pattern": "^DummyTableInheritanceChild$", + "required": "true" }, "@context": { "type": "string", - "pattern": "^/contexts/DummyTableInheritanceChild$" + "pattern": "^/contexts/DummyTableInheritanceChild$", + "required": "true" }, "@id": { "type": "string", - "pattern": "^/dummy_table_inheritance_children/1$" + "pattern": "^/dummy_table_inheritance_children/1$", + "required": "true" }, "name": { "type": "string", @@ -136,15 +177,18 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceDifferentChild$" + "pattern": "^DummyTableInheritanceDifferentChild$", + "required": "true" }, "@context": { "type": "string", - "pattern": "^/contexts/DummyTableInheritanceDifferentChild$" + "pattern": "^/contexts/DummyTableInheritanceDifferentChild$", + "required": "true" }, "@id": { "type": "string", - "pattern": "^/dummy_table_inheritance_different_children/2$" + "pattern": "^/dummy_table_inheritance_different_children/2$", + "required": "true" }, "name": { "type": "string", @@ -181,15 +225,18 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceRelated$" + "pattern": "^DummyTableInheritanceRelated$", + "required": "true" }, "@context": { "type": "string", - "pattern": "^/contexts/DummyTableInheritanceRelated$" + "pattern": "^/contexts/DummyTableInheritanceRelated$", + "required": "true" }, "@id": { "type": "string", - "pattern": "^/dummy_table_inheritance_relateds/1$" + "pattern": "^/dummy_table_inheritance_relateds/1$", + "required": "true" }, "children": { "items": { @@ -199,7 +246,8 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceChild$" + "pattern": "^DummyTableInheritanceChild$", + "required": "true" }, "name": { "type": "string", @@ -215,7 +263,8 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceDifferentChild$" + "pattern": "^DummyTableInheritanceDifferentChild$", + "required": "true" }, "name": { "type": "string", @@ -255,7 +304,8 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceChild$" + "pattern": "^DummyTableInheritanceChild$", + "required": "true" }, "name": { "type": "string", @@ -271,7 +321,8 @@ Feature: Table inheritance "properties": { "@type": { "type": "string", - "pattern": "^DummyTableInheritanceDifferentChild$" + "pattern": "^DummyTableInheritanceDifferentChild$", + "required": "true" }, "name": { "type": "string", diff --git a/src/Api/IdentifiersExtractor.php b/src/Api/IdentifiersExtractor.php index 31f493f7520..981fdb9defd 100644 --- a/src/Api/IdentifiersExtractor.php +++ b/src/Api/IdentifiersExtractor.php @@ -67,8 +67,10 @@ public function getIdentifiersFromResourceClass(string $resourceClass): array public function getIdentifiersFromItem($item): array { $identifiers = []; - $type = $this->getObjectClass($item); - $resourceClass = $this->resourceClassResolver->isResourceClass($type) ? $this->resourceClassResolver->getResourceClass($item) : $type; + $resourceClass = $this->getObjectClass($item); + if (null !== $this->resourceClassResolver) { // BC Layer + $resourceClass = $this->resourceClassResolver->isResourceClass($resourceClass) ? $this->resourceClassResolver->getResourceClass($item) : $resourceClass; + } foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $propertyName) { $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $propertyName); diff --git a/src/Api/ResourceClassResolver.php b/src/Api/ResourceClassResolver.php index 98e88fb1e4e..c932e8c53fe 100644 --- a/src/Api/ResourceClassResolver.php +++ b/src/Api/ResourceClassResolver.php @@ -28,7 +28,6 @@ final class ResourceClassResolver implements ResourceClassResolverInterface use ClassInfoTrait; private $resourceNameCollectionFactory; - private $localIsResourceClassCache = []; public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory) { @@ -56,20 +55,27 @@ public function getResourceClass($value, string $resourceClass = null, bool $str $resolvedResourceClass = $currentResourceClass; } } + if (null !== $resolvedResourceClass) { $resourceClass = $resolvedResourceClass; } + $typeIsStrictResourceClass = $this->isStrictResourceClass($type); + if ($strict && $typeIsStrictResourceClass) { + return $type; + } + + $typeIsResourceClass = $this->isResourceClass($type); if ( null === $type - || ((!$strict || $resourceClass === $type) && $isResourceClass = $this->isResourceClass($type)) - || null !== $resolvedResourceClass && interface_exists($resourceClass) + || (((!$strict || $resourceClass === $type)) && $typeIsResourceClass) + || null !== $resolvedResourceClass && (interface_exists($resourceClass) || !$typeIsStrictResourceClass) ) { return $resourceClass; } if ( - ($isResourceClass ?? $this->isResourceClass($type)) + $typeIsResourceClass || (is_subclass_of($type, $resourceClass) && $this->isResourceClass($resourceClass)) ) { return $type; @@ -83,16 +89,28 @@ public function getResourceClass($value, string $resourceClass = null, bool $str */ public function isResourceClass(string $type): bool { - if (isset($this->localIsResourceClassCache[$type])) { - return $this->localIsResourceClassCache[$type]; + foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) { + if ($type === $resourceClass || is_subclass_of($type, $resourceClass)) { + return true; + } } + return false; + } + + /** + * Same of isResourceClass but more strict: it ignores inheritance. + * + * @param string $type FQCN of an object + */ + private function isStrictResourceClass(string $type): bool + { foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) { - if ($type === $resourceClass || is_subclass_of($type, $resourceClass)) { - return $this->localIsResourceClassCache[$type] = true; + if ($type === $resourceClass) { + return true; } } - return $this->localIsResourceClassCache[$type] = false; + return false; } } diff --git a/src/Api/ResourceClassResolverInterface.php b/src/Api/ResourceClassResolverInterface.php index 1bf900bfec8..1555b4f0086 100644 --- a/src/Api/ResourceClassResolverInterface.php +++ b/src/Api/ResourceClassResolverInterface.php @@ -25,7 +25,7 @@ interface ResourceClassResolverInterface /** * Guesses the associated resource. * - * @param object $value Object you're playing with + * @param mixed $value Object you're playing with * @param string $resourceClass Resource class it is supposed to be (could be parent class for instance) * @param bool $strict value must be type of resource class given or it will return type * diff --git a/src/Bridge/Doctrine/EventListener/PublishMercureUpdatesListener.php b/src/Bridge/Doctrine/EventListener/PublishMercureUpdatesListener.php index 805e2585baa..87f3952d683 100644 --- a/src/Bridge/Doctrine/EventListener/PublishMercureUpdatesListener.php +++ b/src/Bridge/Doctrine/EventListener/PublishMercureUpdatesListener.php @@ -121,7 +121,10 @@ private function reset(): void private function storeEntityToPublish($entity, string $property): void { $resourceClass = $this->getObjectClass($entity); - if (!$this->resourceClassResolver->isResourceClass($resourceClass)) { + + if ($this->resourceClassResolver->isResourceClass($resourceClass)) { + $resourceClass = $this->resourceClassResolver->getResourceClass($entity); + } else { return; } diff --git a/tests/Api/IdentifiersExtractorTest.php b/tests/Api/IdentifiersExtractorTest.php index 878f881f196..de5462afcc5 100644 --- a/tests/Api/IdentifiersExtractorTest.php +++ b/tests/Api/IdentifiersExtractorTest.php @@ -179,6 +179,7 @@ private function getResourceClassResolver() $resourceClassResolver->isResourceClass(Argument::type('string'))->will(function ($args) { return !(Uuid::class === $args[0]); }); + $resourceClassResolver->getResourceClass(Argument::any())->will(function ($args) {return \get_class($args[0]); }); return $resourceClassResolver->reveal(); } diff --git a/tests/Api/ResourceClassResolverTest.php b/tests/Api/ResourceClassResolverTest.php index 025a43afa77..6a3350c348a 100644 --- a/tests/Api/ResourceClassResolverTest.php +++ b/tests/Api/ResourceClassResolverTest.php @@ -24,6 +24,7 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyCar; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritance; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritanceChild; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyTableInheritanceNotApiResourceChild; use PHPUnit\Framework\TestCase; /** @@ -175,13 +176,12 @@ public function testGetResourceClassWithChildResource() public function testGetResourceClassWithInterfaceResource() { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("The given object's resource is the interface \"ApiPlatform\Core\Tests\Fixtures\DummyResourceInterface\", finding a class is not possible."); $dummy = new DummyResourceImplementation(); $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([DummyResourceInterface::class]))->shouldBeCalled(); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClassResolver->getResourceClass($dummy, DummyResourceInterface::class, true); + $this->assertEquals(DummyResourceInterface::class, $resourceClassResolver->getResourceClass($dummy, DummyResourceInterface::class, true)); } public function testGetResourceClassWithoutSecondParameterIsAccurate() @@ -212,4 +212,26 @@ public function testInterfaceCanBeResourceClass() $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); $this->assertTrue($resourceClassResolver->isResourceClass(DummyResourceImplementation::class)); } + + public function testItResolveParentResourceClassOfChildrenOfResourceClasses() + { + $dummy = new DummyTableInheritanceNotApiResourceChild(); + $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([DummyTableInheritance::class]))->shouldBeCalled(); + + $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); +// $this->assertTrue($resourceClassResolver->isResourceClass(DummyTableInheritanceNotApiResourceChild::class)); +// $this->assertEquals(DummyTableInheritance::class, $resourceClassResolver->getResourceClass($dummy)); + $this->assertEquals(DummyTableInheritance::class, $resourceClassResolver->getResourceClass($dummy, DummyTableInheritance::class, true)); + } + + public function testItResolveChildWhenParentAndChildrenAreResourcesAndIsStrict() + { + $dummy = new DummyTableInheritanceChild(); + $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([DummyTableInheritance::class, DummyTableInheritanceChild::class]))->shouldBeCalled(); + + $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); + $this->assertEquals(DummyTableInheritanceChild::class, $resourceClassResolver->getResourceClass($dummy, DummyTableInheritance::class, true)); + } } diff --git a/tests/Bridge/Doctrine/EventListener/PublishMercureUpdatesListenerTest.php b/tests/Bridge/Doctrine/EventListener/PublishMercureUpdatesListenerTest.php index 632338a845e..82d84d8735f 100644 --- a/tests/Bridge/Doctrine/EventListener/PublishMercureUpdatesListenerTest.php +++ b/tests/Bridge/Doctrine/EventListener/PublishMercureUpdatesListenerTest.php @@ -28,6 +28,7 @@ use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\UnitOfWork; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Symfony\Component\Mercure\Update; use Symfony\Component\Serializer\SerializerInterface; @@ -56,6 +57,7 @@ public function testPublishUpdate() $resourceClassResolverProphecy->isResourceClass(NotAResource::class)->willReturn(false); $resourceClassResolverProphecy->isResourceClass(DummyCar::class)->willReturn(true); $resourceClassResolverProphecy->isResourceClass(DummyFriend::class)->willReturn(true); + $resourceClassResolverProphecy->getResourceClass(Argument::type('object'))->will(function ($args) { return \get_class($args[0]); }); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $iriConverterProphecy->getIriFromItem($toInsert, UrlGeneratorInterface::ABS_URL)->willReturn('http://example.com/dummies/1')->shouldBeCalled(); @@ -136,6 +138,7 @@ public function testInvalidMercureAttribute() $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true); + $resourceClassResolverProphecy->getResourceClass(Argument::type('object'))->will(function ($args) { return \get_class($args[0]); }); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); diff --git a/tests/Fixtures/TestBundle/Document/DummyTableInheritanceNotApiResourceChild.php b/tests/Fixtures/TestBundle/Document/DummyTableInheritanceNotApiResourceChild.php new file mode 100644 index 00000000000..046381598f7 --- /dev/null +++ b/tests/Fixtures/TestBundle/Document/DummyTableInheritanceNotApiResourceChild.php @@ -0,0 +1,47 @@ + + * + * 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\Fixtures\TestBundle\Document; + +use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; + +/** + * @ODM\Document + */ +class DummyTableInheritanceNotApiResourceChild extends DummyTableInheritance +{ + /** + * Considering this class is not an ApiResource, what should be render is only parent fields. + * + * @var bool The dummy swagg + * + * @ODM\Field(type="boolean") + */ + private $swaggerThanParent; + + public function __construct() + { + // Definitely always swagger than parents + $this->swaggerThanParent = true; + } + + public function isSwaggerThanParent(): bool + { + return $this->swaggerThanParent; + } + + public function setSwaggerThanParent(bool $swaggerThanParent) + { + $this->swaggerThanParent = $swaggerThanParent; + } +} diff --git a/tests/Fixtures/TestBundle/Entity/DummyTableInheritance.php b/tests/Fixtures/TestBundle/Entity/DummyTableInheritance.php index 4a208281425..23b629d541d 100644 --- a/tests/Fixtures/TestBundle/Entity/DummyTableInheritance.php +++ b/tests/Fixtures/TestBundle/Entity/DummyTableInheritance.php @@ -21,7 +21,12 @@ * @ORM\Entity * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="discr", type="string") - * @ORM\DiscriminatorMap({"dummyTableInheritance"="DummyTableInheritance", "dummyTableInheritanceChild"="DummyTableInheritanceChild", "dummyTableInheritanceDifferentChild"="DummyTableInheritanceDifferentChild"}) + * @ORM\DiscriminatorMap({ + * "dummyTableInheritance"="DummyTableInheritance", + * "dummyTableInheritanceChild"="DummyTableInheritanceChild", + * "dummyTableInheritanceDifferentChild"="DummyTableInheritanceDifferentChild", + * "dummyTableInheritanceNotApiResourceChild"="DummyTableInheritanceNotApiResourceChild" + * }) * @ApiResource */ class DummyTableInheritance diff --git a/tests/Fixtures/TestBundle/Entity/DummyTableInheritanceNotApiResourceChild.php b/tests/Fixtures/TestBundle/Entity/DummyTableInheritanceNotApiResourceChild.php new file mode 100644 index 00000000000..0ae63213898 --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/DummyTableInheritanceNotApiResourceChild.php @@ -0,0 +1,48 @@ + + * + * 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\Fixtures\TestBundle\Entity; + +use ApiPlatform\Core\Annotation\ApiResource; +use Doctrine\ORM\Mapping as ORM; + +/** + * @ORM\Entity + */ +class DummyTableInheritanceNotApiResourceChild extends DummyTableInheritance +{ + /** + * Considering this class is not an ApiResource, what should be render is only parent fields. + * + * @var bool The dummy swagg + * + * @ORM\Column(type="boolean") + */ + private $swaggerThanParent; + + public function __construct() + { + // Definitely always swagger than parents + $this->swaggerThanParent = true; + } + + public function isSwaggerThanParent(): bool + { + return $this->swaggerThanParent; + } + + public function setSwaggerThanParent(bool $swaggerThanParent) + { + $this->swaggerThanParent = $swaggerThanParent; + } +} diff --git a/tests/JsonLd/Serializer/ItemNormalizerTest.php b/tests/JsonLd/Serializer/ItemNormalizerTest.php index fb5b1bf984f..7ebf2de6644 100644 --- a/tests/JsonLd/Serializer/ItemNormalizerTest.php +++ b/tests/JsonLd/Serializer/ItemNormalizerTest.php @@ -13,8 +13,8 @@ namespace ApiPlatform\Core\Tests\JsonLd\Serializer; -use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\Api\ResourceClassResolverInterface; +use ApiPlatform\Core\Api\ResourceIriConverterInterface; use ApiPlatform\Core\JsonLd\ContextBuilderInterface; use ApiPlatform\Core\JsonLd\Serializer\ItemNormalizer; use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; @@ -42,7 +42,7 @@ public function testDontSupportDenormalization() $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $iriConverterProphecy = $this->prophesize(ResourceIriConverterInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); $contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class); $resourceClassResolverProphecy->getResourceClass(['dummy'], 'Dummy')->willReturn(Dummy::class); @@ -66,7 +66,7 @@ public function testSupportNormalization() $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $iriConverterProphecy = $this->prophesize(ResourceIriConverterInterface::class); $contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); @@ -103,8 +103,8 @@ public function testNormalize() $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata)->shouldBeCalled(); - $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1988')->shouldBeCalled(); + $iriConverterProphecy = $this->prophesize(ResourceIriConverterInterface::class); + $iriConverterProphecy->getIriFromItemWithResource($dummy, Argument::type('string'))->willReturn('/dummies/1988')->shouldBeCalled(); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled();