diff --git a/src/Construction/DoctrineObjectConstructor.php b/src/Construction/DoctrineObjectConstructor.php index 340c0a1d5..d00305b31 100644 --- a/src/Construction/DoctrineObjectConstructor.php +++ b/src/Construction/DoctrineObjectConstructor.php @@ -101,7 +101,9 @@ public function construct(DeserializationVisitorInterface $visitor, ClassMetadat return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); } - if (!array_key_exists($propertyMetadata->serializedName, $data)) { + if (is_array($data) && !array_key_exists($propertyMetadata->serializedName, $data)) { + return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); + } elseif (is_object($data) && !property_exists($data, $propertyMetadata->serializedName)) { return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); } diff --git a/tests/Serializer/Doctrine/ObjectConstructorTest.php b/tests/Serializer/Doctrine/ObjectConstructorTest.php index 1faeece44..9ace32a94 100644 --- a/tests/Serializer/Doctrine/ObjectConstructorTest.php +++ b/tests/Serializer/Doctrine/ObjectConstructorTest.php @@ -18,6 +18,10 @@ use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Version as ORMVersion; use Doctrine\Persistence\AbstractManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata; +use Doctrine\Persistence\Mapping\ClassMetadataFactory; +use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\Proxy; use JMS\Serializer\Builder\CallbackDriverFactory; use JMS\Serializer\Builder\DefaultDriverFactory; @@ -30,6 +34,7 @@ use JMS\Serializer\GraphNavigatorInterface; use JMS\Serializer\Metadata\ClassMetadata; use JMS\Serializer\Metadata\Driver\DoctrineTypeDriver; +use JMS\Serializer\Metadata\PropertyMetadata; use JMS\Serializer\Naming\IdenticalPropertyNamingStrategy; use JMS\Serializer\Serializer; use JMS\Serializer\SerializerBuilder; @@ -328,6 +333,57 @@ static function ($id) use ($connection, $entityManager) { $constructor->construct($this->visitor, $class, $data, $type, $this->context); } + /** + * php7.4 Using array_key_exists() on objects is deprecated. + */ + public function testArrayKeyExistsOnObject(): void + { + $metadataFactory = $this->createMock(ClassMetadataFactory::class); + + $ormClassMetadata = $this->createMock(DoctrineClassMetadata::class); + $ormClassMetadata + ->expects(self::atLeastOnce()) + ->method('getIdentifierFieldNames') + ->willReturn(['id']); + + $om = $this->createMock(ObjectManager::class); + $om + ->expects(self::atLeastOnce()) + ->method('getMetadataFactory') + ->willReturn($metadataFactory); + $om + ->expects(self::atLeastOnce()) + ->method('getClassMetadata') + ->willReturnMap([ + [BlogPostSeo::class, $ormClassMetadata], + ]); + + $registry = $this->createMock(ManagerRegistry::class); + $registry + ->expects(self::atLeastOnce()) + ->method('getManagerForClass') + ->willReturnMap([ + [BlogPostSeo::class, $om], + ]); + + $fallback = $this->createMock(ObjectConstructorInterface::class); + $fallback + ->expects(self::once()) + ->method('construct'); + + $type = ['name' => BlogPostSeo::class, 'params' => []]; + + $pm = $this->createMock(PropertyMetadata::class); + $pm->serializedName = 'id'; + + $classMetadata = new ClassMetadata(BlogPostSeo::class); + $classMetadata->propertyMetadata['id'] = $pm; + + $data = new \SimpleXMLElement('test'); + $constructor = new DoctrineObjectConstructor($registry, $fallback, DoctrineObjectConstructor::ON_MISSING_FALLBACK); + $constructor->construct($this->visitor, $classMetadata, $data, $type, $this->context); + } + protected function setUp(): void { $this->visitor = $this->getMockBuilder(DeserializationVisitorInterface::class)->getMock();