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 6, 2023
1 parent 856de18 commit cc182e9
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 1 deletion.
11 changes: 10 additions & 1 deletion lib/Doctrine/ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use ProxyManager\Factory\LazyLoadingGhostFactory;
use ProxyManager\Proxy\GhostObjectInterface;
use ReflectionProperty;
use Throwable;

use function array_filter;
use function count;
Expand Down Expand Up @@ -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)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace Doctrine\ODM\MongoDB\Tests\Proxy\Factory;

use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\LockException;
use Doctrine\ODM\MongoDB\Proxy\Factory\StaticProxyFactory;
use Doctrine\ODM\MongoDB\Tests\BaseTestCase;
use Documents\PaymentProvider;
use MongoDB\Client;
use MongoDB\Collection;
use MongoDB\Database;
use PHPUnit\Framework\MockObject\MockObject;

class StaticProxyFactoryTest extends BaseTestCase
{
/** @var Client|MockObject */
private Client $client;

private StaticProxyFactory $proxyFactory;

public function setUp(): void
{
parent::setUp();

$this->dm = $this->createMockedDocumentManager();
$this->proxyFactory = new StaticProxyFactory($this->dm);
}

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();

$metadata = $this->dm->getClassMetadata(PaymentProvider::class);

$proxy = $this->proxyFactory->getProxy($metadata, '123');
$uow->registerManaged($proxy, '123', []);

try {
$proxy->initializeProxy();
} catch (LockException $exception) {
$this->assertInstanceOf(LockException::class, $exception);
}

$uow->computeChangeSets();

$this->assertFalse($uow->isScheduledForUpdate($proxy), 'Proxy should not be scheduled for update');
$this->assertFalse($proxy->isProxyInitialized(), 'Proxy should not be initialized');
}

public function tearDown(): void
{
}

protected function createMockedDocumentManager(): DocumentManager
{
$config = $this->getConfiguration();

$this->client = $this->createMock(Client::class);

return DocumentManager::create($this->client, $config);
}
}
80 changes: 80 additions & 0 deletions tests/Documents/PaymentProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace Documents;

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/** @ODM\Document */
class PaymentProvider
{
/**
* @ODM\Id
*
* @var string|null
*/
public $id;

/**
* @ODM\Field(type="string")
*
* @var string|null
*/
private $title;

/**
* @ODM\Field(type="boolean")
*
* @var bool
*/
private $active = true;

/**
* @ODM\Field(type="hash")
*
* @var array<string, string>
*/
private $configuration = [];

public function getId(): ?string
{
return $this->id;
}

public function getTitle(): ?string
{
return $this->title;
}

public function setTitle(string $title): void
{
$this->title = $title;
}

public function isActive(): bool
{
return $this->active;
}

public function setActive(bool $active): self
{
$this->active = $active;

return $this;
}

/** @return array<string, string> */
public function getConfiguration(): array
{
return $this->configuration;
}

/** @param array<string, string> $configuration */
public function setConfiguration(array $configuration): self
{
$this->configuration = $configuration;

return $this;
}
}

0 comments on commit cc182e9

Please sign in to comment.