diff --git a/lib/Doctrine/ORM/Proxy/ProxyFactory.php b/lib/Doctrine/ORM/Proxy/ProxyFactory.php index a09dc0f60ac..a32f12aaf4f 100644 --- a/lib/Doctrine/ORM/Proxy/ProxyFactory.php +++ b/lib/Doctrine/ORM/Proxy/ProxyFactory.php @@ -16,6 +16,7 @@ use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Utility\IdentifierFlattener; use Doctrine\Persistence\Mapping\ClassMetadata; +use Throwable; /** * This factory is used to create proxy objects for entities at runtime. @@ -130,7 +131,17 @@ private function createInitializer(ClassMetadata $classMetadata, EntityPersister $identifier = $classMetadata->getIdentifierValues($proxy); - if ($entityPersister->loadById($identifier, $proxy) === null) { + try { + $entity = $entityPersister->loadById($identifier, $proxy); + } catch (Throwable $exception) { + $proxy->__setInitializer($initializer); + $proxy->__setCloner($cloner); + $proxy->__setInitialized(false); + + throw $exception; + } + + if ($entity === null) { $proxy->__setInitializer($initializer); $proxy->__setCloner($cloner); $proxy->__setInitialized(false); diff --git a/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php b/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php index a2c0d53a6da..1a74ec58e45 100644 --- a/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php @@ -9,6 +9,7 @@ use Doctrine\Common\Proxy\AbstractProxyFactory; use Doctrine\Common\Proxy\Proxy; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Exception\ConnectionException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\ORM\EntityNotFoundException; use Doctrine\ORM\Mapping\ClassMetadata; @@ -148,6 +149,38 @@ public function testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized(): void self::assertInstanceOf(Closure::class, $proxy->__getCloner(), 'The cloner wasn\'t removed'); } + public function testExceptionOnProxyLoadingDoesNotMarkTheProxyAsInitialized(): void + { + $persister = $this + ->getMockBuilderWithOnlyMethods(BasicEntityPersister::class, ['load', 'getClassMetadata']) + ->disableOriginalConstructor() + ->getMock(); + $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister); + + $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]); + assert($proxy instanceof Proxy); + + $exception = $this + ->getMockBuilder(ConnectionException::class) + ->disableOriginalConstructor() + ->getMock(); + + $persister + ->expects(self::atLeastOnce()) + ->method('load') + ->will(self::throwException($exception)); + + try { + $proxy->getDescription(); + self::fail('An exception was expected to be raised'); + } catch (ConnectionException $exception) { + } + + self::assertFalse($proxy->__isInitialized(), 'The proxy should not be initialized'); + self::assertInstanceOf(Closure::class, $proxy->__getInitializer(), 'The initializer wasn\'t removed'); + self::assertInstanceOf(Closure::class, $proxy->__getCloner(), 'The cloner wasn\'t removed'); + } + /** @group DDC-2432 */ public function testFailedProxyCloningDoesNotMarkTheProxyAsInitialized(): void {