diff --git a/features/main/custom_normalized.feature b/features/main/custom_normalized.feature
index f9f636bdb4c..b8d1209f060 100644
--- a/features/main/custom_normalized.feature
+++ b/features/main/custom_normalized.feature
@@ -50,7 +50,7 @@ Feature: Using custom normalized entity
"""
Scenario: Create a resource with a custom normalized dummy and an id
- When I add "Content-Type" header equal to "application/json"
+ When I add "Content-Type" header equal to "application/ld+json"
When I add "Accept" header equal to "application/json"
And I send a "PUT" request to "/related_normalized_dummies/1" with body:
"""
@@ -58,7 +58,7 @@ Feature: Using custom normalized entity
"name": "My Dummy",
"customNormalizedDummy":[{
"@context": "/contexts/CustomNormalizedDummy",
- "@id": "/custom_normalized_dummies/1",
+ "@id": "app_dev.php/custom_normalized_dummies/1",
"@type": "CustomNormalizedDummy",
"id": 1,
"name": "My Dummy"
diff --git a/features/main/writable_identifier.feature b/features/main/writable_identifier.feature
new file mode 100644
index 00000000000..1e6cf9d8f09
--- /dev/null
+++ b/features/main/writable_identifier.feature
@@ -0,0 +1,53 @@
+Feature: Writable Identifier
+ In order to use a hypermedia API
+ As a client software developer
+ I need to be able to create resources with a writable identifier
+
+ @createSchema
+ Scenario: Create a resource with a custom identifier
+ When I add "Content-Type" header equal to "application/ld+json"
+ And I send a "POST" request to "/writable_ids" with body:
+ """
+ {
+ "id": "7995560a-4e09-4bba-8950-963528d004f0",
+ "name": "Foo"
+ }
+ """
+ Then the response status code should be 201
+ 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 equal to:
+ """
+ {
+ "@context": "/contexts/WritableId",
+ "@id": "/writable_ids/7995560a-4e09-4bba-8950-963528d004f0",
+ "@type": "WritableId",
+ "id": "7995560a-4e09-4bba-8950-963528d004f0",
+ "name": "Foo"
+ }
+ """
+
+ @dropSchema
+ Scenario: Update a resource with a custom identifier
+ When I add "Content-Type" header equal to "application/ld+json"
+ And I send a "PUT" request to "/writable_ids/7995560a-4e09-4bba-8950-963528d004f0" with body:
+ """
+ {
+ "@id": "/writable_ids/7995560a-4e09-4bba-8950-963528d004f1",
+ "id": "7995560a-4e09-4bba-8950-963528d004f1",
+ "name": "Foo"
+ }
+ """
+ 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 equal to:
+ """
+ {
+ "@context": "/contexts/WritableId",
+ "@id": "/writable_ids/7995560a-4e09-4bba-8950-963528d004f1",
+ "@type": "WritableId",
+ "id": "7995560a-4e09-4bba-8950-963528d004f1",
+ "name": "Foo"
+ }
+ """
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml
index 245bdec48f5..ba31a76fd28 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml
@@ -89,6 +89,7 @@
%api_platform.allow_plain_identifiers%
+
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml
index bdc491d1b38..b4906510708 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/graphql.xml
@@ -76,6 +76,7 @@
%api_platform.allow_plain_identifiers%
+
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/hal.xml b/src/Bridge/Symfony/Bundle/Resources/config/hal.xml
index 9e6a3f5d358..ec68f26b7e8 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/hal.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/hal.xml
@@ -34,6 +34,9 @@
+
+ %api_platform.allow_plain_identifiers%
+
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/jsonapi.xml b/src/Bridge/Symfony/Bundle/Resources/config/jsonapi.xml
index cc1fd13cd1b..ec857cffc96 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/jsonapi.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/jsonapi.xml
@@ -39,6 +39,7 @@
+
diff --git a/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml b/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml
index 999ce4ff92b..3b453208f7b 100644
--- a/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml
+++ b/src/Bridge/Symfony/Bundle/Resources/config/jsonld.xml
@@ -25,6 +25,7 @@
+
diff --git a/src/JsonApi/Serializer/ItemNormalizer.php b/src/JsonApi/Serializer/ItemNormalizer.php
index 0d0f754f0dd..6d018273eed 100644
--- a/src/JsonApi/Serializer/ItemNormalizer.php
+++ b/src/JsonApi/Serializer/ItemNormalizer.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\JsonApi\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\OperationType;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
@@ -40,9 +41,9 @@ final class ItemNormalizer extends AbstractItemNormalizer
private $componentsCache = [];
private $resourceMetadataFactory;
- public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ResourceMetadataFactoryInterface $resourceMetadataFactory)
+ public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ResourceMetadataFactoryInterface $resourceMetadataFactory, IdentifiersExtractorInterface $identifiersExtractor = null)
{
- parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter);
+ parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, null, null, false, $identifiersExtractor);
$this->resourceMetadataFactory = $resourceMetadataFactory;
}
@@ -108,18 +109,6 @@ public function supportsDenormalization($data, $type, $format = null)
*/
public function denormalize($data, $class, $format = null, array $context = [])
{
- // Avoid issues with proxies if we populated the object
- if (isset($data['data']['id']) && !isset($context[self::OBJECT_TO_POPULATE])) {
- if (isset($context['api_allow_update']) && true !== $context['api_allow_update']) {
- throw new InvalidArgumentException('Update is not allowed for this operation.');
- }
-
- $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri(
- $data['data']['id'],
- $context + ['fetch_data' => false]
- );
- }
-
// Merge attributes and relations previous to apply parents denormalizing
$dataToDenormalize = array_merge(
$data['data']['attributes'] ?? [],
diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php
index 5756b141e45..4d3b87d9180 100644
--- a/src/JsonLd/Serializer/ItemNormalizer.php
+++ b/src/JsonLd/Serializer/ItemNormalizer.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\JsonLd\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
@@ -41,9 +42,9 @@ final class ItemNormalizer extends AbstractItemNormalizer
private $resourceMetadataFactory;
private $contextBuilder;
- public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, ContextBuilderInterface $contextBuilder, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ClassMetadataFactoryInterface $classMetadataFactory = null)
+ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, IriConverterInterface $iriConverter, ResourceClassResolverInterface $resourceClassResolver, ContextBuilderInterface $contextBuilder, PropertyAccessorInterface $propertyAccessor = null, NameConverterInterface $nameConverter = null, ClassMetadataFactoryInterface $classMetadataFactory = null, IdentifiersExtractorInterface $identifiersExtractor = null)
{
- parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory);
+ parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $iriConverter, $resourceClassResolver, $propertyAccessor, $nameConverter, $classMetadataFactory, null, false, $identifiersExtractor);
$this->resourceMetadataFactory = $resourceMetadataFactory;
$this->contextBuilder = $contextBuilder;
@@ -91,20 +92,36 @@ public function supportsDenormalization($data, $type, $format = null)
/**
* {@inheritdoc}
- *
- * @throws InvalidArgumentException
*/
- public function denormalize($data, $class, $format = null, array $context = [])
+ protected function setObjectToPopulate($data, string $class, array &$context)
{
- // Avoid issues with proxies if we populated the object
- if (isset($data['@id']) && !isset($context[self::OBJECT_TO_POPULATE])) {
- if (isset($context['api_allow_update']) && true !== $context['api_allow_update']) {
- throw new InvalidArgumentException('Update is not allowed for this operation.');
- }
+ try {
+ parent::setObjectToPopulate($data, $class, $context);
- $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri($data['@id'], $context + ['fetch_data' => true]);
+ return;
+ } catch (InvalidArgumentException $e) {
}
- return parent::denormalize($data, $class, $format, $context);
+ // https://github.com/api-platform/core/issues/857
+ $identifiers = $this->identifiersExtractor->getIdentifiersFromResourceClass($class);
+ $identifiersData = \array_intersect_key($data, array_flip($identifiers));
+ if (0 === \count($identifiersData)) {
+ throw $e;
+ }
+
+ // TODO: use $this->iriConverter->getIriFromPlainIdentifier() once https://github.com/api-platform/core/pull/1837 is merged.
+ $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri(
+ sprintf(
+ '%s/%s',
+ $this->iriConverter->getIriFromResourceClass($context['resource_class']),
+ implode(';', $identifiersData)
+ ),
+ $context + ['fetch_data' => true]
+ );
+ }
+
+ protected function getIdentifiersForDenormalization(string $class): array
+ {
+ return ['@id'];
}
}
diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php
index 4d3cf52d355..a10460bd7c0 100644
--- a/src/Serializer/AbstractItemNormalizer.php
+++ b/src/Serializer/AbstractItemNormalizer.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\OperationType;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
@@ -50,8 +51,9 @@ abstract class AbstractItemNormalizer extends AbstractObjectNormalizer
protected $localCache = [];
protected $itemDataProvider;
protected $allowPlainIdentifiers;
+ protected $identifiersExtractor;
- 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, IdentifiersExtractorInterface $identifiersExtractor = null)
{
parent::__construct($classMetadataFactory, $nameConverter);
@@ -66,6 +68,12 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName
$this->setCircularReferenceHandler(function ($object) {
return $this->iriConverter->getIriFromItem($object);
});
+
+ if (null === $identifiersExtractor) {
+ @trigger_error(sprintf('Not passing an instance of IdentifiersExtractorInterface in "%s" is deprecated and will be mandatory in version 3.0. Not passing it is deprecated since 2.2.', __METHOD__), E_USER_DEPRECATED);
+ }
+
+ $this->identifiersExtractor = $identifiersExtractor;
}
/**
@@ -115,6 +123,8 @@ public function denormalize($data, $class, $format = null, array $context = [])
$context['resource_class'] = $class;
}
+ $this->setObjectToPopulate($data, $class, $context);
+
return parent::denormalize($data, $class, $format, $context);
}
@@ -488,4 +498,51 @@ protected function normalizeRelation(PropertyMetadata $propertyMetadata, $relate
return $iri;
}
+
+ /**
+ * Sets the object to populate if allowed to and not set already. If you pass identifiers, it will search for them,
+ * otherwise it falls back to the provided IdentifiersExtractor.
+ *
+ * @param mixed $data
+ * @param string $class
+ * @param array $context
+ */
+ protected function setObjectToPopulate($data, string $class, array &$context)
+ {
+ if (isset($context[self::OBJECT_TO_POPULATE]) || !\is_array($data)) {
+ return;
+ }
+
+ $updateAllowed = $context['api_allow_update'] ?? false;
+ $identifiers = $this->getIdentifiersForDenormalization($class);
+ $identifiersData = \array_intersect_key($data, array_flip($identifiers));
+
+ if (0 === \count($identifiersData)) {
+ return;
+ }
+
+ if (!$updateAllowed) {
+ throw new InvalidArgumentException('Update is not allowed for this operation.');
+ }
+
+ // TODO: use $this->iriConverter->getIriFromPlainIdentifier() once https://github.com/api-platform/core/pull/1837 is merged.
+ $iri = implode(';', $identifiersData);
+
+ $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri($iri, $context + ['fetch_data' => true]);
+ }
+
+ /**
+ * Returns the identifiers used when denormalizing an object.
+ * Usually this is just what the IdentifiersExtractor provides but you might want to override this method in your
+ * normalizer depending on the format used. Note: They also have to be writeable to serve as proper identifier.
+ */
+ protected function getIdentifiersForDenormalization(string $class): array
+ {
+ // Backwards compatibility
+ if (null === $this->identifiersExtractor) {
+ return ['id'];
+ }
+
+ return $this->identifiersExtractor->getIdentifiersFromResourceClass($class);
+ }
}
diff --git a/src/Serializer/ItemNormalizer.php b/src/Serializer/ItemNormalizer.php
index 36bb1799f1d..52289570d5a 100644
--- a/src/Serializer/ItemNormalizer.php
+++ b/src/Serializer/ItemNormalizer.php
@@ -13,8 +13,6 @@
namespace ApiPlatform\Core\Serializer;
-use ApiPlatform\Core\Exception\InvalidArgumentException;
-
/**
* Generic item normalizer.
*
@@ -24,43 +22,4 @@
*/
class ItemNormalizer extends AbstractItemNormalizer
{
- /**
- * {@inheritdoc}
- *
- * @throws InvalidArgumentException
- */
- public function denormalize($data, $class, $format = null, array $context = [])
- {
- // Avoid issues with proxies if we populated the object
- if (isset($data['id']) && !isset($context[self::OBJECT_TO_POPULATE])) {
- if (isset($context['api_allow_update']) && true !== $context['api_allow_update']) {
- throw new InvalidArgumentException('Update is not allowed for this operation.');
- }
-
- $this->updateObjectToPopulate($data, $context);
- }
-
- return parent::denormalize($data, $class, $format, $context);
- }
-
- private function updateObjectToPopulate(array $data, array &$context)
- {
- try {
- $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri((string) $data['id'], $context + ['fetch_data' => true]);
- } catch (InvalidArgumentException $e) {
- $identifier = null;
- foreach ($this->propertyNameCollectionFactory->create($context['resource_class'], $context) as $propertyName) {
- if (true === $this->propertyMetadataFactory->create($context['resource_class'], $propertyName)->isIdentifier()) {
- $identifier = $propertyName;
- break;
- }
- }
-
- if (null === $identifier) {
- throw $e;
- }
-
- $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri(sprintf('%s/%s', $this->iriConverter->getIriFromResourceClass($context['resource_class']), $data[$identifier]), $context + ['fetch_data' => true]);
- }
- }
}
diff --git a/tests/GraphQl/Serializer/ItemNormalizerTest.php b/tests/GraphQl/Serializer/ItemNormalizerTest.php
index 60a1b4ec566..18b2244fdc4 100644
--- a/tests/GraphQl/Serializer/ItemNormalizerTest.php
+++ b/tests/GraphQl/Serializer/ItemNormalizerTest.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\Tests\GraphQl\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer;
@@ -46,11 +47,19 @@ public function testSupportNormalization()
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled();
$resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$this->assertTrue($normalizer->supportsNormalization($dummy, ItemNormalizer::FORMAT));
@@ -85,11 +94,19 @@ public function testNormalize()
$serializerProphecy->willImplement(NormalizerInterface::class);
$serializerProphecy->normalize('hello', ItemNormalizer::FORMAT, Argument::type('array'))->willReturn('hello')->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -115,11 +132,20 @@ public function testDenormalize()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
diff --git a/tests/Hal/Serializer/ItemNormalizerTest.php b/tests/Hal/Serializer/ItemNormalizerTest.php
index 572f349c2ba..e8c8285a8f2 100644
--- a/tests/Hal/Serializer/ItemNormalizerTest.php
+++ b/tests/Hal/Serializer/ItemNormalizerTest.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\Tests\Hal\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\Exception\RuntimeException;
@@ -50,6 +51,7 @@ public function testDoesNotSupportDenormalization()
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$nameConverter = $this->prophesize(NameConverterInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
@@ -57,7 +59,11 @@ public function testDoesNotSupportDenormalization()
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
null,
- $nameConverter->reveal()
+ $nameConverter->reveal(),
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$this->assertFalse($normalizer->supportsDenormalization('foo', ItemNormalizer::FORMAT));
@@ -80,13 +86,19 @@ public function testSupportsNormalization()
$nameConverter = $this->prophesize(NameConverterInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
null,
- $nameConverter->reveal()
+ $nameConverter->reveal(),
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$this->assertTrue($normalizer->supportsNormalization($dummy, 'jsonhal'));
@@ -130,13 +142,19 @@ public function testNormalize()
$nameConverter->normalize('name')->shouldBeCalled()->willReturn('name');
$nameConverter->normalize('relatedDummy')->shouldBeCalled()->willReturn('related_dummy');
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
null,
- $nameConverter->reveal()
+ $nameConverter->reveal(),
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -190,13 +208,19 @@ public function testNormalizeWithoutCache()
$nameConverter->normalize('name')->shouldBeCalled()->willReturn('name');
$nameConverter->normalize('relatedDummy')->shouldBeCalled()->willReturn('related_dummy');
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
null,
- $nameConverter->reveal()
+ $nameConverter->reveal(),
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -270,7 +294,10 @@ public function testMaxDepth()
$resourceClassResolverProphecy->reveal(),
null,
null,
- $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()))
+ $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())),
+ null,
+ false,
+ $this->prophesize(IdentifiersExtractorInterface::class)->reveal()
);
$serializer = new Serializer([$normalizer]);
$normalizer->setSerializer($serializer);
diff --git a/tests/Hydra/Serializer/ItemNormalizerTest.php b/tests/Hydra/Serializer/ItemNormalizerTest.php
index f91b82bddd7..fb0e5403db5 100644
--- a/tests/Hydra/Serializer/ItemNormalizerTest.php
+++ b/tests/Hydra/Serializer/ItemNormalizerTest.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\Tests\Hydra\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\JsonLd\ContextBuilderInterface;
@@ -44,8 +45,20 @@ public function testDontSupportDenormalization()
$contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class);
$resourceClassResolverProphecy->getResourceClass(['dummy'], 'Dummy')->willReturn(Dummy::class);
$propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn(new PropertyNameCollection(['name' => 'name']));
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
- $normalizer = new ItemNormalizer($resourceMetadataFactoryProphecy->reveal(), $propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $contextBuilderProphecy->reveal());
+ $normalizer = new ItemNormalizer(
+ $resourceMetadataFactoryProphecy->reveal(),
+ $propertyNameCollectionFactoryProphecy->reveal(),
+ $propertyMetadataFactoryProphecy->reveal(),
+ $iriConverterProphecy->reveal(),
+ $resourceClassResolverProphecy->reveal(),
+ $contextBuilderProphecy->reveal(),
+ null,
+ null,
+ null,
+ $identifiersExtractor->reveal()
+ );
$this->assertFalse($normalizer->supportsDenormalization('foo', ItemNormalizer::FORMAT));
}
@@ -66,13 +79,19 @@ public function testSupportNormalization()
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled();
$resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$resourceMetadataFactoryProphecy->reveal(),
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
- $contextBuilderProphecy->reveal()
+ $contextBuilderProphecy->reveal(),
+ null,
+ null,
+ null,
+ $identifiersExtractor->reveal()
);
$this->assertTrue($normalizer->supportsNormalization($dummy, 'jsonld'));
@@ -108,13 +127,19 @@ public function testNormalize()
$contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class);
$contextBuilderProphecy->getResourceContextUri(Dummy::class)->willReturn('/contexts/Dummy');
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$resourceMetadataFactoryProphecy->reveal(),
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
- $contextBuilderProphecy->reveal()
+ $contextBuilderProphecy->reveal(),
+ null,
+ null,
+ null,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
diff --git a/tests/JsonApi/Serializer/ItemNormalizerTest.php b/tests/JsonApi/Serializer/ItemNormalizerTest.php
index 38a2b7cab48..1ee687a8105 100644
--- a/tests/JsonApi/Serializer/ItemNormalizerTest.php
+++ b/tests/JsonApi/Serializer/ItemNormalizerTest.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\Tests\JsonApi\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
@@ -47,6 +48,8 @@ public function testSupportDenormalization()
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled();
$resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$this->prophesize(PropertyNameCollectionFactoryInterface::class)->reveal(),
$this->prophesize(PropertyMetadataFactoryInterface::class)->reveal(),
@@ -54,7 +57,8 @@ public function testSupportDenormalization()
$resourceClassResolverProphecy->reveal(),
null,
null,
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$this->assertTrue($normalizer->supportsDenormalization(null, Dummy::class, ItemNormalizer::FORMAT));
@@ -70,6 +74,8 @@ public function testSupportNormalization()
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled();
$resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$this->prophesize(PropertyNameCollectionFactoryInterface::class)->reveal(),
$this->prophesize(PropertyMetadataFactoryInterface::class)->reveal(),
@@ -77,7 +83,8 @@ public function testSupportNormalization()
$resourceClassResolverProphecy->reveal(),
null,
null,
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$this->assertTrue($normalizer->supportsNormalization($dummy, ItemNormalizer::FORMAT));
@@ -120,6 +127,8 @@ public function testNormalize()
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
$iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/10')->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -127,7 +136,8 @@ public function testNormalize()
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
new ReservedAttributeNameConverter(),
- $resourceMetadataFactoryProphecy->reveal()
+ $resourceMetadataFactoryProphecy->reveal(),
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -156,6 +166,8 @@ public function testNormalizeIsNotAnArray()
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->getResourceClass($object, null, true)->willReturn(\stdClass::class)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$this->prophesize(PropertyNameCollectionFactoryInterface::class)->reveal(),
$this->prophesize(PropertyMetadataFactoryInterface::class)->reveal(),
@@ -163,7 +175,8 @@ public function testNormalizeIsNotAnArray()
$resourceClassResolverProphecy->reveal(),
$this->prophesize(PropertyAccessorInterface::class)->reveal(),
new ReservedAttributeNameConverter(),
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer(new Serializer([$normalizer]));
@@ -200,6 +213,8 @@ public function testNormalizeThrowsNoSuchPropertyException()
$propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);
$propertyAccessorProphecy->getValue($foo, 'bar')->willThrow(new NoSuchPropertyException());
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -207,7 +222,8 @@ public function testNormalizeThrowsNoSuchPropertyException()
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
new ReservedAttributeNameConverter(),
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$normalizer->normalize($foo, ItemNormalizer::FORMAT);
@@ -279,6 +295,9 @@ public function testDenormalize()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(NormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -286,7 +305,8 @@ public function testDenormalize()
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
new ReservedAttributeNameConverter(),
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -329,28 +349,41 @@ public function testDenormalizeUpdateOperationNotAllowed()
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Update is not allowed for this operation.');
+ $iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
+
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$this->prophesize(PropertyNameCollectionFactoryInterface::class)->reveal(),
$this->prophesize(PropertyMetadataFactoryInterface::class)->reveal(),
- $this->prophesize(IriConverterInterface::class)->reveal(),
+ $iriConverterProphecy->reveal(),
$this->prophesize(ResourceClassResolverInterface::class)->reveal(),
- null,
- null,
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(PropertyAccessorInterface::class)->reveal(),
+ new ReservedAttributeNameConverter(),
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
- $normalizer->denormalize(
- [
- 'data' => [
- 'id' => 1,
- 'type' => 'dummy',
- ],
- ],
+ $this->assertInstanceOf(
Dummy::class,
- ItemNormalizer::FORMAT,
- [
- 'api_allow_update' => false,
- ]
+ $normalizer->denormalize(
+ [
+ 'data' => [
+ 'type' => 'dummy',
+ 'attributes' => [
+ 'id' => '/dummies/1',
+ 'name' => 'foo',
+ 'ghost' => 'invisible',
+ ],
+ ],
+ ],
+ Dummy::class,
+ ItemNormalizer::FORMAT,
+ [
+ 'api_allow_update' => false,
+ ]
+ )
);
}
@@ -380,6 +413,9 @@ public function testDenormalizeCollectionIsNotArray()
)
)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -387,7 +423,8 @@ public function testDenormalizeCollectionIsNotArray()
$this->prophesize(ResourceClassResolverInterface::class)->reveal(),
$this->prophesize(PropertyAccessorInterface::class)->reveal(),
new ReservedAttributeNameConverter(),
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$normalizer->denormalize(
@@ -432,6 +469,9 @@ public function testDenormalizeCollectionWithInvalidKey()
)
)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -439,7 +479,8 @@ public function testDenormalizeCollectionWithInvalidKey()
$this->prophesize(ResourceClassResolverInterface::class)->reveal(),
$this->prophesize(PropertyAccessorInterface::class)->reveal(),
new ReservedAttributeNameConverter(),
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$normalizer->denormalize(
@@ -486,6 +527,9 @@ public function testDenormalizeRelationIsNotResourceLinkage()
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -493,7 +537,8 @@ public function testDenormalizeRelationIsNotResourceLinkage()
$resourceClassResolverProphecy->reveal(),
$this->prophesize(PropertyAccessorInterface::class)->reveal(),
new ReservedAttributeNameConverter(),
- $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal()
+ $this->prophesize(ResourceMetadataFactoryInterface::class)->reveal(),
+ $identifiersExtractor->reveal()
);
$normalizer->denormalize(
diff --git a/tests/Serializer/AbstractItemNormalizerTest.php b/tests/Serializer/AbstractItemNormalizerTest.php
index 420c6e5c898..a1e53a3b080 100644
--- a/tests/Serializer/AbstractItemNormalizerTest.php
+++ b/tests/Serializer/AbstractItemNormalizerTest.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\Tests\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
@@ -51,6 +52,7 @@ public function testSupportNormalizationAndSupportDenormalization()
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
$propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled();
@@ -62,6 +64,11 @@ public function testSupportNormalizationAndSupportDenormalization()
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$this->assertTrue($normalizer->supportsNormalization($dummy));
@@ -131,12 +138,19 @@ public function testNormalize()
$serializerProphecy->normalize('foo', null, Argument::type('array'))->willReturn('foo')->shouldBeCalled();
$serializerProphecy->normalize(['/dummies/2'], null, Argument::type('array'))->willReturn(['/dummies/2'])->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
$normalizer->setIgnoredAttributes(['alias']);
@@ -199,12 +213,19 @@ public function testNormalizeReadableLinks()
$serializerProphecy->normalize(['foo' => 'hello'], null, Argument::type('array'))->willReturn(['foo' => 'hello'])->shouldBeCalled();
$serializerProphecy->normalize([['foo' => 'hello']], null, Argument::type('array'))->willReturn([['foo' => 'hello']])->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -269,12 +290,20 @@ public function testDenormalize()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(NormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -341,12 +370,20 @@ public function testDenormalizeWritableLinks()
['bar' => 'baz'], RelatedDummy::class, null, Argument::type('array')
)->willReturn($relatedDummy2)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -388,12 +425,20 @@ public function testBadRelationType()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -431,12 +476,20 @@ public function testInnerDocumentNotAllowed()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -465,12 +518,20 @@ public function testBadType()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -497,12 +558,20 @@ public function testJsonAllowIntAsFloat()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -546,12 +615,20 @@ public function testDenormalizeBadKeyType()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -581,12 +658,20 @@ public function testNullable()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -626,12 +711,19 @@ public function testChildInheritedProperty()
$serializerProphecy->normalize('foo', null, Argument::type('array'))->willReturn('foo')->shouldBeCalled();
$serializerProphecy->normalize(null, null, Argument::type('array'))->willReturn(null)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
$resourceClassResolverProphecy->reveal(),
$propertyAccessorProphecy->reveal(),
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -672,6 +764,9 @@ public function testDenormalizeRelationWithPlainId()
$itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class);
$itemDataProviderProphecy->getItem(RelatedDummy::class, 1, null, Argument::type('array'))->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -682,6 +777,7 @@ public function testDenormalizeRelationWithPlainId()
null,
$itemDataProviderProphecy->reveal(),
true,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -722,6 +818,9 @@ public function testDoNotDenormalizeRelationWithPlainIdWhenPlainIdentifiersAreNo
$itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class);
$itemDataProviderProphecy->getItem(RelatedDummy::class, 1, null, Argument::type('array'))->shouldNotBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
@@ -732,6 +831,7 @@ public function testDoNotDenormalizeRelationWithPlainIdWhenPlainIdentifiersAreNo
null,
$itemDataProviderProphecy->reveal(),
false,
+ $identifiersExtractor->reveal(),
]);
$normalizer->setSerializer($serializerProphecy->reveal());
diff --git a/tests/Serializer/ItemNormalizerTest.php b/tests/Serializer/ItemNormalizerTest.php
index 93b4ab4faef..482e2ab690c 100644
--- a/tests/Serializer/ItemNormalizerTest.php
+++ b/tests/Serializer/ItemNormalizerTest.php
@@ -13,6 +13,7 @@
namespace ApiPlatform\Core\Tests\Serializer;
+use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
@@ -47,11 +48,19 @@ public function testSupportNormalization()
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled();
$resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false)->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$this->assertTrue($normalizer->supportsNormalization($dummy));
@@ -86,11 +95,19 @@ public function testNormalize()
$serializerProphecy->willImplement(NormalizerInterface::class);
$serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello')->shouldBeCalled();
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -116,11 +133,20 @@ public function testDenormalize()
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -140,18 +166,27 @@ public function testDenormalizeWithIri()
$propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadataFactory)->shouldBeCalled();
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
- $iriConverterProphecy->getItemFromIri('/dummies/12', ['resource_class' => Dummy::class, 'api_allow_update' => true, 'fetch_data' => true])->shouldBeCalled();
+ $iriConverterProphecy->getItemFromIri('/dummies/12', ['resource_class' => Dummy::class, 'api_denormalize' => true, 'api_allow_update' => true, 'fetch_data' => true])->shouldBeCalled();
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(DenormalizerInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$normalizer = new ItemNormalizer(
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
@@ -171,6 +206,9 @@ public function testDenormalizeWithIdAndUpdateNotAllowed()
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
+ $identifiersExtractor = $this->prophesize(IdentifiersExtractorInterface::class);
+ $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)->willReturn(['id'])->shouldBeCalled();
+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$serializerProphecy = $this->prophesize(SerializerInterface::class);
@@ -180,9 +218,15 @@ public function testDenormalizeWithIdAndUpdateNotAllowed()
$propertyNameCollectionFactoryProphecy->reveal(),
$propertyMetadataFactoryProphecy->reveal(),
$iriConverterProphecy->reveal(),
- $resourceClassResolverProphecy->reveal()
+ $resourceClassResolverProphecy->reveal(),
+ null,
+ null,
+ null,
+ null,
+ false,
+ $identifiersExtractor->reveal()
);
$normalizer->setSerializer($serializerProphecy->reveal());
- $normalizer->denormalize(['id' => '12', 'name' => 'hello'], Dummy::class, null, $context);
+ $normalizer->denormalize(['id' => '/dummies/12', 'name' => 'hello'], Dummy::class, null, $context);
}
}