Skip to content

Commit bce7e33

Browse files
authored
Merge pull request #2521 from notrix/fix-proxy-state-on-init-exception
Restore document proxy state to uninitialized on load exception
2 parents 856de18 + 9bbe84a commit bce7e33

File tree

2 files changed

+110
-1
lines changed

2 files changed

+110
-1
lines changed

lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use ProxyManager\Factory\LazyLoadingGhostFactory;
1616
use ProxyManager\Proxy\GhostObjectInterface;
1717
use ReflectionProperty;
18+
use Throwable;
1819

1920
use function array_filter;
2021
use function count;
@@ -108,7 +109,15 @@ private function createInitializer(
108109
$initializer = null;
109110
$identifier = $metadata->getIdentifierValue($ghostObject);
110111

111-
if (! $documentPersister->load(['_id' => $identifier], $ghostObject)) {
112+
try {
113+
$document = $documentPersister->load(['_id' => $identifier], $ghostObject);
114+
} catch (Throwable $exception) {
115+
$initializer = $originalInitializer;
116+
117+
throw $exception;
118+
}
119+
120+
if (! $document) {
112121
$initializer = $originalInitializer;
113122

114123
if (! $this->lifecycleEventManager->documentNotFound($ghostObject, $identifier)) {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\ODM\MongoDB\Tests\Proxy\Factory;
6+
7+
use Closure;
8+
use Doctrine\ODM\MongoDB\DocumentManager;
9+
use Doctrine\ODM\MongoDB\Event\DocumentNotFoundEventArgs;
10+
use Doctrine\ODM\MongoDB\Events;
11+
use Doctrine\ODM\MongoDB\LockException;
12+
use Doctrine\ODM\MongoDB\Tests\BaseTestCase;
13+
use Documents\Cart;
14+
use MongoDB\Client;
15+
use MongoDB\Collection;
16+
use MongoDB\Database;
17+
use PHPUnit\Framework\MockObject\MockObject;
18+
use ProxyManager\Proxy\GhostObjectInterface;
19+
20+
class StaticProxyFactoryTest extends BaseTestCase
21+
{
22+
/** @var Client|MockObject */
23+
private Client $client;
24+
25+
public function setUp(): void
26+
{
27+
parent::setUp();
28+
29+
$this->dm = $this->createMockedDocumentManager();
30+
}
31+
32+
public function testProxyInitializeWithException(): void
33+
{
34+
$collection = $this->createMock(Collection::class);
35+
$database = $this->createMock(Database::class);
36+
37+
$this->client->expects($this->once())
38+
->method('selectDatabase')
39+
->willReturn($database);
40+
41+
$database->expects($this->once())
42+
->method('selectCollection')
43+
->willReturn($collection);
44+
45+
$collection->expects($this->once())
46+
->method('findOne')
47+
->willThrowException(LockException::lockFailed(null));
48+
49+
$uow = $this->dm->getUnitOfWork();
50+
51+
$proxy = $this->dm->getReference(Cart::class, '123');
52+
self::assertInstanceOf(GhostObjectInterface::class, $proxy);
53+
54+
$closure = static function (DocumentNotFoundEventArgs $eventArgs) {
55+
self::fail('DocumentNotFoundListener should not be called');
56+
};
57+
$this->dm->getEventManager()->addEventListener(Events::documentNotFound, new DocumentNotFoundListener($closure));
58+
59+
try {
60+
$proxy->initializeProxy();
61+
self::fail('An exception should have been thrown');
62+
} catch (LockException $exception) {
63+
self::assertInstanceOf(LockException::class, $exception);
64+
}
65+
66+
$uow->computeChangeSets();
67+
68+
self::assertFalse($proxy->isProxyInitialized(), 'Proxy should not be initialized');
69+
}
70+
71+
public function tearDown(): void
72+
{
73+
// db connection is mocked, nothing to clean up
74+
}
75+
76+
private function createMockedDocumentManager(): DocumentManager
77+
{
78+
$config = $this->getConfiguration();
79+
80+
$this->client = $this->createMock(Client::class);
81+
82+
return DocumentManager::create($this->client, $config);
83+
}
84+
}
85+
86+
class DocumentNotFoundListener
87+
{
88+
private Closure $closure;
89+
90+
public function __construct(Closure $closure)
91+
{
92+
$this->closure = $closure;
93+
}
94+
95+
public function documentNotFound(DocumentNotFoundEventArgs $eventArgs): void
96+
{
97+
$closure = $this->closure;
98+
$closure($eventArgs);
99+
}
100+
}

0 commit comments

Comments
 (0)