diff --git a/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php b/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php index 9d5e56938..96fe25dbd 100644 --- a/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php +++ b/lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php @@ -15,6 +15,7 @@ use ProxyManager\Factory\LazyLoadingGhostFactory; use ProxyManager\Proxy\GhostObjectInterface; use ReflectionProperty; +use Throwable; use function array_filter; use function count; @@ -108,7 +109,15 @@ private function createInitializer( $initializer = null; $identifier = $metadata->getIdentifierValue($ghostObject); - if (! $documentPersister->load(['_id' => $identifier], $ghostObject)) { + try { + $document = $documentPersister->load(['_id' => $identifier], $ghostObject); + } catch (Throwable $exception) { + $initializer = $originalInitializer; + + throw $exception; + } + + if (! $document) { $initializer = $originalInitializer; if (! $this->lifecycleEventManager->documentNotFound($ghostObject, $identifier)) { diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Proxy/Factory/StaticProxyFactoryTest.php b/tests/Doctrine/ODM/MongoDB/Tests/Proxy/Factory/StaticProxyFactoryTest.php new file mode 100644 index 000000000..c70a46cfc --- /dev/null +++ b/tests/Doctrine/ODM/MongoDB/Tests/Proxy/Factory/StaticProxyFactoryTest.php @@ -0,0 +1,100 @@ +dm = $this->createMockedDocumentManager(); + } + + public function testProxyInitializeWithException(): void + { + $collection = $this->createMock(Collection::class); + $database = $this->createMock(Database::class); + + $this->client->expects($this->once()) + ->method('selectDatabase') + ->willReturn($database); + + $database->expects($this->once()) + ->method('selectCollection') + ->willReturn($collection); + + $collection->expects($this->once()) + ->method('findOne') + ->willThrowException(LockException::lockFailed(null)); + + $uow = $this->dm->getUnitOfWork(); + + $proxy = $this->dm->getReference(Cart::class, '123'); + self::assertInstanceOf(GhostObjectInterface::class, $proxy); + + $closure = static function (DocumentNotFoundEventArgs $eventArgs) { + self::fail('DocumentNotFoundListener should not be called'); + }; + $this->dm->getEventManager()->addEventListener(Events::documentNotFound, new DocumentNotFoundListener($closure)); + + try { + $proxy->initializeProxy(); + self::fail('An exception should have been thrown'); + } catch (LockException $exception) { + self::assertInstanceOf(LockException::class, $exception); + } + + $uow->computeChangeSets(); + + self::assertFalse($proxy->isProxyInitialized(), 'Proxy should not be initialized'); + } + + public function tearDown(): void + { + // db connection is mocked, nothing to clean up + } + + private function createMockedDocumentManager(): DocumentManager + { + $config = $this->getConfiguration(); + + $this->client = $this->createMock(Client::class); + + return DocumentManager::create($this->client, $config); + } +} + +class DocumentNotFoundListener +{ + private Closure $closure; + + public function __construct(Closure $closure) + { + $this->closure = $closure; + } + + public function documentNotFound(DocumentNotFoundEventArgs $eventArgs): void + { + $closure = $this->closure; + $closure($eventArgs); + } +}