From b9e80ca0d232dacb6b30b4f7ac25b70078f72fe0 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Mon, 9 Apr 2018 15:42:36 +0200 Subject: [PATCH 1/3] feature: add a new `getIriFromPlainIdentifier` method and remove ItemDataProvider from AbstractItemNormalizer --- CHANGELOG.md | 6 +++ ...PlainIdentifierAwareConverterInterface.php | 39 ++++++++++++++++ src/Bridge/Symfony/Routing/IriConverter.php | 26 ++++++++++- src/Serializer/AbstractItemNormalizer.php | 12 ++++- .../Serializer/AbstractItemNormalizerTest.php | 44 +++++++++++++++++-- 5 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 src/Api/IriPlainIdentifierAwareConverterInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f6b88158cb0..77127ba64b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2.3.0 + +* Introduce a new interface `IriPlainIdentifierAwareConverterInterface` +* Add `getIriFromPlainIdentifier` in `IriPlainIdentifierAwareConverterInterface` to be able to retrieve an iri from an ID +* [deprecated] Passing an implementation of `ItemDataProviderInterface` in an implementation of `AbstractItemNormalizer` is deprecated and will be not possible in 3.0 + ## 2.2.5 * Fix a various issues preventing the metadata cache to work properly (performance fix) diff --git a/src/Api/IriPlainIdentifierAwareConverterInterface.php b/src/Api/IriPlainIdentifierAwareConverterInterface.php new file mode 100644 index 00000000000..7d0a8fb7435 --- /dev/null +++ b/src/Api/IriPlainIdentifierAwareConverterInterface.php @@ -0,0 +1,39 @@ + + * + * 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\Api; + +use ApiPlatform\Core\Exception\InvalidArgumentException; +use ApiPlatform\Core\Exception\ItemNotFoundException; +use ApiPlatform\Core\Exception\RuntimeException; + +/** + * Converts a plain identifier to an IRI + * + * @author Hamza Amrouche + */ +interface IriPlainIdentifierAwareConverterInterface extends IriConverterInterface +{ + /** + * Gets the IRI associated with the given plain identifier. + * + * @param string|int|array $id + * @param string $resourceClass + * @param int $referenceType + * + * @throws InvalidArgumentException + * + * @return string + */ + public function getIriFromPlainIdentifier($id, string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string; +} diff --git a/src/Bridge/Symfony/Routing/IriConverter.php b/src/Bridge/Symfony/Routing/IriConverter.php index 3462e74e346..5e020af6ffc 100644 --- a/src/Bridge/Symfony/Routing/IriConverter.php +++ b/src/Bridge/Symfony/Routing/IriConverter.php @@ -16,7 +16,9 @@ use ApiPlatform\Core\Api\IdentifiersExtractor; use ApiPlatform\Core\Api\IdentifiersExtractorInterface; use ApiPlatform\Core\Api\IriConverterInterface; +use ApiPlatform\Core\Api\IriPlainIdentifierAwareConverterInterface; use ApiPlatform\Core\Api\OperationType; +use ApiPlatform\Core\Api\PlainIdentifierConverterInterface; use ApiPlatform\Core\Api\UrlGeneratorInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\OperationDataProviderTrait; @@ -40,7 +42,7 @@ * * @author Kévin Dunglas */ -final class IriConverter implements IriConverterInterface +final class IriConverter implements IriPlainIdentifierAwareConverterInterface { use ClassInfoTrait; use OperationDataProviderTrait; @@ -106,6 +108,28 @@ public function getItemFromIri(string $iri, array $context = []) throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri)); } + /** + * {@inheritdoc} + */ + public function getIriFromPlainIdentifier($id, string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string + { + $routeName = $this->routeNameResolver->getRouteName($resourceClass, OperationType::ITEM); + + try { + return $this->router->generate($routeName, ['id' => \is_array($id) ? implode(';', $id) : $id], $referenceType); + } catch (RuntimeException $e) { + throw new InvalidArgumentException(sprintf( + 'Unable to generate an IRI for the item of type "%s"', + $resourceClass + ), $e->getCode(), $e); + } catch (RoutingExceptionInterface $e) { + throw new InvalidArgumentException(sprintf( + 'Unable to generate an IRI for the item of type "%s"', + $resourceClass + ), $e->getCode(), $e); + } + } + /** * {@inheritdoc} */ diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index f40e1474a5c..78b0d3137f9 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -14,7 +14,9 @@ namespace ApiPlatform\Core\Serializer; use ApiPlatform\Core\Api\IriConverterInterface; +use ApiPlatform\Core\Api\IriPlainIdentifierAwareConverterInterface; use ApiPlatform\Core\Api\OperationType; +use ApiPlatform\Core\Api\PlainIdentifierConverterInterface; use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\Exception\InvalidArgumentException; @@ -43,6 +45,9 @@ abstract class AbstractItemNormalizer extends AbstractObjectNormalizer protected $propertyNameCollectionFactory; protected $propertyMetadataFactory; + /** + * @var IriPlainIdentifierAwareConverterInterface|IriConverterInterface $iriConverter + */ protected $iriConverter; protected $resourceClassResolver; protected $propertyAccessor; @@ -59,6 +64,9 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName $this->iriConverter = $iriConverter; $this->resourceClassResolver = $resourceClassResolver; $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); + if (null !== $itemDataProvider) { + @trigger_error(sprintf('Passing a %s is deprecated since 2.3 and will not be possible in 3.0.', ItemDataProviderInterface::class)); + } $this->itemDataProvider = $itemDataProvider; $this->allowPlainIdentifiers = $allowPlainIdentifiers; @@ -309,9 +317,9 @@ protected function denormalizeRelation(string $attributeName, PropertyMetadata $ if (!\is_array($value)) { // repeat the code so that IRIs keep working with the json format - if (true === $this->allowPlainIdentifiers && $this->itemDataProvider) { + if (true === $this->allowPlainIdentifiers && $this->iriConverter instanceof IriPlainIdentifierAwareConverterInterface) { try { - return $this->itemDataProvider->getItem($className, $value, null, $context + ['fetch_data' => true]); + return $this->iriConverter->getItemFromIri($this->iriConverter->getIriFromPlainIdentifier($value, $className), $context + ['fetch_data' => true]); } catch (ItemNotFoundException $e) { throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } catch (InvalidArgumentException $e) { diff --git a/tests/Serializer/AbstractItemNormalizerTest.php b/tests/Serializer/AbstractItemNormalizerTest.php index 9f764c55e39..fd37ecdfbc8 100644 --- a/tests/Serializer/AbstractItemNormalizerTest.php +++ b/tests/Serializer/AbstractItemNormalizerTest.php @@ -14,6 +14,8 @@ namespace ApiPlatform\Core\Tests\Serializer; use ApiPlatform\Core\Api\IriConverterInterface; +use ApiPlatform\Core\Api\IriPlainIdentifierAwareConverterInterface; +use ApiPlatform\Core\Api\PlainIdentifierConverterInterface; use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; @@ -663,7 +665,13 @@ public function testDenormalizeRelationWithPlainId() ) )->shouldBeCalled(); - $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $getItemFromIriSecondArgCallback = function ($arg) { + return is_array($arg) && isset($arg['fetch_data']) && true === $arg['fetch_data']; + }; + + $iriConverterProphecy = $this->prophesize(IriPlainIdentifierAwareConverterInterface::class); + $iriConverterProphecy->getItemFromIri('/related_dummies/1', Argument::that($getItemFromIriSecondArgCallback))->shouldBeCalled(); + $iriConverterProphecy->getIriFromPlainIdentifier('1', RelatedDummy::class)->shouldBeCalled()->willReturn('/related_dummies/1'); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); @@ -673,7 +681,7 @@ public function testDenormalizeRelationWithPlainId() $serializerProphecy->willImplement(DenormalizerInterface::class); $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); - $itemDataProviderProphecy->getItem(RelatedDummy::class, 1, null, Argument::type('array'))->shouldBeCalled(); + $itemDataProviderProphecy->getItem(RelatedDummy::class, 1, null, Argument::type('array'))->shouldNotBeCalled(); $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ $propertyNameCollectionFactoryProphecy->reveal(), @@ -683,14 +691,42 @@ public function testDenormalizeRelationWithPlainId() $propertyAccessorProphecy->reveal(), null, null, - $itemDataProviderProphecy->reveal(), - true, + null, + true ]); $normalizer->setSerializer($serializerProphecy->reveal()); $normalizer->denormalize(['relatedDummy' => 1], Dummy::class, 'jsonld'); } + /** + * @group legacy + * @expectedDeprecation + */ + public function testTriggerDeprecation() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $serializerProphecy = $this->prophesize(SerializerInterface::class); + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + + $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ + $propertyNameCollectionFactoryProphecy->reveal(), + $propertyMetadataFactoryProphecy->reveal(), + $iriConverterProphecy->reveal(), + $resourceClassResolverProphecy->reveal(), + $propertyAccessorProphecy->reveal(), + null, + null, + $itemDataProviderProphecy->reveal(), + true + ]); + $normalizer->setSerializer($serializerProphecy->reveal()); + } + /** * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException * @expectedExceptionMessage Expected IRI or nested document for attribute "relatedDummy", "integer" given. From 6480222a1ca0fe9d0a0b20dcec3038e0d7b9faf6 Mon Sep 17 00:00:00 2001 From: Evgeniy Sokolov Date: Mon, 19 Feb 2018 22:34:09 +0100 Subject: [PATCH 2/3] throw NotFound exception when use plain identifiers --- CHANGELOG.md | 5 +- ... => IriToIdentifierConverterInterface.php} | 10 +- src/Bridge/Symfony/Routing/IriConverter.php | 8 +- src/Serializer/AbstractItemNormalizer.php | 26 +-- .../Symfony/Routing/IriConverterTest.php | 192 +++++++++++++++++- tests/Fixtures/TestBundle/Entity/Dummy.php | 2 + .../Serializer/AbstractItemNormalizerTest.php | 138 ++++++++++++- 7 files changed, 343 insertions(+), 38 deletions(-) rename src/Api/{IriPlainIdentifierAwareConverterInterface.php => IriToIdentifierConverterInterface.php} (63%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77127ba64b0..5058067f538 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,9 @@ ## 2.3.0 -* Introduce a new interface `IriPlainIdentifierAwareConverterInterface` -* Add `getIriFromPlainIdentifier` in `IriPlainIdentifierAwareConverterInterface` to be able to retrieve an iri from an ID +* Introduce a new interface `IriToIdentifierConverterInterface` +* Add `getIriFromPlainIdentifier` in `IriToIdentifierConverterInterface` to be able to retrieve an iri from an ID +* IriConverter now implements `IriToIdentifierConverterInterface` * [deprecated] Passing an implementation of `ItemDataProviderInterface` in an implementation of `AbstractItemNormalizer` is deprecated and will be not possible in 3.0 ## 2.2.5 diff --git a/src/Api/IriPlainIdentifierAwareConverterInterface.php b/src/Api/IriToIdentifierConverterInterface.php similarity index 63% rename from src/Api/IriPlainIdentifierAwareConverterInterface.php rename to src/Api/IriToIdentifierConverterInterface.php index 7d0a8fb7435..5289f113796 100644 --- a/src/Api/IriPlainIdentifierAwareConverterInterface.php +++ b/src/Api/IriToIdentifierConverterInterface.php @@ -14,20 +14,18 @@ namespace ApiPlatform\Core\Api; use ApiPlatform\Core\Exception\InvalidArgumentException; -use ApiPlatform\Core\Exception\ItemNotFoundException; -use ApiPlatform\Core\Exception\RuntimeException; /** - * Converts a plain identifier to an IRI + * Converts a plain identifier to an IRI. * * @author Hamza Amrouche */ -interface IriPlainIdentifierAwareConverterInterface extends IriConverterInterface +interface IriToIdentifierConverterInterface { /** * Gets the IRI associated with the given plain identifier. * - * @param string|int|array $id + * @param array $id * @param string $resourceClass * @param int $referenceType * @@ -35,5 +33,5 @@ interface IriPlainIdentifierAwareConverterInterface extends IriConverterInterfac * * @return string */ - public function getIriFromPlainIdentifier($id, string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string; + public function getIriFromPlainIdentifier(array $id, string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string; } diff --git a/src/Bridge/Symfony/Routing/IriConverter.php b/src/Bridge/Symfony/Routing/IriConverter.php index 5e020af6ffc..37ad56be1dd 100644 --- a/src/Bridge/Symfony/Routing/IriConverter.php +++ b/src/Bridge/Symfony/Routing/IriConverter.php @@ -16,9 +16,8 @@ use ApiPlatform\Core\Api\IdentifiersExtractor; use ApiPlatform\Core\Api\IdentifiersExtractorInterface; use ApiPlatform\Core\Api\IriConverterInterface; -use ApiPlatform\Core\Api\IriPlainIdentifierAwareConverterInterface; +use ApiPlatform\Core\Api\IriToIdentifierConverterInterface; use ApiPlatform\Core\Api\OperationType; -use ApiPlatform\Core\Api\PlainIdentifierConverterInterface; use ApiPlatform\Core\Api\UrlGeneratorInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\OperationDataProviderTrait; @@ -42,7 +41,7 @@ * * @author Kévin Dunglas */ -final class IriConverter implements IriPlainIdentifierAwareConverterInterface +final class IriConverter implements IriToIdentifierConverterInterface, IriConverterInterface { use ClassInfoTrait; use OperationDataProviderTrait; @@ -61,7 +60,7 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName $this->identifierDenormalizer = $identifierDenormalizer; if (null === $identifiersExtractor) { - @trigger_error(sprintf('Not injecting "%s" is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3', IdentifiersExtractorInterface::class), E_USER_DEPRECATED); + @trigger_error(sprintf('Not injecting "%s" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3.', IdentifiersExtractorInterface::class), E_USER_DEPRECATED); $this->identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, $propertyAccessor ?? PropertyAccess::createPropertyAccessor()); } } @@ -114,7 +113,6 @@ public function getItemFromIri(string $iri, array $context = []) public function getIriFromPlainIdentifier($id, string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string { $routeName = $this->routeNameResolver->getRouteName($resourceClass, OperationType::ITEM); - try { return $this->router->generate($routeName, ['id' => \is_array($id) ? implode(';', $id) : $id], $referenceType); } catch (RuntimeException $e) { diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index 78b0d3137f9..1c2004abaa2 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -14,9 +14,8 @@ namespace ApiPlatform\Core\Serializer; use ApiPlatform\Core\Api\IriConverterInterface; -use ApiPlatform\Core\Api\IriPlainIdentifierAwareConverterInterface; +use ApiPlatform\Core\Api\IriToIdentifierConverterInterface; use ApiPlatform\Core\Api\OperationType; -use ApiPlatform\Core\Api\PlainIdentifierConverterInterface; use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\Exception\InvalidArgumentException; @@ -46,7 +45,7 @@ abstract class AbstractItemNormalizer extends AbstractObjectNormalizer protected $propertyNameCollectionFactory; protected $propertyMetadataFactory; /** - * @var IriPlainIdentifierAwareConverterInterface|IriConverterInterface $iriConverter + * @var IriToIdentifierConverterInterface|IriConverterInterface */ protected $iriConverter; protected $resourceClassResolver; @@ -65,7 +64,7 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName $this->resourceClassResolver = $resourceClassResolver; $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); if (null !== $itemDataProvider) { - @trigger_error(sprintf('Passing a %s is deprecated since 2.3 and will not be possible in 3.0.', ItemDataProviderInterface::class)); + @trigger_error(sprintf('Passing a %s is deprecated since 2.3 and will not be possible in 3.0.', ItemDataProviderInterface::class), E_USER_DEPRECATED); } $this->itemDataProvider = $itemDataProvider; $this->allowPlainIdentifiers = $allowPlainIdentifiers; @@ -316,17 +315,20 @@ protected function denormalizeRelation(string $attributeName, PropertyMetadata $ } if (!\is_array($value)) { - // repeat the code so that IRIs keep working with the json format - if (true === $this->allowPlainIdentifiers && $this->iriConverter instanceof IriPlainIdentifierAwareConverterInterface) { - try { + try { + // repeat the code so that IRIs keep working with the json format + if (true === $this->allowPlainIdentifiers && ($this->iriConverter instanceof IriToIdentifierConverterInterface && $this->iriConverter instanceof IriConverterInterface)) { return $this->iriConverter->getItemFromIri($this->iriConverter->getIriFromPlainIdentifier($value, $className), $context + ['fetch_data' => true]); - } catch (ItemNotFoundException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } catch (InvalidArgumentException $e) { - // Give a chance to other normalizers (e.g.: DateTimeNormalizer) } - } + if (true === $this->allowPlainIdentifiers && $this->itemDataProvider) { + return $this->itemDataProvider->getItem($className, $value, null, $context + ['fetch_data' => true]); + } + } catch (ItemNotFoundException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } catch (InvalidArgumentException $e) { + // Give a chance to other normalizers (e.g.: DateTimeNormalizer) + } throw new InvalidArgumentException(sprintf( 'Expected IRI or nested document for attribute "%s", "%s" given.', $attributeName, \gettype($value) )); diff --git a/tests/Bridge/Symfony/Routing/IriConverterTest.php b/tests/Bridge/Symfony/Routing/IriConverterTest.php index 3065f3820ff..283616e0f95 100644 --- a/tests/Bridge/Symfony/Routing/IriConverterTest.php +++ b/tests/Bridge/Symfony/Routing/IriConverterTest.php @@ -14,6 +14,7 @@ namespace ApiPlatform\Core\Tests\Bridge\Symfony\Routing; use ApiPlatform\Core\Api\IdentifiersExtractor; +use ApiPlatform\Core\Api\IdentifiersExtractorInterface; use ApiPlatform\Core\Api\OperationType; use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\Api\UrlGeneratorInterface; @@ -22,6 +23,7 @@ use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface; use ApiPlatform\Core\Exception\InvalidIdentifierException; +use ApiPlatform\Core\Exception\RuntimeException; use ApiPlatform\Core\Identifier\Normalizer\ChainIdentifierDenormalizer; use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; @@ -84,6 +86,39 @@ public function testGetItemFromIriItemNotFoundException() $converter->getItemFromIri('/users/3'); } + /** + * @group legacy + * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3. + * @expectedDeprecation Not injecting ApiPlatform\Core\Api\ResourceClassResolverInterface in the CachedIdentifiersExtractor might introduce cache issues with object identifiers. + */ + public function testIdentifiersExtractorDeprecation() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + + $routeNameResolverProphecy = $this->prophesize(RouteNameResolverInterface::class); + + $routerProphecy = $this->prophesize(RouterInterface::class); + + $propertyNameCollectionFactory = $propertyNameCollectionFactoryProphecy->reveal(); + $propertyMetadataFactory = $propertyMetadataFactoryProphecy->reveal(); + $identifierDenormalizer = $this->prophesize(ChainIdentifierDenormalizer::class); + + $converter = new IriConverter( + $propertyNameCollectionFactory, + $propertyMetadataFactory, + $itemDataProviderProphecy->reveal(), + $routeNameResolverProphecy->reveal(), + $routerProphecy->reveal(), + null, + null, + $identifierDenormalizer->reveal() + ); + } + public function testGetItemFromIri() { $item = new \StdClass(); @@ -193,6 +228,37 @@ public function testGetItemIriFromResourceClass() $this->assertEquals($converter->getItemIriFromResourceClass(Dummy::class, ['id' => 1]), '/dummies/1'); } + public function testGetItemIriFromPlainIdentifier() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + + $routeNameResolverProphecy = $this->prophesize(RouteNameResolverInterface::class); + $routeNameResolverProphecy->getRouteName(Dummy::class, OperationType::ITEM)->willReturn('api_dummies_get_item'); + + $routerProphecy = $this->prophesize(RouterInterface::class); + $routerProphecy->generate('api_dummies_get_item', ['id' => 1], UrlGeneratorInterface::ABS_PATH)->willReturn('/dummies/1'); + + $propertyNameCollectionFactory = $propertyNameCollectionFactoryProphecy->reveal(); + $propertyMetadataFactory = $propertyMetadataFactoryProphecy->reveal(); + $identifierDenormalizer = $this->prophesize(ChainIdentifierDenormalizer::class); + + $converter = new IriConverter( + $propertyNameCollectionFactory, + $propertyMetadataFactory, + $itemDataProviderProphecy->reveal(), + $routeNameResolverProphecy->reveal(), + $routerProphecy->reveal(), + null, + new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, null, $this->getResourceClassResolver()), + $identifierDenormalizer->reveal() + ); + $this->assertEquals($converter->getIriFromPlainIdentifier(1, Dummy::class), '/dummies/1'); + } + /** * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException * @expectedExceptionMessage Unable to generate an IRI for "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy" @@ -293,25 +359,143 @@ public function testGetItemFromIriBadIdentifierException() /** * @group legacy - * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3 + * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3. * @expectedDeprecation Not injecting ApiPlatform\Core\Api\ResourceClassResolverInterface in the CachedIdentifiersExtractor might introduce cache issues with object identifiers. */ public function testLegacyConstructor() { $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + + $routeNameResolverProphecy = $this->prophesize(RouteNameResolverInterface::class); + $routeNameResolverProphecy->getRouteName(Dummy::class, OperationType::ITEM)->willReturn('dummies'); + $routerProphecy = $this->prophesize(RouterInterface::class); + $routerProphecy->generate('dummies', ['id' => 1], UrlGeneratorInterface::ABS_PATH)->willReturn('/dummies/1'); + + $propertyNameCollectionFactory = $propertyNameCollectionFactoryProphecy->reveal(); + $propertyMetadataFactory = $propertyMetadataFactoryProphecy->reveal(); + $identifierDenormalizer = $this->prophesize(ChainIdentifierDenormalizer::class); + + $converter = new IriConverter( + $propertyNameCollectionFactory, + $propertyMetadataFactory, + $itemDataProviderProphecy->reveal(), + $routeNameResolverProphecy->reveal(), + $routerProphecy->reveal(), + null + ); + $converter->getItemIriFromResourceClass(Dummy::class, ['id' => 1]); + } + + /** + * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException + * @expectedExceptionMessage Unable to generate an IRI for the item of type "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy" + */ + public function testNotAbleToGenerateAnIriWithGetIriFromPlainIdentifier() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + + $routeNameResolverProphecy = $this->prophesize(RouteNameResolverInterface::class); + $routeNameResolverProphecy->getRouteName(Dummy::class, OperationType::ITEM)->willReturn('dummies'); + + $routerProphecy = $this->prophesize(RouterInterface::class); + $routerProphecy->generate('dummies', ['id' => 1], UrlGeneratorInterface::ABS_PATH)->willThrow(new RouteNotFoundException()); + + $propertyNameCollectionFactory = $propertyNameCollectionFactoryProphecy->reveal(); + $propertyMetadataFactory = $propertyMetadataFactoryProphecy->reveal(); + $identifierDenormalizer = $this->prophesize(ChainIdentifierDenormalizer::class); + + $converter = new IriConverter( + $propertyNameCollectionFactory, + $propertyMetadataFactory, + $itemDataProviderProphecy->reveal(), + $routeNameResolverProphecy->reveal(), + $routerProphecy->reveal(), + null, + new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, null, $this->getResourceClassResolver()), + $identifierDenormalizer->reveal() + ); + $converter->getIriFromPlainIdentifier(1, Dummy::class); + } + + /** + * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException + * @expectedExceptionMessage Unable to generate an IRI for the item of type "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy" + */ + public function testNotAbleToGenerateGetIriFromItem() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + $routeNameResolverProphecy = $this->prophesize(RouteNameResolverInterface::class); + $routeNameResolverProphecy->getRouteName(Dummy::class, OperationType::ITEM)->willReturn('dummies'); + + $routerProphecy = $this->prophesize(RouterInterface::class); + $routerProphecy->generate('dummies', ['id' => 'id'], UrlGeneratorInterface::ABS_PATH)->willThrow(new RuntimeException()); + + $propertyNameCollectionFactory = $propertyNameCollectionFactoryProphecy->reveal(); + $propertyMetadataFactory = $propertyMetadataFactoryProphecy->reveal(); + $identifierDenormalizer = $this->prophesize(ChainIdentifierDenormalizer::class); + + $dummy = (new Dummy())->setId(1); + $identifierExtractorProphecy = $this->prophesize(IdentifiersExtractorInterface::class); + $identifierExtractorProphecy->getIdentifiersFromItem($dummy)->willReturn(['id'])->shouldBeCalled(); + $converter = new IriConverter( + $propertyNameCollectionFactory, + $propertyMetadataFactory, + $itemDataProviderProphecy->reveal(), + $routeNameResolverProphecy->reveal(), + $routerProphecy->reveal(), + null, + $identifierExtractorProphecy->reveal(), + $identifierDenormalizer->reveal() + ); + $converter->getIriFromItem($dummy); + } + + /** + * @group legacy + * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3. + * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException + * @expectedExceptionMessage Unable to generate an IRI for the item of type "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy" + */ + public function testNotAbleToGenerateAnIriWithGetItemIriFromPlainIdentifierRouterException() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); - new IriConverter( - $propertyNameCollectionFactoryProphecy->reveal(), - $propertyMetadataFactoryProphecy->reveal(), + $routeNameResolverProphecy = $this->prophesize(RouteNameResolverInterface::class); + $routeNameResolverProphecy->getRouteName(Dummy::class, OperationType::ITEM)->willReturn('dummies'); + + $routerProphecy = $this->prophesize(RouterInterface::class); + $routerProphecy->generate('dummies', ['id' => 1], UrlGeneratorInterface::ABS_PATH)->willThrow(new RuntimeException()); + + $propertyNameCollectionFactory = $propertyNameCollectionFactoryProphecy->reveal(); + $propertyMetadataFactory = $propertyMetadataFactoryProphecy->reveal(); + + $converter = new IriConverter( + $propertyNameCollectionFactory, + $propertyMetadataFactory, $itemDataProviderProphecy->reveal(), $routeNameResolverProphecy->reveal(), $routerProphecy->reveal(), null ); + $converter->getIriFromPlainIdentifier(1, Dummy::class); } private function getResourceClassResolver() diff --git a/tests/Fixtures/TestBundle/Entity/Dummy.php b/tests/Fixtures/TestBundle/Entity/Dummy.php index 5265c411d1a..2518260f58d 100644 --- a/tests/Fixtures/TestBundle/Entity/Dummy.php +++ b/tests/Fixtures/TestBundle/Entity/Dummy.php @@ -171,6 +171,8 @@ public function getId() public function setId($id) { $this->id = $id; + + return $this; } public function setName($name) diff --git a/tests/Serializer/AbstractItemNormalizerTest.php b/tests/Serializer/AbstractItemNormalizerTest.php index fd37ecdfbc8..453ef449501 100644 --- a/tests/Serializer/AbstractItemNormalizerTest.php +++ b/tests/Serializer/AbstractItemNormalizerTest.php @@ -14,10 +14,11 @@ namespace ApiPlatform\Core\Tests\Serializer; use ApiPlatform\Core\Api\IriConverterInterface; -use ApiPlatform\Core\Api\IriPlainIdentifierAwareConverterInterface; -use ApiPlatform\Core\Api\PlainIdentifierConverterInterface; +use ApiPlatform\Core\Api\IriToIdentifierConverterInterface; use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; +use ApiPlatform\Core\Exception\InvalidArgumentException; +use ApiPlatform\Core\Exception\ItemNotFoundException; use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; use ApiPlatform\Core\Metadata\Property\PropertyMetadata; @@ -286,6 +287,73 @@ public function testDenormalize() ], Dummy::class); } + /** + * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException + * @expectedExceptionMessage NotFound exception + */ + public function testDenormalizeNotFound() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn( + new PropertyNameCollection(['name', 'relatedDummy', 'relatedDummies']) + )->shouldBeCalled(); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn( + new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', false, true) + )->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn( + new PropertyMetadata( + new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class), + '', + false, + true, + false, + false + ) + )->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummies', [])->willReturn( + new PropertyMetadata( + new Type(Type::BUILTIN_TYPE_OBJECT, + false, + ArrayCollection::class, + true, + new Type(Type::BUILTIN_TYPE_INT), + new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class) + ), + '', + false, + true, + false, + false + ) + )->shouldBeCalled(); + + $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $iriConverterProphecy->getItemFromIri('/dummies/1', Argument::type('array'))->willThrow(new ItemNotFoundException('NotFound exception'))->shouldBeCalled(); + + $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + + $serializerProphecy = $this->prophesize(SerializerInterface::class); + $serializerProphecy->willImplement(NormalizerInterface::class); + + $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ + $propertyNameCollectionFactoryProphecy->reveal(), + $propertyMetadataFactoryProphecy->reveal(), + $iriConverterProphecy->reveal(), + $resourceClassResolverProphecy->reveal(), + $propertyAccessorProphecy->reveal(), + ]); + $normalizer->setSerializer($serializerProphecy->reveal()); + + $normalizer->denormalize([ + 'name' => 'foo', + 'relatedDummy' => '/dummies/1', + ], Dummy::class); + } + public function testDenormalizeWritableLinks() { $relatedDummy1 = new RelatedDummy(); @@ -669,7 +737,7 @@ public function testDenormalizeRelationWithPlainId() return is_array($arg) && isset($arg['fetch_data']) && true === $arg['fetch_data']; }; - $iriConverterProphecy = $this->prophesize(IriPlainIdentifierAwareConverterInterface::class); + $iriConverterProphecy = $this->prophesize(IriToIdentifierConverterInterface::class)->willImplement(IriConverterInterface::class); $iriConverterProphecy->getItemFromIri('/related_dummies/1', Argument::that($getItemFromIriSecondArgCallback))->shouldBeCalled(); $iriConverterProphecy->getIriFromPlainIdentifier('1', RelatedDummy::class)->shouldBeCalled()->willReturn('/related_dummies/1'); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); @@ -680,8 +748,60 @@ public function testDenormalizeRelationWithPlainId() $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(DenormalizerInterface::class); - $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); - $itemDataProviderProphecy->getItem(RelatedDummy::class, 1, null, Argument::type('array'))->shouldNotBeCalled(); + $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ + $propertyNameCollectionFactoryProphecy->reveal(), + $propertyMetadataFactoryProphecy->reveal(), + $iriConverterProphecy->reveal(), + $resourceClassResolverProphecy->reveal(), + $propertyAccessorProphecy->reveal(), + null, + null, + null, + true, + ]); + $normalizer->setSerializer($serializerProphecy->reveal()); + + $normalizer->denormalize(['relatedDummy' => 1], Dummy::class, 'jsonld'); + } + + /** + * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException + * @expectedExceptionMessage Item with id "1" not found for class "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy". + */ + public function testDenormalizeNotFoundRelationWithPlainId() + { + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn( + new PropertyNameCollection(['relatedDummy']) + )->shouldBeCalled(); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn( + new PropertyMetadata( + new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class), + '', + false, + true, + false, + false + ) + )->shouldBeCalled(); + + $iriConverterProphecy = $this->prophesize(IriToIdentifierConverterInterface::class)->willImplement(IriConverterInterface::class); + + $getItemFromIriSecondArgCallback = function ($arg) { + return is_array($arg) && isset($arg['fetch_data']) && true === $arg['fetch_data']; + }; + + $iriConverterProphecy->getItemFromIri('/related_dummies/1', Argument::that($getItemFromIriSecondArgCallback))->shouldBeCalled()->willThrow(new ItemNotFoundException('Item with id "1" not found for class "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy".')); + $iriConverterProphecy->getIriFromPlainIdentifier('1', RelatedDummy::class)->shouldBeCalled()->willReturn('/related_dummies/1'); + $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true)->shouldBeCalled(); + + $serializerProphecy = $this->prophesize(SerializerInterface::class); + $serializerProphecy->willImplement(DenormalizerInterface::class); $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ $propertyNameCollectionFactoryProphecy->reveal(), @@ -692,7 +812,7 @@ public function testDenormalizeRelationWithPlainId() null, null, null, - true + true, ]); $normalizer->setSerializer($serializerProphecy->reveal()); @@ -701,7 +821,7 @@ public function testDenormalizeRelationWithPlainId() /** * @group legacy - * @expectedDeprecation + * @expectedDeprecation Passing a ApiPlatform\Core\DataProvider\ItemDataProviderInterface is deprecated since 2.3 and will not be possible in 3.0. */ public function testTriggerDeprecation() { @@ -722,7 +842,7 @@ public function testTriggerDeprecation() null, null, $itemDataProviderProphecy->reveal(), - true + true, ]); $normalizer->setSerializer($serializerProphecy->reveal()); } @@ -770,7 +890,7 @@ public function testDoNotDenormalizeRelationWithPlainIdWhenPlainIdentifiersAreNo $propertyAccessorProphecy->reveal(), null, null, - $itemDataProviderProphecy->reveal(), + null, false, ]); $normalizer->setSerializer($serializerProphecy->reveal()); From 0b2c7933736648fcc1db916aecc221d2c6253304 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Wed, 9 May 2018 14:57:19 +0200 Subject: [PATCH 3/3] feature: allow an implementation of IriToIdentifierConverterInterface different than the IriConverterInterface --- src/Bridge/Symfony/Routing/IriConverter.php | 6 +++--- src/Serializer/AbstractItemNormalizer.php | 13 ++++++------- .../Bridge/Symfony/Routing/IriConverterTest.php | 16 ++++++++++------ tests/Serializer/AbstractItemNormalizerTest.php | 12 ++++++++---- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/Bridge/Symfony/Routing/IriConverter.php b/src/Bridge/Symfony/Routing/IriConverter.php index 37ad56be1dd..2b439f52853 100644 --- a/src/Bridge/Symfony/Routing/IriConverter.php +++ b/src/Bridge/Symfony/Routing/IriConverter.php @@ -60,7 +60,7 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName $this->identifierDenormalizer = $identifierDenormalizer; if (null === $identifiersExtractor) { - @trigger_error(sprintf('Not injecting "%s" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3.', IdentifiersExtractorInterface::class), E_USER_DEPRECATED); + @trigger_error(sprintf('Not injecting "%s" is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3.', IdentifiersExtractorInterface::class), E_USER_DEPRECATED); $this->identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, $propertyAccessor ?? PropertyAccess::createPropertyAccessor()); } } @@ -110,11 +110,11 @@ public function getItemFromIri(string $iri, array $context = []) /** * {@inheritdoc} */ - public function getIriFromPlainIdentifier($id, string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string + public function getIriFromPlainIdentifier(array $id, string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string { $routeName = $this->routeNameResolver->getRouteName($resourceClass, OperationType::ITEM); try { - return $this->router->generate($routeName, ['id' => \is_array($id) ? implode(';', $id) : $id], $referenceType); + return $this->router->generate($routeName, ['id' => implode(';', $id)], $referenceType); } catch (RuntimeException $e) { throw new InvalidArgumentException(sprintf( 'Unable to generate an IRI for the item of type "%s"', diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index 1c2004abaa2..4dde27827e8 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -44,17 +44,15 @@ abstract class AbstractItemNormalizer extends AbstractObjectNormalizer protected $propertyNameCollectionFactory; protected $propertyMetadataFactory; - /** - * @var IriToIdentifierConverterInterface|IriConverterInterface - */ protected $iriConverter; protected $resourceClassResolver; protected $propertyAccessor; protected $localCache = []; protected $itemDataProvider; protected $allowPlainIdentifiers; + protected $iriToIdentifierConverter; - public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ClassMetadataFactoryInterface $classMetadataFactory = null, ItemDataProviderInterface $itemDataProvider = null, bool $allowPlainIdentifiers = false) + public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ClassMetadataFactoryInterface $classMetadataFactory = null, ItemDataProviderInterface $itemDataProvider = null, bool $allowPlainIdentifiers = false, IriToIdentifierConverterInterface $iriToIdentifierConverter = null) { parent::__construct($classMetadataFactory, $nameConverter); @@ -68,6 +66,7 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName } $this->itemDataProvider = $itemDataProvider; $this->allowPlainIdentifiers = $allowPlainIdentifiers; + $this->iriToIdentifierConverter = $iriToIdentifierConverter; $this->setCircularReferenceHandler(function ($object) { return $this->iriConverter->getIriFromItem($object); @@ -317,11 +316,11 @@ protected function denormalizeRelation(string $attributeName, PropertyMetadata $ if (!\is_array($value)) { try { // repeat the code so that IRIs keep working with the json format - if (true === $this->allowPlainIdentifiers && ($this->iriConverter instanceof IriToIdentifierConverterInterface && $this->iriConverter instanceof IriConverterInterface)) { - return $this->iriConverter->getItemFromIri($this->iriConverter->getIriFromPlainIdentifier($value, $className), $context + ['fetch_data' => true]); + if (($allowPlainIdentifiers = true === $this->allowPlainIdentifiers) && $this->iriToIdentifierConverter) { + return $this->iriConverter->getItemFromIri($this->iriToIdentifierConverter->getIriFromPlainIdentifier((array) $value, $className), $context + ['fetch_data' => true]); } - if (true === $this->allowPlainIdentifiers && $this->itemDataProvider) { + if ($allowPlainIdentifiers && $this->itemDataProvider) { return $this->itemDataProvider->getItem($className, $value, null, $context + ['fetch_data' => true]); } } catch (ItemNotFoundException $e) { diff --git a/tests/Bridge/Symfony/Routing/IriConverterTest.php b/tests/Bridge/Symfony/Routing/IriConverterTest.php index 283616e0f95..4f9b28d4365 100644 --- a/tests/Bridge/Symfony/Routing/IriConverterTest.php +++ b/tests/Bridge/Symfony/Routing/IriConverterTest.php @@ -88,7 +88,7 @@ public function testGetItemFromIriItemNotFoundException() /** * @group legacy - * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3. + * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3. * @expectedDeprecation Not injecting ApiPlatform\Core\Api\ResourceClassResolverInterface in the CachedIdentifiersExtractor might introduce cache issues with object identifiers. */ public function testIdentifiersExtractorDeprecation() @@ -115,6 +115,7 @@ public function testIdentifiersExtractorDeprecation() $routerProphecy->reveal(), null, null, + null, $identifierDenormalizer->reveal() ); } @@ -254,9 +255,10 @@ public function testGetItemIriFromPlainIdentifier() $routerProphecy->reveal(), null, new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, null, $this->getResourceClassResolver()), + null, $identifierDenormalizer->reveal() ); - $this->assertEquals($converter->getIriFromPlainIdentifier(1, Dummy::class), '/dummies/1'); + $this->assertEquals($converter->getIriFromPlainIdentifier([1], Dummy::class), '/dummies/1'); } /** @@ -359,7 +361,7 @@ public function testGetItemFromIriBadIdentifierException() /** * @group legacy - * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3. + * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3. * @expectedDeprecation Not injecting ApiPlatform\Core\Api\ResourceClassResolverInterface in the CachedIdentifiersExtractor might introduce cache issues with object identifiers. */ public function testLegacyConstructor() @@ -421,9 +423,10 @@ public function testNotAbleToGenerateAnIriWithGetIriFromPlainIdentifier() $routerProphecy->reveal(), null, new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, null, $this->getResourceClassResolver()), + null, $identifierDenormalizer->reveal() ); - $converter->getIriFromPlainIdentifier(1, Dummy::class); + $converter->getIriFromPlainIdentifier([1], Dummy::class); } /** @@ -459,6 +462,7 @@ public function testNotAbleToGenerateGetIriFromItem() $routerProphecy->reveal(), null, $identifierExtractorProphecy->reveal(), + null, $identifierDenormalizer->reveal() ); $converter->getIriFromItem($dummy); @@ -466,7 +470,7 @@ public function testNotAbleToGenerateGetIriFromItem() /** * @group legacy - * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.3 and will not be possible anymore in API Platform 3. + * @expectedDeprecation Not injecting "ApiPlatform\Core\Api\IdentifiersExtractorInterface" is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3. * @expectedException \ApiPlatform\Core\Exception\InvalidArgumentException * @expectedExceptionMessage Unable to generate an IRI for the item of type "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy" */ @@ -495,7 +499,7 @@ public function testNotAbleToGenerateAnIriWithGetItemIriFromPlainIdentifierRoute $routerProphecy->reveal(), null ); - $converter->getIriFromPlainIdentifier(1, Dummy::class); + $converter->getIriFromPlainIdentifier([1], Dummy::class); } private function getResourceClassResolver() diff --git a/tests/Serializer/AbstractItemNormalizerTest.php b/tests/Serializer/AbstractItemNormalizerTest.php index 453ef449501..3e6ef734a92 100644 --- a/tests/Serializer/AbstractItemNormalizerTest.php +++ b/tests/Serializer/AbstractItemNormalizerTest.php @@ -737,9 +737,10 @@ public function testDenormalizeRelationWithPlainId() return is_array($arg) && isset($arg['fetch_data']) && true === $arg['fetch_data']; }; - $iriConverterProphecy = $this->prophesize(IriToIdentifierConverterInterface::class)->willImplement(IriConverterInterface::class); + $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $iriConverterProphecy->getItemFromIri('/related_dummies/1', Argument::that($getItemFromIriSecondArgCallback))->shouldBeCalled(); - $iriConverterProphecy->getIriFromPlainIdentifier('1', RelatedDummy::class)->shouldBeCalled()->willReturn('/related_dummies/1'); + $iriToIdentifierConverterProphecy = $this->prophesize(IriToIdentifierConverterInterface::class); + $iriToIdentifierConverterProphecy->getIriFromPlainIdentifier([1], RelatedDummy::class)->shouldBeCalled()->willReturn('/related_dummies/1'); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); @@ -758,6 +759,7 @@ public function testDenormalizeRelationWithPlainId() null, null, true, + $iriToIdentifierConverterProphecy->reveal(), ]); $normalizer->setSerializer($serializerProphecy->reveal()); @@ -787,14 +789,15 @@ public function testDenormalizeNotFoundRelationWithPlainId() ) )->shouldBeCalled(); - $iriConverterProphecy = $this->prophesize(IriToIdentifierConverterInterface::class)->willImplement(IriConverterInterface::class); $getItemFromIriSecondArgCallback = function ($arg) { return is_array($arg) && isset($arg['fetch_data']) && true === $arg['fetch_data']; }; + $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $iriConverterProphecy->getItemFromIri('/related_dummies/1', Argument::that($getItemFromIriSecondArgCallback))->shouldBeCalled()->willThrow(new ItemNotFoundException('Item with id "1" not found for class "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy".')); - $iriConverterProphecy->getIriFromPlainIdentifier('1', RelatedDummy::class)->shouldBeCalled()->willReturn('/related_dummies/1'); + $iriToIdentifierConverterProphecy = $this->prophesize(IriToIdentifierConverterInterface::class); + $iriToIdentifierConverterProphecy->getIriFromPlainIdentifier([1], RelatedDummy::class)->shouldBeCalled()->willReturn('/related_dummies/1'); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); @@ -813,6 +816,7 @@ public function testDenormalizeNotFoundRelationWithPlainId() null, null, true, + $iriToIdentifierConverterProphecy->reveal(), ]); $normalizer->setSerializer($serializerProphecy->reveal());