diff --git a/src/DeserializationContext.php b/src/DeserializationContext.php index 8edf30ffa..ed54d5898 100644 --- a/src/DeserializationContext.php +++ b/src/DeserializationContext.php @@ -16,7 +16,7 @@ class DeserializationContext extends Context /** * @var bool */ - private $deserializeNull = false; + private $deserializeNull = true; public static function create(): self { diff --git a/src/GraphNavigator/DeserializationGraphNavigator.php b/src/GraphNavigator/DeserializationGraphNavigator.php index 60f559ee6..3ff5c65dc 100644 --- a/src/GraphNavigator/DeserializationGraphNavigator.php +++ b/src/GraphNavigator/DeserializationGraphNavigator.php @@ -125,11 +125,10 @@ public function accept($data, ?array $type = null) // If null is explicitly allowed we should skip this if ($this->visitor instanceof NullAwareVisitorInterface && true === $this->visitor->isNull($data) - && (!empty($type['nullable']) || false === $this->shouldDeserializeNull) + && true === $this->shouldDeserializeNull ) { $type = ['name' => 'NULL', 'params' => []]; } - switch ($type['name']) { case 'NULL': return $this->visitor->visitNull($data, $type); @@ -170,9 +169,11 @@ public function accept($data, ?array $type = null) // before loading metadata because the type name might not be a class, but // could also simply be an artifical type. if (null !== $handler = $this->handlerRegistry->getHandler(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, $type['name'], $this->format)) { - $rs = \call_user_func($handler, $this->visitor, $data, $type, $this->context); - $this->context->decreaseDepth(); - + try { + $rs = \call_user_func($handler, $this->visitor, $data, $type, $this->context); + } finally { + $this->context->decreaseDepth(); + } return $rs; } @@ -219,9 +220,7 @@ public function accept($data, ?array $type = null) try { $v = $this->visitor->visitProperty($propertyMetadata, $data); - if (null !== $v || true === $this->shouldDeserializeNull) { - $this->accessor->setValue($object, $v, $propertyMetadata, $this->context); - } + $this->accessor->setValue($object, $v, $propertyMetadata, $this->context); } catch (NotAcceptableException $e) { } $this->context->popPropertyMetadata(); diff --git a/src/JsonDeserializationVisitor.php b/src/JsonDeserializationVisitor.php index f0b255c87..5b2696610 100644 --- a/src/JsonDeserializationVisitor.php +++ b/src/JsonDeserializationVisitor.php @@ -161,13 +161,6 @@ public function visitProperty(PropertyMetadata $metadata, $data) } if (true === $metadata->inline) { - if (!$metadata->type) { - throw new RuntimeException(sprintf( - 'You must define a type for %s::$%s.', - $metadata->class, - $metadata->name - )); - } return $this->navigator->accept($data, $metadata->type); } @@ -176,7 +169,7 @@ public function visitProperty(PropertyMetadata $metadata, $data) throw new NotAcceptableException(); } - return null !== $data[$name] ? $this->navigator->accept($data[$name], $metadata->type) : null; + return $this->navigator->accept($data[$name], $metadata->type); } /** diff --git a/tests/Fixtures/InitializedBlogPostConstructor.php b/tests/Fixtures/InitializedBlogPostConstructor.php index 078978b67..6a514832e 100644 --- a/tests/Fixtures/InitializedBlogPostConstructor.php +++ b/tests/Fixtures/InitializedBlogPostConstructor.php @@ -14,9 +14,15 @@ class InitializedBlogPostConstructor implements ObjectConstructorInterface { private $fallback; - public function __construct() + /** + * @var BlogPost + */ + private $blogPost; + + public function __construct(BlogPost $blogPost) { $this->fallback = new UnserializeObjectConstructor(); + $this->blogPost = $blogPost; } public function construct(DeserializationVisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context): ?object @@ -25,6 +31,6 @@ public function construct(DeserializationVisitorInterface $visitor, ClassMetadat return $this->fallback->construct($visitor, $metadata, $data, $type, $context); } - return new BlogPost('This is a nice title.', new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), new Publisher('Bar Foo')); + return $this->blogPost; } } diff --git a/tests/Serializer/BaseSerializationTest.php b/tests/Serializer/BaseSerializationTest.php index b4005fd1b..69c015a74 100644 --- a/tests/Serializer/BaseSerializationTest.php +++ b/tests/Serializer/BaseSerializationTest.php @@ -216,7 +216,7 @@ public function testDeserializeNullObjectWithHandler() $this->markTestSkipped(sprintf('No deserializer available for format `%s`', $this->getFormat())); } $ctx = DeserializationContext::create() - ->setDeserializeNull(true); + ->setDeserializeNull(false); /** @var ObjectWithNullObject $dObj */ $dObj = $this->serializer->deserialize( @@ -750,14 +750,13 @@ public function testBlogPost() public function testDeserializingNull() { - $objectConstructor = new InitializedBlogPostConstructor(); + $post = new BlogPost('This is a nice title.', $author = new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), new Publisher('Bar Foo')); + $objectConstructor = new InitializedBlogPostConstructor($post); $builder = SerializerBuilder::create(); $builder->setObjectConstructor($objectConstructor); $this->serializer = $builder->build(); - $post = new BlogPost('This is a nice title.', $author = new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), new Publisher('Bar Foo')); - $this->setField($post, 'author', null); $this->setField($post, 'publisher', null); @@ -771,37 +770,42 @@ public function testDeserializingNull() self::assertAttributeSame(false, 'published', $deserialized); self::assertAttributeSame(false, 'reviewed', $deserialized); self::assertAttributeEquals(new ArrayCollection(), 'comments', $deserialized); - self::assertAttributeEquals(null, 'author', $deserialized); + self::assertAttributeSame(null, 'author', $deserialized); + self::assertAttributeSame(null, 'tag', $deserialized); } } public function testDeserializingNullAllowed() { - $objectConstructor = new InitializedBlogPostConstructor(); + $savedPost = new BlogPost('This is a nice title.', $author = new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), $publisher = new Publisher('Bar Foo')); + $savedPost->addTag(new Tag('foo')); + $initialTag = $this->getField($savedPost, 'tag'); + + $objectConstructor = new InitializedBlogPostConstructor($savedPost); $builder = SerializerBuilder::create(); $builder->setObjectConstructor($objectConstructor); $this->serializer = $builder->build(); - $post = new BlogPost('This is a nice title.', $author = new Author('Foo Bar'), new \DateTime('2011-07-30 00:00', new \DateTimeZone('UTC')), new Publisher('Bar Foo')); - + $post = clone $savedPost; $this->setField($post, 'author', null); $this->setField($post, 'publisher', null); - - self::assertEquals($this->getContent('blog_post_unauthored'), $this->serialize($post, SerializationContext::create()->setSerializeNull(true))); + $this->setField($post, 'tag', null); if ($this->hasDeserializer()) { $ctx = DeserializationContext::create(); - $ctx->setDeserializeNull(true); + $ctx->setDeserializeNull(false); - $deserialized = $this->deserialize($this->getContent('blog_post_unauthored'), get_class($post), $ctx); + $deserialized = $this->deserialize($this->serialize($post), get_class($post), $ctx); self::assertEquals('2011-07-30T00:00:00+00:00', $this->getField($deserialized, 'createdAt')->format(\DateTime::ATOM)); self::assertAttributeEquals('This is a nice title.', 'title', $deserialized); self::assertAttributeSame(false, 'published', $deserialized); self::assertAttributeSame(false, 'reviewed', $deserialized); self::assertAttributeEquals(new ArrayCollection(), 'comments', $deserialized); - self::assertEquals(null, $this->getField($deserialized, 'author')); + self::assertAttributeEquals($author, 'author', $deserialized); + self::assertAttributeEquals($publisher, 'publisher', $deserialized); + self::assertAttributeEquals($initialTag, 'tag', $deserialized); } }