Skip to content

Commit 9bdb39c

Browse files
committed
Run the full test suite with proxy manager
1 parent 8742c51 commit 9bdb39c

21 files changed

+109
-56
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ jobs:
3434
- "highest"
3535
symfony-version:
3636
- "stable"
37+
proxy:
38+
- "lazy-ghost"
3739
include:
3840
# Test against lowest dependencies
3941
- dependencies: "lowest"
@@ -42,20 +44,30 @@ jobs:
4244
driver-version: "1.17.0"
4345
topology: "server"
4446
symfony-version: "stable"
47+
proxy: "lazy-ghost"
4548
# Test with highest dependencies
4649
- topology: "server"
4750
php-version: "8.2"
4851
mongodb-version: "7.0"
4952
driver-version: "stable"
5053
dependencies: "highest"
5154
symfony-version: "7"
55+
proxy: "lazy-ghost"
5256
# Test with a 5.0 replica set
5357
- topology: "replica_set"
5458
php-version: "8.2"
5559
mongodb-version: "5.0"
5660
driver-version: "stable"
5761
dependencies: "highest"
5862
symfony-version: "stable"
63+
proxy: "lazy-ghost"
64+
# Test with ProxyManager
65+
- php-version: "8.2"
66+
mongodb-version: "5.0"
67+
driver-version: "stable"
68+
dependencies: "highest"
69+
symfony-version: "stable"
70+
proxy: "proxy-manager"
5971
# Test with a 5.0 sharded cluster
6072
# Currently disabled due to a bug where MongoDB reports "sharding status unknown"
6173
# - topology: "sharded_cluster"
@@ -64,6 +76,7 @@ jobs:
6476
# driver-version: "stable"
6577
# dependencies: "highest"
6678
# symfony-version: "stable"
79+
# proxy: "lazy-ghost"
6780

6881
steps:
6982
- name: "Checkout"
@@ -118,6 +131,13 @@ jobs:
118131
# https://github.com/vimeo/psalm/pull/10928
119132
composer remove --no-update --dev vimeo/psalm
120133
134+
- name: "Remove proxy-manager-lts"
135+
if: "${{ matrix.lazy-ghost == 'true' }}"
136+
run: |
137+
# proxy-manager-lts is not installed by default and must not be used
138+
# unless explicitly requested
139+
composer remove --no-update --dev friendsofphp/proxy-manager-lts
140+
121141
- name: "Install dependencies with Composer"
122142
uses: "ramsey/composer-install@v3"
123143
with:
@@ -134,3 +154,4 @@ jobs:
134154
run: "vendor/bin/phpunit"
135155
env:
136156
DOCTRINE_MONGODB_SERVER: ${{ steps.setup-mongodb.outputs.cluster-uri }}
157+
USE_LAZY_GHOST_OBJECTS: ${{ matrix.proxy == 'lazy-ghost' && '1' || '0' }}"

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,20 @@
2828
"doctrine/event-manager": "^1.0 || ^2.0",
2929
"doctrine/instantiator": "^1.1 || ^2",
3030
"doctrine/persistence": "^3.2",
31-
"friendsofphp/proxy-manager-lts": "^1.0",
3231
"jean85/pretty-package-versions": "^1.3.0 || ^2.0.1",
3332
"mongodb/mongodb": "^1.17.0",
3433
"psr/cache": "^1.0 || ^2.0 || ^3.0",
3534
"symfony/console": "^5.4 || ^6.0 || ^7.0",
3635
"symfony/deprecation-contracts": "^2.2 || ^3.0",
3736
"symfony/var-dumper": "^5.4 || ^6.0 || ^7.0",
38-
"symfony/var-exporter": "^5.4 || ^6.0 || ^7.0"
37+
"symfony/var-exporter": "^6.2 || ^7.0"
3938
},
4039
"require-dev": {
4140
"ext-bcmath": "*",
4241
"doctrine/annotations": "^1.12 || ^2.0",
4342
"doctrine/coding-standard": "^12.0",
4443
"doctrine/orm": "^3.2",
44+
"friendsofphp/proxy-manager-lts": "^1.0",
4545
"jmikola/geojson": "^1.0",
4646
"phpbench/phpbench": "^1.0.0",
4747
"phpstan/phpstan": "~1.10.67",

lib/Doctrine/ODM/MongoDB/Configuration.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
2525
use Doctrine\Persistence\ObjectRepository;
2626
use InvalidArgumentException;
27+
use LogicException;
2728
use MongoDB\Driver\WriteConcern;
2829
use ProxyManager\Configuration as ProxyManagerConfiguration;
2930
use ProxyManager\Factory\LazyLoadingGhostFactory;
@@ -33,6 +34,7 @@
3334
use ReflectionClass;
3435

3536
use function array_key_exists;
37+
use function class_exists;
3638
use function interface_exists;
3739
use function trigger_deprecation;
3840
use function trim;
@@ -128,6 +130,8 @@ class Configuration
128130

129131
private bool $useTransactionalFlush = false;
130132

133+
private bool $useLazyGhostObject = true;
134+
131135
/**
132136
* Adds a namespace under a certain alias.
133137
*/
@@ -613,6 +617,32 @@ public function isTransactionalFlushEnabled(): bool
613617
{
614618
return $this->useTransactionalFlush;
615619
}
620+
621+
/**
622+
* Generate proxy classes using Symfony VarExporter's LazyGhostTrait if true.
623+
* Otherwise, use ProxyManager's LazyLoadingGhostFactory (deprecated)
624+
*/
625+
public function setUseLazyGhostObject(bool $flag): void
626+
{
627+
if ($flag === false) {
628+
if (! class_exists(ProxyManagerConfiguration::class)) {
629+
throw new LogicException('Package "friendsofphp/proxy-manager-lts" is required to disable LazyGhostObject.');
630+
}
631+
632+
trigger_deprecation(
633+
'doctrine/mongodb-odm',
634+
'2.6',
635+
'Using "friendsofphp/proxy-manager-lts" is deprecated. Use "symfony/var-exporter" LazyGhostObjects instead.',
636+
);
637+
}
638+
639+
$this->useLazyGhostObject = $flag;
640+
}
641+
642+
public function isLazyGhostObjectEnabled(): bool
643+
{
644+
return $this->useLazyGhostObject ?? true;
645+
}
616646
}
617647

618648
interface_exists(MappingDriver::class);

lib/Doctrine/ODM/MongoDB/DocumentManager.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
use Doctrine\ODM\MongoDB\Mapping\MappingException;
1212
use Doctrine\ODM\MongoDB\Proxy\Factory\LazyGhostProxyFactory;
1313
use Doctrine\ODM\MongoDB\Proxy\Factory\ProxyFactory;
14+
use Doctrine\ODM\MongoDB\Proxy\Factory\StaticProxyFactory;
1415
use Doctrine\ODM\MongoDB\Proxy\Resolver\CachingClassNameResolver;
1516
use Doctrine\ODM\MongoDB\Proxy\Resolver\ClassNameResolver;
1617
use Doctrine\ODM\MongoDB\Proxy\Resolver\LazyGhostProxyClassNameResolver;
18+
use Doctrine\ODM\MongoDB\Proxy\Resolver\ProxyManagerClassNameResolver;
1719
use Doctrine\ODM\MongoDB\Query\FilterCollection;
1820
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
1921
use Doctrine\ODM\MongoDB\Repository\GridFSRepository;
@@ -156,7 +158,9 @@ protected function __construct(?Client $client = null, ?Configuration $config =
156158
],
157159
);
158160

159-
$this->classNameResolver = new CachingClassNameResolver(new LazyGhostProxyClassNameResolver());
161+
$this->classNameResolver = $config->isLazyGhostObjectEnabled()
162+
? new CachingClassNameResolver(new LazyGhostProxyClassNameResolver())
163+
: new CachingClassNameResolver(new ProxyManagerClassNameResolver($this->config));
160164

161165
$metadataFactoryClassName = $this->config->getClassMetadataFactoryName();
162166
$this->metadataFactory = new $metadataFactoryClassName();
@@ -181,7 +185,9 @@ protected function __construct(?Client $client = null, ?Configuration $config =
181185

182186
$this->unitOfWork = new UnitOfWork($this, $this->eventManager, $this->hydratorFactory);
183187
$this->schemaManager = new SchemaManager($this, $this->metadataFactory);
184-
$this->proxyFactory = new LazyGhostProxyFactory($this, $config->getProxyDir(), $config->getProxyNamespace(), $config->getAutoGenerateProxyClasses());
188+
$this->proxyFactory = $config->isLazyGhostObjectEnabled()
189+
? new LazyGhostProxyFactory($this, $config->getProxyDir(), $config->getProxyNamespace(), $config->getAutoGenerateProxyClasses())
190+
: new StaticProxyFactory($this);
185191
$this->repositoryFactory = $this->config->getRepositoryFactory();
186192
}
187193

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public function __serialize(): array
8484
private readonly UnitOfWork $uow;
8585

8686
/** @var Configuration::AUTOGENERATE_* */
87-
private $autoGenerate;
87+
private int $autoGenerate;
8888

8989
/** @var array<class-string, Closure> */
9090
private array $proxyFactories = [];

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
/**
2424
* This factory is used to create proxy objects for documents at runtime.
2525
*
26-
* @deprecated
26+
* @deprecated since 2.10, use LazyGhostProxyFactory instead
2727
*/
2828
final class StaticProxyFactory implements ProxyFactory
2929
{

phpunit.xml.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@
2929
<ini name="error_reporting" value="-1"/>
3030
<const name="DOCTRINE_MONGODB_SERVER" value="mongodb://localhost:27017" />
3131
<const name="DOCTRINE_MONGODB_DATABASE" value="doctrine_odm_tests" />
32+
<env name="USE_LAZY_GHOST_OBJECTS" value="1"/>
3233
</php>
3334
</phpunit>

tests/Doctrine/ODM/MongoDB/Tests/BaseTestCase.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Doctrine\ODM\MongoDB\Tests;
66

7+
use Composer\InstalledVersions;
78
use Doctrine\ODM\MongoDB\Configuration;
89
use Doctrine\ODM\MongoDB\DocumentManager;
910
use Doctrine\ODM\MongoDB\Mapping\Driver\AttributeDriver;
@@ -89,6 +90,7 @@ protected static function getConfiguration(): Configuration
8990
$config->setPersistentCollectionNamespace('PersistentCollections');
9091
$config->setDefaultDB(DOCTRINE_MONGODB_DATABASE);
9192
$config->setMetadataDriverImpl(static::createMetadataDriverImpl());
93+
$config->setUseLazyGhostObject((bool) $_ENV['USE_LAZY_GHOST_OBJECTS']);
9294

9395
$config->addFilter('testFilter', Filter::class);
9496
$config->addFilter('testFilter2', Filter::class);
@@ -118,10 +120,14 @@ public static function assertArraySubset(array $subset, array $array, bool $chec
118120

119121
public static function assertIsLazyObject(object $document): void
120122
{
121-
self::logicalOr(
122-
self::isInstanceOf(InternalProxy::class),
123-
self::isInstanceOf(LazyLoadingInterface::class),
124-
)->evaluate($document);
123+
if (InstalledVersions::isInstalled('friendsofphp/proxy-manager')) {
124+
self::logicalOr(
125+
self::isInstanceOf(InternalProxy::class),
126+
self::isInstanceOf(LazyLoadingInterface::class),
127+
)->evaluate($document);
128+
} else {
129+
self::assertInstanceOf(InternalProxy::class, $document);
130+
}
125131
}
126132

127133
protected static function createMetadataDriverImpl(): MappingDriver

tests/Doctrine/ODM/MongoDB/Tests/Functional/IdentifiersTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Doctrine\ODM\MongoDB\Tests\Functional;
66

7-
use Doctrine\ODM\MongoDB\Proxy\InternalProxy;
87
use Doctrine\ODM\MongoDB\Tests\BaseTestCase;
98
use Documents\Event;
109
use Documents\User;
@@ -30,7 +29,7 @@ public function testGetIdentifierValue(): void
3029

3130
$userTest = $test->getUser();
3231
self::assertEquals($user->getId(), $userTest->getId());
33-
self::assertInstanceOf(InternalProxy::class, $userTest);
32+
self::assertIsLazyObject($userTest);
3433
self::assertTrue($this->uow->isUninitializedObject($userTest));
3534

3635
$this->dm->clear();
@@ -42,7 +41,7 @@ public function testGetIdentifierValue(): void
4241
$foundUser = $test->getUser();
4342
self::assertEquals($user->getId(), $class->getIdentifierValue($user));
4443
self::assertEquals($user->getId(), $class->getFieldValue($foundUser, 'id'));
45-
self::assertInstanceOf(InternalProxy::class, $foundUser);
44+
self::assertIsLazyObject($foundUser);
4645
self::assertTrue($this->uow->isUninitializedObject($foundUser));
4746

4847
self::assertEquals('jwage', $foundUser->getUsername());

tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function testPrimeReferencesWithDBRefObjects(): void
9595
->field('groups')->prime(true);
9696

9797
foreach ($qb->getQuery() as $user) {
98-
self::assertInstanceOf(InternalProxy::class, $user->getAccount());
98+
self::assertIsLazyObject($user->getAccount());
9999
self::assertFalse($this->uow->isUninitializedObject($user->getAccount()));
100100

101101
self::assertCount(2, $user->getGroups());
@@ -133,7 +133,7 @@ public function testPrimeReferencesWithSimpleReferences(): void
133133
->field('users')->prime(true);
134134

135135
foreach ($qb->getQuery() as $simpleUser) {
136-
self::assertInstanceOf(InternalProxy::class, $simpleUser->getUser());
136+
self::assertIsLazyObject($simpleUser->getUser());
137137
self::assertFalse($this->uow->isUninitializedObject($simpleUser->getUser()));
138138

139139
self::assertCount(2, $simpleUser->getUsers());
@@ -196,7 +196,7 @@ public function testPrimeReferencesNestedInNamedEmbeddedReference(): void
196196
self::assertNotInstanceOf(InternalProxy::class, $embeddedDoc);
197197
self::assertInstanceOf(EmbeddedWhichReferences::class, $embeddedDoc);
198198

199-
self::assertInstanceOf(InternalProxy::class, $embeddedDoc->referencedDoc);
199+
self::assertIsLazyObject($embeddedDoc->referencedDoc);
200200
self::assertFalse($this->uow->isUninitializedObject($embeddedDoc->referencedDoc));
201201

202202
self::assertCount(2, $embeddedDoc->referencedDocs);
@@ -252,7 +252,7 @@ public function testPrimeReferencesWithDifferentStoreAsReferences(): void
252252
assert($referenceUser instanceof ReferenceUser);
253253
$user = $referenceUser->getUser();
254254
self::assertInstanceOf(User::class, $user);
255-
self::assertInstanceOf(InternalProxy::class, $user);
255+
self::assertIsLazyObject($user);
256256
self::assertFalse($this->uow->isUninitializedObject($user));
257257

258258
self::assertCount(1, $referenceUser->getUsers());
@@ -263,7 +263,7 @@ public function testPrimeReferencesWithDifferentStoreAsReferences(): void
263263
}
264264

265265
$parentUser = $referenceUser->getParentUser();
266-
self::assertInstanceOf(InternalProxy::class, $parentUser);
266+
self::assertIsLazyObject($parentUser);
267267
self::assertInstanceOf(User::class, $parentUser);
268268
self::assertFalse($this->uow->isUninitializedObject($parentUser));
269269

@@ -276,7 +276,7 @@ public function testPrimeReferencesWithDifferentStoreAsReferences(): void
276276

277277
$otherUser = $referenceUser->getOtherUser();
278278
self::assertInstanceOf(User::class, $otherUser);
279-
self::assertInstanceOf(InternalProxy::class, $otherUser);
279+
self::assertIsLazyObject($otherUser);
280280
self::assertFalse($this->uow->isUninitializedObject($otherUser));
281281

282282
self::assertCount(1, $referenceUser->getOtherUsers());
@@ -331,7 +331,7 @@ public function testPrimeReferencesWithDiscriminatedReferenceOne(): void
331331
->field('server')->prime(true);
332332

333333
foreach ($qb->getQuery() as $agent) {
334-
self::assertInstanceOf(InternalProxy::class, $agent->server);
334+
self::assertIsLazyObject($agent->server);
335335
self::assertFalse($this->uow->isUninitializedObject($agent->server));
336336
}
337337
}
@@ -523,7 +523,7 @@ public function testPrimeEmbeddedReferenceTwoLevelsDeep(): void
523523

524524
$currency = $money->getCurrency();
525525

526-
self::assertInstanceOf(InternalProxy::class, $currency);
526+
self::assertIsLazyObject($currency);
527527
self::assertInstanceOf(Currency::class, $currency);
528528
self::assertFalse($this->uow->isUninitializedObject($currency));
529529
}
@@ -551,7 +551,7 @@ public function testPrimeReferencesInReferenceMany(): void
551551
self::assertInstanceOf(BlogPost::class, $post);
552552

553553
$comment = $post->comments->first();
554-
self::assertInstanceOf(InternalProxy::class, $comment->author);
554+
self::assertIsLazyObject($comment->author);
555555
self::assertFalse($this->uow->isUninitializedObject($comment->author));
556556
}
557557

@@ -578,7 +578,7 @@ public function testPrimeReferencesInReferenceManyWithRepositoryMethodEager(): v
578578
self::assertInstanceOf(BlogPost::class, $post);
579579

580580
$comment = $post->repoCommentsWithPrimer->first();
581-
self::assertInstanceOf(InternalProxy::class, $comment->author);
581+
self::assertIsLazyObject($comment->author);
582582
self::assertFalse($this->uow->isUninitializedObject($comment->author));
583583
}
584584
}

0 commit comments

Comments
 (0)