Skip to content

Commit

Permalink
Restore document proxy state to uninitialized on load exception
Browse files Browse the repository at this point in the history
  • Loading branch information
notrix committed Apr 21, 2023
1 parent 099e51d commit 6c049ce
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 1 deletion.
13 changes: 12 additions & 1 deletion lib/Doctrine/ORM/Proxy/ProxyFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 33 additions & 0 deletions tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
{
Expand Down

0 comments on commit 6c049ce

Please sign in to comment.