From 03a6b29a9f8e9c7e7d5fbc2bf2e602f5f3566039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 18 Nov 2025 20:39:38 +0100 Subject: [PATCH] Remove proxy class generators, only native lazy objects are supported Remove dependencies to proxy-manager and var-exporter --- .github/workflows/continuous-integration.yml | 3 - benchmark/BaseBench.php | 2 - composer.json | 4 +- phpunit.xml.dist | 2 - src/Configuration.php | 173 +------- src/ConfigurationException.php | 5 - src/DocumentManager.php | 77 +--- src/Event/DocumentNotFoundEventArgs.php | 4 +- src/Hydrator/HydratorFactory.php | 11 - src/Mapping/ClassMetadata.php | 21 +- src/Mapping/ClassMetadataFactoryInterface.php | 8 - .../ObjectCastPropertyAccessor.php | 72 ---- .../RawValuePropertyAccessor.php | 17 +- src/Proxy/Autoloader.php | 90 ----- src/Proxy/Factory/LazyGhostProxyFactory.php | 378 ------------------ src/Proxy/Factory/ProxyFactory.php | 1 + src/Proxy/Factory/StaticProxyFactory.php | 175 -------- src/Proxy/FileLocator.php | 25 -- src/Proxy/InternalProxy.php | 18 - .../Resolver/CachingClassNameResolver.php | 31 -- src/Proxy/Resolver/ClassNameResolver.php | 16 - .../LazyGhostProxyClassNameResolver.php | 31 -- .../ProxyManagerClassNameResolver.php | 40 -- src/Query/Builder.php | 4 +- src/Query/ReferencePrimer.php | 4 +- .../Command/GenerateProxiesCommand.php | 110 ----- .../Console/Command/Schema/CreateCommand.php | 15 - src/UnitOfWork.php | 43 +- src/Utility/LifecycleEventManager.php | 4 +- tests/Tests/BaseTestCase.php | 20 +- tests/Tests/ConfigurationTest.php | 81 ---- tests/Tests/DocumentManagerTest.php | 11 +- tests/Tests/Functional/PropertyHooksTest.php | 11 - .../Functional/ReadOnlyPropertiesTest.php | 5 - tests/Tests/Functional/Ticket/GH1990Test.php | 2 +- .../ObjectCastPropertyAccessorTest.php | 85 ---- .../Tests/Proxy/Factory/ProxyFactoryTest.php | 12 +- 37 files changed, 53 insertions(+), 1558 deletions(-) delete mode 100644 src/Mapping/PropertyAccessors/ObjectCastPropertyAccessor.php delete mode 100644 src/Proxy/Autoloader.php delete mode 100644 src/Proxy/Factory/LazyGhostProxyFactory.php delete mode 100644 src/Proxy/Factory/StaticProxyFactory.php delete mode 100644 src/Proxy/FileLocator.php delete mode 100644 src/Proxy/InternalProxy.php delete mode 100644 src/Proxy/Resolver/CachingClassNameResolver.php delete mode 100644 src/Proxy/Resolver/ClassNameResolver.php delete mode 100644 src/Proxy/Resolver/LazyGhostProxyClassNameResolver.php delete mode 100644 src/Proxy/Resolver/ProxyManagerClassNameResolver.php delete mode 100644 src/Tools/Console/Command/GenerateProxiesCommand.php delete mode 100644 tests/Tests/Mapping/PropertyAccessors/ObjectCastPropertyAccessorTest.php diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 0df1185043..0b348bd768 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -109,7 +109,6 @@ jobs: - name: "Remove optional dependencies" if: "${{ matrix.remove-optional-dependencies }}" run: | - composer remove --no-update friendsofphp/proxy-manager-lts symfony/var-exporter composer remove --no-update --dev symfony/cache doctrine/orm doctrine/annotations composer remove --no-update --dev doctrine/coding-standard phpstan/phpstan phpstan/phpstan-deprecation-rule phpstan/phpstan-phpunit @@ -136,6 +135,4 @@ jobs: run: "vendor/bin/phpunit --exclude-group=atlas ${{ matrix.dependencies == 'lowest' && '--do-not-fail-on-deprecation --do-not-fail-on-warning --do-not-fail-on-notice' || '' }}" env: DOCTRINE_MONGODB_SERVER: ${{ steps.setup-mongodb.outputs.cluster-uri }} - USE_LAZY_GHOST_OBJECT: 0 - USE_NATIVE_LAZY_OBJECT: 1 CRYPT_SHARED_LIB_PATH: ${{ steps.setup-mongodb.outputs.crypt-shared-lib-path }} diff --git a/benchmark/BaseBench.php b/benchmark/BaseBench.php index 89b1a6bc32..e5dfd2db14 100644 --- a/benchmark/BaseBench.php +++ b/benchmark/BaseBench.php @@ -35,8 +35,6 @@ public function initDocumentManager(): void { $config = new Configuration(); - $config->setProxyDir(__DIR__ . '/../../tests/Proxies'); - $config->setProxyNamespace('Proxies'); $config->setHydratorDir(__DIR__ . '/../../tests/Hydrators'); $config->setHydratorNamespace('Hydrators'); $config->setPersistentCollectionDir(__DIR__ . '/../../tests/PersistentCollections'); diff --git a/composer.json b/composer.json index 6cee2b40a1..6a15d2dd89 100644 --- a/composer.json +++ b/composer.json @@ -34,12 +34,10 @@ "doctrine/event-manager": "^1.0 || ^2.0", "doctrine/instantiator": "^1.1 || ^2", "doctrine/persistence": "^3.2 || ^4", - "friendsofphp/proxy-manager-lts": "^1.0", "mongodb/mongodb": "^2.1.1", "psr/cache": "^1.0 || ^2.0 || ^3.0", "symfony/console": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0", - "symfony/var-exporter": "^6.4 || ^7.0 || ^8.0" + "symfony/deprecation-contracts": "^2.2 || ^3.0" }, "require-dev": { "ext-bcmath": "*", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e3bc2085ba..ac81d783cc 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -33,7 +33,5 @@ - - diff --git a/src/Configuration.php b/src/Configuration.php index 63747d4b69..4ea6fab4c6 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -16,7 +16,6 @@ use Doctrine\ODM\MongoDB\PersistentCollection\DefaultPersistentCollectionGenerator; use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionFactory; use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionGenerator; -use Doctrine\ODM\MongoDB\Proxy\FileLocator; use Doctrine\ODM\MongoDB\Repository\DefaultGridFSRepository; use Doctrine\ODM\MongoDB\Repository\DefaultRepositoryFactory; use Doctrine\ODM\MongoDB\Repository\DocumentRepository; @@ -24,28 +23,19 @@ use Doctrine\ODM\MongoDB\Repository\RepositoryFactory; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\ObjectRepository; -use InvalidArgumentException; -use LogicException; use MongoDB\Client; use MongoDB\Driver\Manager; use MongoDB\Driver\WriteConcern; -use ProxyManager\Configuration as ProxyManagerConfiguration; -use ProxyManager\Factory\LazyLoadingGhostFactory; -use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy; -use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy; use Psr\Cache\CacheItemPoolInterface; use ReflectionClass; use stdClass; -use Symfony\Component\VarExporter\LazyGhostTrait; use Throwable; use function array_diff_key; use function array_intersect_key; use function array_key_exists; -use function class_exists; use function interface_exists; use function is_string; -use function trait_exists; use function trigger_deprecation; use function trim; @@ -65,42 +55,39 @@ class Configuration { /** - * Never autogenerate a proxy/hydrator/persistent collection and rely that - * it was generated by some process before deployment. Copied from - * \Doctrine\Common\Proxy\AbstractProxyFactory. + * Never autogenerate a hydrator/persistent collection and rely that + * it was generated by some process before deployment. */ public const AUTOGENERATE_NEVER = 0; /** - * Always generates a new proxy/hydrator/persistent collection in every request. + * Always generates a new hydrator/persistent collection in every request. * * This is only sane during development. - * Copied from \Doctrine\Common\Proxy\AbstractProxyFactory. */ public const AUTOGENERATE_ALWAYS = 1; /** - * Autogenerate the proxy/hydrator/persistent collection class when the file does not exist. + * Autogenerate the hydrator/persistent collection class when the file does not exist. * - * This strategy causes a file exists call whenever any proxy/hydrator is used the - * first time in a request. Copied from \Doctrine\Common\Proxy\AbstractProxyFactory. + * This strategy causes a file exists call whenever any hydrator is used the + * first time in a request. */ public const AUTOGENERATE_FILE_NOT_EXISTS = 2; /** - * Generate the proxy/hydrator/persistent collection classes using eval(). + * Generate the hydrator/persistent collection classes using eval(). * * This strategy is only sane for development. - * Copied from \Doctrine\Common\Proxy\AbstractProxyFactory. */ public const AUTOGENERATE_EVAL = 3; /** - * Autogenerate the proxy class when the proxy file does not exist or + * Autogenerate the class when the file does not exist or * when the proxied file changed. * - * This strategy causes a file_exists() call whenever any proxy is used the - * first time in a request. When the proxied file is changed, the proxy will + * This strategy causes a file_exists() call whenever any class is used the + * first time in a request. When the proxied file is changed, the class will * be updated. */ public const AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED = 4; @@ -111,7 +98,6 @@ class Configuration * @phpstan-var array{ * autoGenerateHydratorClasses?: self::AUTOGENERATE_*, * autoGeneratePersistentCollectionClasses?: self::AUTOGENERATE_*, - * autoGenerateProxyClasses?: self::AUTOGENERATE_*, * classMetadataFactoryName?: class-string, * defaultCommitOptions?: CommitOptions, * defaultDocumentRepositoryClassName?: class-string>, @@ -130,8 +116,6 @@ class Configuration * persistentCollectionGenerator?: PersistentCollectionGenerator, * persistentCollectionDir?: string, * persistentCollectionNamespace?: string, - * proxyDir?: string, - * proxyNamespace?: string, * repositoryFactory?: RepositoryFactory, * kmsProvider?: KmsProvider, * defaultMasterKey?: array|null, @@ -142,14 +126,8 @@ class Configuration private ?CacheItemPoolInterface $metadataCache = null; - /** @deprecated */ - private ProxyManagerConfiguration $proxyManagerConfiguration; - private bool $useTransactionalFlush = false; - private bool $lazyGhostObject = false; - private bool $nativeLazyObject = false; - private static string $version; /** @@ -312,57 +290,6 @@ public function setMetadataCache(CacheItemPoolInterface $cache): void $this->attributes['metadataCacheImpl'] = DoctrineProvider::wrap($cache); } - /** - * Sets the directory where Doctrine generates any necessary proxy class files. - */ - public function setProxyDir(string $dir): void - { - $this->attributes['proxyDir'] = $dir; - unset($this->proxyManagerConfiguration); - } - - /** - * Gets the directory where Doctrine generates any necessary proxy class files. - */ - public function getProxyDir(): ?string - { - return $this->attributes['proxyDir'] ?? null; - } - - /** - * Gets an int flag that indicates whether proxy classes should always be regenerated - * during each script execution. - * - * @return self::AUTOGENERATE_* - */ - public function getAutoGenerateProxyClasses(): int - { - return $this->attributes['autoGenerateProxyClasses'] ?? self::AUTOGENERATE_FILE_NOT_EXISTS; - } - - /** - * Sets an int flag that indicates whether proxy classes should always be regenerated - * during each script execution. - * - * @param self::AUTOGENERATE_* $mode - */ - public function setAutoGenerateProxyClasses(int $mode): void - { - $this->attributes['autoGenerateProxyClasses'] = $mode; - unset($this->proxyManagerConfiguration); - } - - public function getProxyNamespace(): ?string - { - return $this->attributes['proxyNamespace'] ?? null; - } - - public function setProxyNamespace(string $ns): void - { - $this->attributes['proxyNamespace'] = $ns; - unset($this->proxyManagerConfiguration); - } - public function setHydratorDir(string $dir): void { $this->attributes['hydratorDir'] = $dir; @@ -640,41 +567,6 @@ public function getPersistentCollectionGenerator(): PersistentCollectionGenerato return $this->attributes['persistentCollectionGenerator']; } - /** @deprecated */ - public function buildGhostObjectFactory(): LazyLoadingGhostFactory - { - return new LazyLoadingGhostFactory($this->getProxyManagerConfiguration()); - } - - /** @deprecated */ - public function getProxyManagerConfiguration(): ProxyManagerConfiguration - { - if (isset($this->proxyManagerConfiguration)) { - return $this->proxyManagerConfiguration; - } - - $proxyManagerConfiguration = new ProxyManagerConfiguration(); - $proxyManagerConfiguration->setProxiesTargetDir($this->getProxyDir()); - $proxyManagerConfiguration->setProxiesNamespace($this->getProxyNamespace()); - - switch ($this->getAutoGenerateProxyClasses()) { - case self::AUTOGENERATE_FILE_NOT_EXISTS: - $proxyManagerConfiguration->setGeneratorStrategy(new FileWriterGeneratorStrategy( - new FileLocator($proxyManagerConfiguration->getProxiesTargetDir()), - )); - - break; - case self::AUTOGENERATE_EVAL: - $proxyManagerConfiguration->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); - - break; - default: - throw new InvalidArgumentException('Invalid proxy generation strategy given - only AUTOGENERATE_FILE_NOT_EXISTS and AUTOGENERATE_EVAL are supported.'); - } - - return $this->proxyManagerConfiguration = $proxyManagerConfiguration; - } - public function setUseTransactionalFlush(bool $useTransactionalFlush): void { $this->useTransactionalFlush = $useTransactionalFlush; @@ -685,51 +577,6 @@ public function isTransactionalFlushEnabled(): bool return $this->useTransactionalFlush; } - /** - * Generate proxy classes using Symfony VarExporter's LazyGhostTrait if true. - * Otherwise, use ProxyManager's LazyLoadingGhostFactory (deprecated) - */ - public function setUseLazyGhostObject(bool $flag): void - { - if ($this->nativeLazyObject) { - throw new LogicException('Cannot enable or disable LazyGhostObject when native lazy objects are enabled.'); - } - - if ($flag && ! trait_exists(LazyGhostTrait::class)) { - throw new LogicException('Package "symfony/var-exporter" >= 8.0 does not provide lazy ghost objects, use native lazy objects instead.'); - } - - if (! $flag) { - if (! class_exists(ProxyManagerConfiguration::class)) { - throw new LogicException('Package "friendsofphp/proxy-manager-lts" is required to disable LazyGhostObject.'); - } - - trigger_deprecation('doctrine/mongodb-odm', '2.10', 'Using "friendsofphp/proxy-manager-lts" is deprecated. Use "symfony/var-exporter" LazyGhostObjects instead.'); - } - - $this->lazyGhostObject = $flag; - } - - public function isLazyGhostObjectEnabled(): bool - { - // Always false if native lazy objects are enabled - return $this->lazyGhostObject && ! $this->nativeLazyObject; - } - - public function setUseNativeLazyObject(bool $nativeLazyObject): void - { - $this->nativeLazyObject = $nativeLazyObject; - } - - public function isNativeLazyObjectEnabled(): bool - { - if (! $this->nativeLazyObject) { - trigger_deprecation('doctrine/mongodb-odm', '2.14', 'Not using native lazy objects is deprecated and will be impossible in Doctrine MongoDB ODM 3.0.'); - } - - return $this->nativeLazyObject; - } - /** * Set the KMS provider to use for auto-encryption. The name of the KMS provider * must be specified in the 'type' key of the array. diff --git a/src/ConfigurationException.php b/src/ConfigurationException.php index 21ff646573..6933976a6a 100644 --- a/src/ConfigurationException.php +++ b/src/ConfigurationException.php @@ -25,11 +25,6 @@ public static function noMetadataDriverConfigured(): self return new self('No metadata driver was configured. Please set a metadata driver implementation in your configuration.'); } - public static function proxyDirMissing(): self - { - return new self('No proxy directory was configured. Please set a target directory first!'); - } - public static function clientEncryptionOptionsNotSet(): self { return new self('MongoDB client encryption options are not set in configuration'); diff --git a/src/DocumentManager.php b/src/DocumentManager.php index 62085a936b..42d93595ef 100644 --- a/src/DocumentManager.php +++ b/src/DocumentManager.php @@ -9,20 +9,12 @@ use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactoryInterface; use Doctrine\ODM\MongoDB\Mapping\MappingException; -use Doctrine\ODM\MongoDB\Proxy\Factory\LazyGhostProxyFactory; use Doctrine\ODM\MongoDB\Proxy\Factory\NativeLazyObjectFactory; -use Doctrine\ODM\MongoDB\Proxy\Factory\ProxyFactory; -use Doctrine\ODM\MongoDB\Proxy\Factory\StaticProxyFactory; -use Doctrine\ODM\MongoDB\Proxy\Resolver\CachingClassNameResolver; -use Doctrine\ODM\MongoDB\Proxy\Resolver\ClassNameResolver; -use Doctrine\ODM\MongoDB\Proxy\Resolver\LazyGhostProxyClassNameResolver; -use Doctrine\ODM\MongoDB\Proxy\Resolver\ProxyManagerClassNameResolver; use Doctrine\ODM\MongoDB\Query\FilterCollection; use Doctrine\ODM\MongoDB\Repository\DocumentRepository; use Doctrine\ODM\MongoDB\Repository\GridFSRepository; use Doctrine\ODM\MongoDB\Repository\RepositoryFactory; use Doctrine\ODM\MongoDB\Repository\ViewRepository; -use Doctrine\Persistence\Mapping\ProxyClassNameResolver; use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectRepository; use InvalidArgumentException; @@ -41,7 +33,6 @@ use function is_object; use function ltrim; use function sprintf; -use function trigger_deprecation; /** * The DocumentManager class is the central access point for managing the @@ -92,9 +83,9 @@ class DocumentManager implements ObjectManager private HydratorFactory $hydratorFactory; /** - * The Proxy factory instance. + * The Lazy object factory instance. */ - private ProxyFactory $proxyFactory; + private NativeLazyObjectFactory $lazyObjectFactory; /** * The repository factory used to create dynamic repositories. @@ -137,9 +128,6 @@ class DocumentManager implements ObjectManager */ private ?FilterCollection $filterCollection = null; - /** @var ProxyClassNameResolver&ClassNameResolver */ - private ProxyClassNameResolver $classNameResolver; - /** * Creates a new Document that operates on the given Mongo connection * and uses the given Configuration. @@ -154,31 +142,10 @@ protected function __construct(?Client $client = null, ?Configuration $config = $this->config->getDriverOptions(), ); - if ($this->config->isNativeLazyObjectEnabled()) { - $this->classNameResolver = new class implements ClassNameResolver, ProxyClassNameResolver { - public function getRealClass(string $class): string - { - return $class; - } - - public function resolveClassName(string $className): string - { - return $className; - } - }; - } elseif ($this->config->isLazyGhostObjectEnabled()) { - $this->classNameResolver = new CachingClassNameResolver(new LazyGhostProxyClassNameResolver()); - } else { - $this->classNameResolver = new CachingClassNameResolver(new ProxyManagerClassNameResolver($this->config)); - } - $metadataFactoryClassName = $this->config->getClassMetadataFactoryName(); $this->metadataFactory = new $metadataFactoryClassName(); $this->metadataFactory->setDocumentManager($this); $this->metadataFactory->setConfiguration($this->config); - if (! $this->config->isNativeLazyObjectEnabled()) { - $this->metadataFactory->setProxyClassNameResolver($this->classNameResolver); - } $cacheDriver = $this->config->getMetadataCache(); if ($cacheDriver) { @@ -195,22 +162,20 @@ public function resolveClassName(string $className): string $this->config->getAutoGenerateHydratorClasses(), ); - $this->unitOfWork = new UnitOfWork($this, $this->eventManager, $this->hydratorFactory); - $this->schemaManager = new SchemaManager($this, $this->metadataFactory); - $this->proxyFactory = match (true) { - $this->config->isNativeLazyObjectEnabled() => new NativeLazyObjectFactory($this), - $this->config->isLazyGhostObjectEnabled() => new LazyGhostProxyFactory($this, $this->config->getProxyDir(), $this->config->getProxyNamespace(), $this->config->getAutoGenerateProxyClasses()), - default => new StaticProxyFactory($this), - }; + $this->unitOfWork = new UnitOfWork($this, $this->eventManager, $this->hydratorFactory); + $this->schemaManager = new SchemaManager($this, $this->metadataFactory); + $this->lazyObjectFactory = new NativeLazyObjectFactory($this); $this->repositoryFactory = $this->config->getRepositoryFactory(); } /** - * Gets the proxy factory used by the DocumentManager to create document proxies. + * Gets the lazy object factory used by the DocumentManager to create document proxies. + * + * @internal */ - public function getProxyFactory(): ProxyFactory + public function getLazyObjectFactory(): NativeLazyObjectFactory { - return $this->proxyFactory; + return $this->lazyObjectFactory; } /** @@ -261,7 +226,7 @@ public function getMetadataFactory(): ClassmetadataFactoryInterface } /** - * Helper method to initialize a lazy loading proxy or persistent collection. + * Helper method to initialize a lazy object or persistent collection. * * This method is a no-op for other objects. * @@ -273,7 +238,7 @@ public function initializeObject($obj): void } /** - * Helper method to check whether a lazy loading proxy or persistent collection has been initialized. + * Helper method to check whether a lazy object or persistent collection has been initialized. */ public function isUninitializedObject(mixed $obj): bool { @@ -309,20 +274,6 @@ public function getSchemaManager(): SchemaManager return $this->schemaManager; } - /** - * Returns the class name resolver which is used to resolve real class names for proxy objects. - * - * @deprecated Since 2.15, the use of proxy classes is deprecated and will be removed in Doctrine ODM 3.0. - */ - public function getClassNameResolver(): ClassNameResolver - { - if ($this->getConfiguration()->isNativeLazyObjectEnabled()) { - trigger_deprecation('doctrine/mongodb-odm', '2.15', 'The %s() method is deprecated and will be removed in Doctrine ODM 3.0. There are no proxy classes when using native lazy objects', __METHOD__); - } - - return $this->classNameResolver; - } - /** * Returns the metadata for a class. * @@ -623,7 +574,7 @@ public function flush(array $options = []): void * without actually loading it. * * If partial objects are allowed, this method will return a partial object that only - * has its identifier populated. Otherwise a proxy is returned that automatically + * has its identifier populated. Otherwise a lazy object is returned that automatically * loads itself on first access. * * @param mixed $identifier @@ -646,7 +597,7 @@ public function getReference(string $documentName, $identifier): object return $document; } - $document = $this->proxyFactory->getProxy($class, $identifier); + $document = $this->lazyObjectFactory->getProxy($class, $identifier); $this->unitOfWork->registerManaged($document, $identifier, [$class->identifier => $identifier]); return $document; diff --git a/src/Event/DocumentNotFoundEventArgs.php b/src/Event/DocumentNotFoundEventArgs.php index 3a31a1ffbb..bc569b3f3e 100644 --- a/src/Event/DocumentNotFoundEventArgs.php +++ b/src/Event/DocumentNotFoundEventArgs.php @@ -29,7 +29,7 @@ public function getIdentifier() } /** - * Indicates whether the proxy initialization exception is disabled. + * Indicates whether the lazy object initialization exception is disabled. */ public function isExceptionDisabled(): bool { @@ -39,7 +39,7 @@ public function isExceptionDisabled(): bool /** * Disable the throwing of an exception * - * This method indicates to the proxy initializer that the missing document + * This method indicates to the lazy object initializer that the missing document * has been handled and no exception should be thrown. This can't be reset. */ public function disableException(bool $disableException = true): void diff --git a/src/Hydrator/HydratorFactory.php b/src/Hydrator/HydratorFactory.php index 5172bc94a5..0fab156f2e 100644 --- a/src/Hydrator/HydratorFactory.php +++ b/src/Hydrator/HydratorFactory.php @@ -11,10 +11,8 @@ use Doctrine\ODM\MongoDB\Event\PreLoadEventArgs; use Doctrine\ODM\MongoDB\Events; use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; -use Doctrine\ODM\MongoDB\Proxy\InternalProxy; use Doctrine\ODM\MongoDB\Types\Type; use Doctrine\ODM\MongoDB\UnitOfWork; -use ProxyManager\Proxy\GhostObjectInterface; use function array_key_exists; use function chmod; @@ -452,15 +450,6 @@ public function hydrate(object $document, array $data, array $hints = []): array $metadata->reflClass->markLazyObjectAsInitialized($document); - if ($document instanceof InternalProxy) { - $document->__setInitialized(true); - } - - // Support for legacy proxy-manager-lts - if ($document instanceof GhostObjectInterface) { - $document->setProxyInitializer(null); - } - $data = $this->getHydratorFor($metadata->name)->hydrate($document, $data, $hints); // Invoke the postLoad lifecycle callbacks and listeners diff --git a/src/Mapping/ClassMetadata.php b/src/Mapping/ClassMetadata.php index 963b8be01a..bfe7988024 100644 --- a/src/Mapping/ClassMetadata.php +++ b/src/Mapping/ClassMetadata.php @@ -18,7 +18,6 @@ use Doctrine\ODM\MongoDB\Mapping\PropertyAccessors\EnumPropertyAccessor; use Doctrine\ODM\MongoDB\Mapping\PropertyAccessors\PropertyAccessor; use Doctrine\ODM\MongoDB\Mapping\PropertyAccessors\PropertyAccessorFactory; -use Doctrine\ODM\MongoDB\Proxy\InternalProxy; use Doctrine\ODM\MongoDB\Types\Incrementable; use Doctrine\ODM\MongoDB\Types\Type; use Doctrine\ODM\MongoDB\Types\Versionable; @@ -31,7 +30,6 @@ use MongoDB\BSON\Decimal128; use MongoDB\BSON\Int64; use MongoDB\BSON\UTCDateTime; -use ProxyManager\Proxy\GhostObjectInterface; use ReflectionClass; use ReflectionEnum; use ReflectionNamedType; @@ -1012,8 +1010,7 @@ public function setCustomRepositoryClass(?string $repositoryClassName): void * * @param mixed[]|null $arguments * - * @throws InvalidArgumentException If document class is not this class or - * a Proxy of this class. + * @throws InvalidArgumentException If the document class is not this class. */ public function invokeLifecycleCallbacks(string $event, object $document, ?array $arguments = null): void { @@ -1977,15 +1974,7 @@ public function getIdentifierObject(object $document) */ public function setFieldValue(object $document, string $field, $value): void { - if ($document instanceof InternalProxy && ! $document->__isInitialized()) { - //property changes to an uninitialized proxy will not be tracked or persisted, - //so the proxy needs to be loaded first. - $document->__load(); - } elseif ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) { - $document->initializeProxy(); - } else { - $this->reflClass->initializeLazyObject($document); - } + $this->reflClass->initializeLazyObject($document); $this->propertyAccessors[$field]->setValue($document, $value); } @@ -1997,11 +1986,7 @@ public function setFieldValue(object $document, string $field, $value): void */ public function getFieldValue(object $document, string $field) { - if ($document instanceof InternalProxy && $field !== $this->identifier && ! $document->__isInitialized()) { - $document->__load(); - } elseif ($document instanceof GhostObjectInterface && $field !== $this->identifier && ! $document->isProxyInitialized()) { - $document->initializeProxy(); - } elseif ($field !== $this->identifier && $this->reflClass->isUninitializedLazyObject($document)) { + if ($field !== $this->identifier && $this->reflClass->isUninitializedLazyObject($document)) { $this->reflClass->initializeLazyObject($document); } diff --git a/src/Mapping/ClassMetadataFactoryInterface.php b/src/Mapping/ClassMetadataFactoryInterface.php index bacd47ec3d..5ad9216c53 100644 --- a/src/Mapping/ClassMetadataFactoryInterface.php +++ b/src/Mapping/ClassMetadataFactoryInterface.php @@ -7,7 +7,6 @@ use Doctrine\ODM\MongoDB\Configuration; use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\Persistence\Mapping\ClassMetadataFactory; -use Doctrine\Persistence\Mapping\ProxyClassNameResolver; use Psr\Cache\CacheItemPoolInterface; /** @@ -32,11 +31,4 @@ public function setConfiguration(Configuration $config): void; * Sets the document manager owning the factory. */ public function setDocumentManager(DocumentManager $dm): void; - - /** - * Sets a resolver for real class names of a proxy. - * - * @deprecated This method is deprecated and will be removed in Doctrine ODM 3.0. - */ - public function setProxyClassNameResolver(ProxyClassNameResolver $resolver): void; } diff --git a/src/Mapping/PropertyAccessors/ObjectCastPropertyAccessor.php b/src/Mapping/PropertyAccessors/ObjectCastPropertyAccessor.php deleted file mode 100644 index 34ac25cd26..0000000000 --- a/src/Mapping/PropertyAccessors/ObjectCastPropertyAccessor.php +++ /dev/null @@ -1,72 +0,0 @@ -isPrivate() => "\0" . ltrim($class, '\\') . "\0" . $name, - $reflectionProperty->isProtected() => "\0*\0" . $name, - default => $name, - }; - - return new self($reflectionProperty, $key); - } - - public static function fromReflectionProperty(ReflectionProperty $reflectionProperty): self - { - $name = $reflectionProperty->getName(); - - $key = match (true) { - $reflectionProperty->isPrivate() => "\0" . ltrim($reflectionProperty->getDeclaringClass()->getName(), '\\') . "\0" . $name, - $reflectionProperty->isProtected() => "\0*\0" . $name, - default => $name, - }; - - return new self($reflectionProperty, $key); - } - - private function __construct(private ReflectionProperty $reflectionProperty, private string $key) - { - } - - public function setValue(object $object, mixed $value): void - { - if ($object instanceof InternalProxy && ! $object->__isInitialized()) { - $object->__setInitialized(true); - $this->reflectionProperty->setValue($object, $value); - $object->__setInitialized(false); - } elseif ($object instanceof GhostObjectInterface && ! $object->isProxyInitialized()) { - $initializer = $object->getProxyInitializer(); - $object->setProxyInitializer(null); - $this->reflectionProperty->setValue($object, $value); - $object->setProxyInitializer($initializer); - } else { - $this->reflectionProperty->setValue($object, $value); - } - } - - public function getValue(object $object): mixed - { - return ((array) $object)[$this->key] ?? null; - } - - public function getUnderlyingReflector(): ReflectionProperty - { - return $this->reflectionProperty; - } -} diff --git a/src/Mapping/PropertyAccessors/RawValuePropertyAccessor.php b/src/Mapping/PropertyAccessors/RawValuePropertyAccessor.php index eb7d6f0927..f873e793ca 100644 --- a/src/Mapping/PropertyAccessors/RawValuePropertyAccessor.php +++ b/src/Mapping/PropertyAccessors/RawValuePropertyAccessor.php @@ -4,15 +4,11 @@ namespace Doctrine\ODM\MongoDB\Mapping\PropertyAccessors; -use Doctrine\ODM\MongoDB\Proxy\InternalProxy; -use ProxyManager\Proxy\GhostObjectInterface; use ReflectionProperty; use function ltrim; /** - * This is a PHP 8.4 and up only class and replaces {@see ObjectCastPropertyAccessor}. - * * It works based on the raw values of a property, which for a case of property hooks * is the backed value. If we kept using setValue/getValue, this would go through the hooks, * which potentially change the data. @@ -40,18 +36,7 @@ private function __construct(private ReflectionProperty $reflectionProperty, pri public function setValue(object $object, mixed $value): void { - if ($object instanceof InternalProxy && ! $object->__isInitialized()) { - $object->__setInitialized(true); - $this->reflectionProperty->setRawValue($object, $value); - $object->__setInitialized(false); - } elseif ($object instanceof GhostObjectInterface && ! $object->isProxyInitialized()) { - $initializer = $object->getProxyInitializer(); - $object->setProxyInitializer(null); - $this->reflectionProperty->setRawValue($object, $value); - $object->setProxyInitializer($initializer); - } else { - $this->reflectionProperty->setRawValueWithoutLazyInitialization($object, $value); - } + $this->reflectionProperty->setRawValueWithoutLazyInitialization($object, $value); } public function getValue(object $object): mixed diff --git a/src/Proxy/Autoloader.php b/src/Proxy/Autoloader.php deleted file mode 100644 index d346a0c194..0000000000 --- a/src/Proxy/Autoloader.php +++ /dev/null @@ -1,90 +0,0 @@ -; - -/** - * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR - */ -class extends \ implements \ -{ - - - public function __isInitialized(): bool - { - return isset($this->lazyObjectState) && $this->isLazyObjectInitialized(); - } - - public function __serialize(): array - { - - } -} - -EOPHP; - - /** The UnitOfWork this factory uses to retrieve persisters */ - private readonly UnitOfWork $uow; - - /** @var Configuration::AUTOGENERATE_* */ - private int $autoGenerate; - - /** @var array */ - private array $proxyFactories = []; - - private LifecycleEventManager $lifecycleEventManager; - - /** - * Initializes a new instance of the ProxyFactory class that is - * connected to the given EntityManager. - * - * @param DocumentManager $dm The EntityManager the new factory works for. - * @param string $proxyDir The directory to use for the proxy classes. It must exist. - * @param string $proxyNs The namespace to use for the proxy classes. - * @param bool|Configuration::AUTOGENERATE_* $autoGenerate The strategy for automatically generating proxy classes. - */ - public function __construct( - private readonly DocumentManager $dm, - private readonly string $proxyDir, - private readonly string $proxyNs, - bool|int $autoGenerate = Configuration::AUTOGENERATE_NEVER, - ) { - if (! $proxyDir) { - throw new InvalidArgumentException('You must configure a proxy directory. See docs for details'); - } - - if (! $proxyNs) { - throw new InvalidArgumentException('You must configure a proxy namespace'); - } - - if (is_int($autoGenerate) && ($autoGenerate < 0 || $autoGenerate > 4)) { - throw new InvalidArgumentException(sprintf('Invalid auto generate mode "%d" given.', $autoGenerate)); - } - - $this->uow = $dm->getUnitOfWork(); - $this->autoGenerate = (int) $autoGenerate; - $this->lifecycleEventManager = new LifecycleEventManager($dm, $this->uow, $dm->getEventManager()); - } - - /** @param mixed $identifier */ - public function getProxy(ClassMetadata $metadata, $identifier): InternalProxy - { - $className = $metadata->getName(); - - $proxyFactory = $this->proxyFactories[$className] ?? $this->getProxyFactory($className); - - return $proxyFactory($identifier); - } - - /** - * Generates proxy classes for all given classes. - * - * @param ClassMetadata[] $classes The classes (ClassMetadata instances) for which to generate proxies. - * @param string|null $proxyDir The target directory of the proxy classes. If not specified, the - * directory configured on the Configuration of the EntityManager used - * by this factory is used. - * - * @return int Number of generated proxies. - */ - public function generateProxyClasses(array $classes, string|null $proxyDir = null): int - { - $generated = 0; - - foreach ($classes as $class) { - if ($this->skipClass($class)) { - continue; - } - - $proxyFileName = $this->getProxyFileName($class->getName(), $proxyDir ?: $this->proxyDir); - $proxyClassName = self::generateProxyClassName($class->getName(), $this->proxyNs); - - $this->generateProxyClass($class, $proxyFileName, $proxyClassName); - - ++$generated; - } - - return $generated; - } - - protected function skipClass(ClassMetadata $metadata): bool - { - return $metadata->isMappedSuperclass - || $metadata->isEmbeddedDocument - || $metadata->getReflectionClass()->isAbstract(); - } - - /** - * Creates a closure capable of initializing a proxy - * - * @param ClassMetadata $classMetadata - * - * @return Closure(InternalProxy&T, array):void - * - * @throws DocumentNotFoundException - * - * @template T of object - */ - private function createLazyInitializer(ClassMetadata $classMetadata, DocumentPersister $persister): Closure - { - $factory = $this; - - return static function (InternalProxy $proxy, mixed $identifier) use ($persister, $classMetadata, $factory): void { - $original = $persister->load([$classMetadata->identifier => $identifier], $proxy); - - if (! $original && ! $factory->lifecycleEventManager->documentNotFound($proxy, $identifier)) { - throw DocumentNotFoundException::documentNotFound($classMetadata->getName(), $identifier); - } - - // phpcs:ignore SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed - if ($proxy instanceof NotifyPropertyChanged) { - $proxy->addPropertyChangedListener($factory->uow); - } - }; - } - - private function getProxyFileName(string $className, string $baseDirectory): string - { - $baseDirectory = $baseDirectory ?: $this->proxyDir; - - return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . InternalProxy::MARKER - . str_replace('\\', '', $className) . '.php'; - } - - /** @param class-string $className */ - private function getProxyFactory(string $className): Closure - { - $skippedProperties = []; - $class = $this->dm->getClassMetadata($className); - $filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE; - $reflector = $class->getReflectionClass(); - - while ($reflector) { - foreach ($reflector->getProperties($filter) as $property) { - $name = $property->name; - - if ($property->isStatic() || (($class->hasField($name) || $class->hasAssociation($name)))) { - continue; - } - - $prefix = $property->isPrivate() ? "\0" . $property->class . "\0" : ($property->isProtected() ? "\0*\0" : ''); - - $skippedProperties[$prefix . $name] = true; - } - - $filter = ReflectionProperty::IS_PRIVATE; - $reflector = $reflector->getParentClass(); - } - - $className = $class->getName(); // aliases and case sensitivity - $entityPersister = $this->uow->getDocumentPersister($className); - $initializer = $this->createLazyInitializer($class, $entityPersister); - $proxyClassName = $this->loadProxyClass($class); - - $proxyFactory = Closure::bind(static function (mixed $identifier) use ($initializer, $skippedProperties, $class): InternalProxy { - /** @see LazyGhostTrait::createLazyGhost() */ - $proxy = static::createLazyGhost(static function (InternalProxy $object) use ($initializer, $identifier): void { - $initializer($object, $identifier); - }, $skippedProperties); - - $class->setIdentifierValue($proxy, $identifier); - - return $proxy; - }, null, $proxyClassName); - - return $this->proxyFactories[$className] = $proxyFactory; - } - - private function loadProxyClass(ClassMetadata $class): string - { - $proxyClassName = self::generateProxyClassName($class->getName(), $this->proxyNs); - - if (class_exists($proxyClassName, false)) { - return $proxyClassName; - } - - if ($this->autoGenerate === Configuration::AUTOGENERATE_EVAL) { - $this->generateProxyClass($class, null, $proxyClassName); - - return $proxyClassName; - } - - $fileName = $this->getProxyFileName($class->getName(), $this->proxyDir); - - if ( - match ($this->autoGenerate) { - Configuration::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED => ! file_exists($fileName) || filemtime($fileName) < filemtime($class->getReflectionClass()->getFileName()), - Configuration::AUTOGENERATE_FILE_NOT_EXISTS => ! file_exists($fileName), - Configuration::AUTOGENERATE_ALWAYS => true, - Configuration::AUTOGENERATE_NEVER => false, - } - ) { - $this->generateProxyClass($class, $fileName, $proxyClassName); - } - - require $fileName; - - return $proxyClassName; - } - - private function generateProxyClass(ClassMetadata $class, string|null $fileName, string $proxyClassName): void - { - $i = strrpos($proxyClassName, '\\'); - $placeholders = [ - '' => $class->getName(), - '' => substr($proxyClassName, 0, $i), - '' => substr($proxyClassName, 1 + $i), - '' => InternalProxy::class, - ]; - - preg_match_all('(<([a-zA-Z]+)>)', self::PROXY_CLASS_TEMPLATE, $placeholderMatches); - - foreach (array_combine($placeholderMatches[0], $placeholderMatches[1]) as $placeholder => $name) { - $placeholders[$placeholder] ?? $placeholders[$placeholder] = $this->{'generate' . ucfirst($name)}($class); - } - - $proxyCode = strtr(self::PROXY_CLASS_TEMPLATE, $placeholders); - - if (! $fileName) { - if (! class_exists($proxyClassName)) { - eval(substr($proxyCode, 5)); - } - - return; - } - - $parentDirectory = dirname($fileName); - - if (! is_dir($parentDirectory) && ! @mkdir($parentDirectory, 0775, true) || ! is_writable($parentDirectory)) { - throw new InvalidArgumentException(sprintf('Your proxy directory "%s" must be writable', $this->proxyDir)); - } - - $tmpFileName = $fileName . '.' . bin2hex(random_bytes(12)); - - file_put_contents($tmpFileName, $proxyCode); - @chmod($tmpFileName, 0664); - rename($tmpFileName, $fileName); - } - - private function generateUseLazyGhostTrait(ClassMetadata $class): string - { - $code = ProxyHelper::generateLazyGhost($class->getReflectionClass()); - $code = substr($code, 7 + (int) strpos($code, "\n{")); - $code = substr($code, 0, (int) strpos($code, "\n}")); - $code = str_replace('LazyGhostTrait;', str_replace("\n ", "\n", 'LazyGhostTrait { - initializeLazyObject as private; - setLazyObjectAsInitialized as public __setInitialized; - isLazyObjectInitialized as private; - createLazyGhost as private; - resetLazyObject as private; - } - - public function __load(): void - { - $this->initializeLazyObject(); - } - '), $code); - - return $code; - } - - private function generateSerializeImpl(ClassMetadata $class): string - { - $reflector = $class->getReflectionClass(); - $properties = $reflector->hasMethod('__serialize') ? 'parent::__serialize()' : '(array) $this'; - - $code = '$properties = ' . $properties . '; - unset($properties["\0" . self::class . "\0lazyObjectState"]); - - '; - - if ($reflector->hasMethod('__serialize') || ! $reflector->hasMethod('__sleep')) { - return $code . 'return $properties;'; - } - - return $code . '$data = []; - - foreach (parent::__sleep() as $name) { - $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0' . $reflector->name . '\0$name"] ?? $k = null; - - if (null === $k) { - trigger_error(sprintf(\'serialize(): "%s" returned as member variable from __sleep() but does not exist\', $name), \E_USER_NOTICE); - } else { - $data[$k] = $value; - } - } - - return $data;'; - } - - private static function generateProxyClassName(string $className, string $proxyNamespace): string - { - return rtrim($proxyNamespace, '\\') . '\\' . Proxy::MARKER . '\\' . ltrim($className, '\\'); - } -} diff --git a/src/Proxy/Factory/ProxyFactory.php b/src/Proxy/Factory/ProxyFactory.php index 4a8d93aeeb..2a3f5250c0 100644 --- a/src/Proxy/Factory/ProxyFactory.php +++ b/src/Proxy/Factory/ProxyFactory.php @@ -6,6 +6,7 @@ use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; +/** @internal */ interface ProxyFactory { /** @param ClassMetadata[] $classes */ diff --git a/src/Proxy/Factory/StaticProxyFactory.php b/src/Proxy/Factory/StaticProxyFactory.php deleted file mode 100644 index fdf7b47963..0000000000 --- a/src/Proxy/Factory/StaticProxyFactory.php +++ /dev/null @@ -1,175 +0,0 @@ -uow = $documentManager->getUnitOfWork(); - $this->lifecycleEventManager = new LifecycleEventManager($documentManager, $this->uow, $documentManager->getEventManager()); - $this->proxyFactory = $documentManager->getConfiguration()->buildGhostObjectFactory(); - } - - /** - * @param mixed $identifier - * @phpstan-param ClassMetadata $metadata - * - * @return T&GhostObjectInterface - * - * @template T of object - */ - public function getProxy(ClassMetadata $metadata, $identifier): GhostObjectInterface - { - $documentPersister = $this->uow->getDocumentPersister($metadata->getName()); - - $ghostObject = $this - ->proxyFactory - ->createProxy( - $metadata->getName(), - $this->createInitializer($metadata, $documentPersister), - [ - 'skippedProperties' => $this->skippedFieldsFqns($metadata), - ], - ); - - $metadata->setIdentifierValue($ghostObject, $identifier); - - return $ghostObject; - } - - public function generateProxyClasses(array $classes): int - { - $concreteClasses = array_filter($classes, static fn (ClassMetadata $metadata): bool => ! ($metadata->isMappedSuperclass || $metadata->isQueryResultDocument || $metadata->getReflectionClass()->isAbstract())); - - foreach ($concreteClasses as $metadata) { - $this - ->proxyFactory - ->createProxy( - $metadata->getName(), - static fn (): bool => true, // empty closure, serves its purpose, for now - [ - 'skippedProperties' => $this->skippedFieldsFqns($metadata), - ], - ); - } - - return count($concreteClasses); - } - - /** - * @param ClassMetadata $metadata - * @param DocumentPersister $documentPersister - * - * @phpstan-return Closure( - * TDocument&GhostObjectInterface=, - * string=, - * array=, - * ?Closure=, - * array= - * ) : bool - * - * @template TDocument of object - */ - private function createInitializer( - ClassMetadata $metadata, - DocumentPersister $documentPersister, - ): Closure { - return function ( - GhostObjectInterface $ghostObject, - string $method, // we don't care - array $parameters, // we don't care - &$initializer, - array $properties, // we currently do not use this - ) use ( - $metadata, - $documentPersister, - ): bool { - $originalInitializer = $initializer; - $initializer = null; - $identifier = $metadata->getIdentifierValue($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)) { - throw DocumentNotFoundException::documentNotFound($metadata->getName(), $identifier); - } - } - - if ($ghostObject instanceof NotifyPropertyChanged) { - $ghostObject->addPropertyChangedListener($this->uow); - } - - return true; - }; - } - - /** @return array */ - private function skippedFieldsFqns(ClassMetadata $metadata): array - { - $skippedFieldsFqns = []; - - foreach ($metadata->getIdentifierFieldNames() as $idField) { - $skippedFieldsFqns[] = $this->propertyFqcn($metadata->getPropertyAccessor($idField)->getUnderlyingReflector()); - } - - foreach ($metadata->getReflectionClass()->getProperties() as $property) { - if ($metadata->hasField($property->getName())) { - continue; - } - - $skippedFieldsFqns[] = $this->propertyFqcn($property); - } - - return $skippedFieldsFqns; - } - - private function propertyFqcn(ReflectionProperty $property): string - { - if ($property->isPrivate()) { - return "\0" . $property->getDeclaringClass()->getName() . "\0" . $property->getName(); - } - - if ($property->isProtected()) { - return "\0*\0" . $property->getName(); - } - - return $property->getName(); - } -} diff --git a/src/Proxy/FileLocator.php b/src/Proxy/FileLocator.php deleted file mode 100644 index 516b4ef6e9..0000000000 --- a/src/Proxy/FileLocator.php +++ /dev/null @@ -1,25 +0,0 @@ - - */ -interface InternalProxy extends Proxy -{ - public function __setInitialized(bool $initialized): void; -} diff --git a/src/Proxy/Resolver/CachingClassNameResolver.php b/src/Proxy/Resolver/CachingClassNameResolver.php deleted file mode 100644 index cd0343301c..0000000000 --- a/src/Proxy/Resolver/CachingClassNameResolver.php +++ /dev/null @@ -1,31 +0,0 @@ - */ - private array $resolvedNames = []; - - public function __construct(private ProxyClassNameResolver $resolver) - { - } - - /** - * Gets the real class name of a class name that could be a proxy. - */ - public function getRealClass(string $class): string - { - return $this->resolveClassName($class); - } - - public function resolveClassName(string $className): string - { - return $this->resolvedNames[$className] ??= $this->resolver->resolveClassName($className); - } -} diff --git a/src/Proxy/Resolver/ClassNameResolver.php b/src/Proxy/Resolver/ClassNameResolver.php deleted file mode 100644 index f869de0eb5..0000000000 --- a/src/Proxy/Resolver/ClassNameResolver.php +++ /dev/null @@ -1,16 +0,0 @@ -resolveClassName($class); - } - - public function resolveClassName(string $className): string - { - $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); - - if ($pos === false) { - return $className; - } - - return substr($className, $pos + Proxy::MARKER_LENGTH + 2); - } -} diff --git a/src/Proxy/Resolver/ProxyManagerClassNameResolver.php b/src/Proxy/Resolver/ProxyManagerClassNameResolver.php deleted file mode 100644 index 08c9f704fe..0000000000 --- a/src/Proxy/Resolver/ProxyManagerClassNameResolver.php +++ /dev/null @@ -1,40 +0,0 @@ -resolveClassName($class); - } - - /** - * @param class-string|class-string> $className - * - * @return class-string - * - * @phpstan-template RealClassName of object - */ - public function resolveClassName(string $className): string - { - return $this->getClassNameInflector()->getUserClassName($className); - } - - private function getClassNameInflector(): ClassNameInflectorInterface - { - return $this->configuration->getProxyManagerConfiguration()->getClassNameInflector(); - } -} diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 43e8f7cc73..e60d45141f 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -1116,8 +1116,8 @@ public function popLast(): self * * If $primer is true or a callable is provided, referenced documents for * this field will loaded into UnitOfWork immediately after the query is - * executed. This will avoid multiple queries due to lazy initialization of - * Proxy objects. + * executed. This will avoid multiple queries due to initialization of + * lazy objects. * * If $primer is false, no priming will take place. That is also the default * behavior. diff --git a/src/Query/ReferencePrimer.php b/src/Query/ReferencePrimer.php index d038974f4d..10d4c07493 100644 --- a/src/Query/ReferencePrimer.php +++ b/src/Query/ReferencePrimer.php @@ -30,7 +30,7 @@ * * Priming a field mapped as either reference-one or reference-many will load * the referenced document(s) eagerly and avoid individual lazy loading through - * proxy object initialization. + * lazy object initialization. * * Priming can only be used for the owning side side of a relationship, since * the referenced identifiers are not immediately available on an inverse side. @@ -105,7 +105,7 @@ public function primeReferences(ClassMetadata $class, $documents, string $fieldN foreach ($documents as $document) { $fieldValue = $class->getFieldValue($document, $fieldName); - /* The field will need to be either a Proxy (reference-one) or + /* The field will need to be either a lazy object (reference-one) or * PersistentCollection (reference-many) in order to prime anything. */ if (! is_object($fieldValue)) { diff --git a/src/Tools/Console/Command/GenerateProxiesCommand.php b/src/Tools/Console/Command/GenerateProxiesCommand.php deleted file mode 100644 index 06a502729f..0000000000 --- a/src/Tools/Console/Command/GenerateProxiesCommand.php +++ /dev/null @@ -1,110 +0,0 @@ -setName('odm:generate:proxies') - ->setDescription('Generates proxy classes for document classes.') - ->setDefinition([ - new InputOption( - 'filter', - null, - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'A string pattern used to match documents that should be processed.' - ), - ]) - ->setHelp(<<<'EOT' -Generates proxy classes for document classes. -EOT - ); - } - - private function doExecute(InputInterface $input, OutputInterface $output): int - { - $filter = $input->getOption('filter'); - assert(is_array($filter)); - - $dm = $this->getHelper('documentManager')->getDocumentManager(); - assert($dm instanceof DocumentManager); - - $metadatas = array_filter($dm->getMetadataFactory()->getAllMetadata(), static fn (ClassMetadata $classMetadata): bool => ! $classMetadata->isEmbeddedDocument && ! $classMetadata->isMappedSuperclass && ! $classMetadata->isQueryResultDocument); - $metadatas = MetadataFilter::filter($metadatas, $filter); - $destPath = $dm->getConfiguration()->getProxyDir(); - - if (! is_string($destPath)) { - throw ConfigurationException::proxyDirMissing(); - } - - if (! is_dir($destPath)) { - mkdir($destPath, 0775, true); - } - - $destPath = realpath($destPath); - assert($destPath !== false); - - if (! file_exists($destPath)) { - throw new InvalidArgumentException( - sprintf("Proxies destination directory '%s' does not exist.", $destPath) - ); - } - - if (! is_writable($destPath)) { - throw new InvalidArgumentException( - sprintf("Proxies destination directory '%s' does not have write permissions.", $destPath) - ); - } - - if (count($metadatas)) { - foreach ($metadatas as $metadata) { - $output->write( - sprintf('Processing document "%s"', $metadata->name) . PHP_EOL - ); - } - - // Generating Proxies - $dm->getProxyFactory()->generateProxyClasses($metadatas); - - // Outputting information message - $output->write(PHP_EOL . sprintf('Proxy classes generated to "%s"', $destPath) . PHP_EOL); - } else { - $output->write('No Metadata Classes to process.' . PHP_EOL); - } - - return 0; - } -} diff --git a/src/Tools/Console/Command/Schema/CreateCommand.php b/src/Tools/Console/Command/Schema/CreateCommand.php index 443c236756..822c6703c4 100644 --- a/src/Tools/Console/Command/Schema/CreateCommand.php +++ b/src/Tools/Console/Command/Schema/CreateCommand.php @@ -121,19 +121,4 @@ protected function processSearchIndex(SchemaManager $sm): void { $sm->createSearchIndexes(); } - - /** @return void */ - protected function processDocumentProxy(SchemaManager $sm, string $document) - { - $classMetadata = $this->getMetadataFactory()->getMetadataFor($document); - - $this->getDocumentManager()->getProxyFactory()->generateProxyClasses([$classMetadata]); - } - - /** @return void */ - protected function processProxy(SchemaManager $sm) - { - $metadatas = $this->getMetadataFactory()->getAllMetadata(); - $this->getDocumentManager()->getProxyFactory()->generateProxyClasses($metadatas); - } } diff --git a/src/UnitOfWork.php b/src/UnitOfWork.php index 9fa61a158a..201d758ad9 100644 --- a/src/UnitOfWork.php +++ b/src/UnitOfWork.php @@ -14,7 +14,6 @@ use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionInterface; use Doctrine\ODM\MongoDB\Persisters\CollectionPersister; use Doctrine\ODM\MongoDB\Persisters\PersistenceBuilder; -use Doctrine\ODM\MongoDB\Proxy\InternalProxy; use Doctrine\ODM\MongoDB\Query\Query; use Doctrine\ODM\MongoDB\Types\DateType; use Doctrine\ODM\MongoDB\Types\Type; @@ -28,7 +27,6 @@ use MongoDB\Driver\Exception\RuntimeException; use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; -use ProxyManager\Proxy\GhostObjectInterface; use ReflectionProperty; use Throwable; use UnexpectedValueException; @@ -937,7 +935,7 @@ public function computeChangeSets(): void } foreach ($documentsToProcess as $document) { - // Ignore uninitialized proxy objects + // Ignore uninitialized lazy object if ($this->isUninitializedObject($document)) { continue; } @@ -972,14 +970,6 @@ private function computeAssociationChanges(object $parentDocument, array $assoc, $class = $this->dm->getClassMetadata($parentDocument::class); $topOrExistingDocument = ( ! $isNewParentDocument || ! $class->isEmbeddedDocument); - if ($value instanceof InternalProxy && ! $value->__isInitialized()) { - return; - } - - if ($value instanceof GhostObjectInterface && ! $value->isProxyInitialized()) { - return; - } - if ($value instanceof PersistentCollectionInterface && $value->isDirty() && $value->getOwner() !== null && ($assoc['isOwningSide'] || isset($assoc['embedded']))) { if ($topOrExistingDocument || CollectionHelper::usesSet($assoc['strategy'])) { $this->scheduleCollectionUpdate($value); @@ -1097,7 +1087,7 @@ private function computeAssociationChanges(object $parentDocument, array $assoc, */ public function recomputeSingleDocumentChangeSet(ClassMetadata $class, object $document): void { - // Ignore uninitialized proxy objects + // Ignore uninitialized lazy objects if ($this->isUninitializedObject($document)) { return; } @@ -1837,7 +1827,7 @@ private function doRemove(object $document, array &$visited): void $visited[$oid] = $document; // mark visited /* Cascade first, because scheduleForDelete() removes the entity from - * the identity map, which can cause problems when a lazy Proxy has to + * the identity map, which can cause problems when a lazy object has to * be initialized for the cascade operation. */ $this->cascadeRemove($document, $visited); @@ -1988,7 +1978,7 @@ private function doMerge(object $document, array &$visited, ?object $prevManaged } else { $other = $this ->dm - ->getProxyFactory() + ->getLazyObjectFactory() ->getProxy($targetClass, $relatedId); $this->registerManaged($other, $relatedId, [$targetClass->identifier => $relatedId]); } @@ -2768,15 +2758,7 @@ public function getOrCreateDocument(string $className, array $data, array &$hint $document = $this->identityMap[$class->name][$serializedId]; $oid = spl_object_id($document); if ($this->isUninitializedObject($document)) { - if ($this->dm->getConfiguration()->isNativeLazyObjectEnabled()) { - $class->reflClass->markLazyObjectAsInitialized($document); - } elseif ($document instanceof InternalProxy) { - $document->__setInitialized(true); - } elseif ($document instanceof GhostObjectInterface) { - $document->setProxyInitializer(null); - } else { - throw new \RuntimeException(sprintf('Expected uninitialized proxy or ghost object from class "%s"', $document::class)); - } + $class->reflClass->markLazyObjectAsInitialized($document); $overrideLocalValues = true; if ($document instanceof NotifyPropertyChanged) { @@ -3051,17 +3033,13 @@ public function getScheduledCollectionUpdates(): array } /** - * Helper method to initialize a lazy loading proxy or persistent collection. + * Helper method to initialize a lazy object or persistent collection. * * @internal */ public function initializeObject(object $obj): void { - if ($obj instanceof InternalProxy && $obj->__isInitialized() === false) { - $obj->__load(); - } elseif ($obj instanceof GhostObjectInterface && $obj->isProxyInitialized() === false) { - $obj->initializeProxy(); - } elseif ($obj instanceof PersistentCollectionInterface) { + if ($obj instanceof PersistentCollectionInterface) { $obj->initialize(); } else { $this->dm->getClassMetadata($obj::class)->reflClass->initializeLazyObject($obj); @@ -3069,18 +3047,15 @@ public function initializeObject(object $obj): void } /** - * Helper method to check whether a lazy loading proxy or persistent collection has been initialized. + * Helper method to check whether a lazy object or persistent collection has been initialized. * * @internal */ public function isUninitializedObject(object $obj): bool { return match (true) { - $obj instanceof InternalProxy => ! $obj->__isInitialized(), - $obj instanceof GhostObjectInterface => ! $obj->isProxyInitialized(), $obj instanceof PersistentCollectionInterface => ! $obj->isInitialized(), - $this->dm->getConfiguration()->isNativeLazyObjectEnabled() => $this->dm->getClassMetadata($obj::class)->reflClass->isUninitializedLazyObject($obj), - default => false + default => $this->dm->getClassMetadata($obj::class)->reflClass->isUninitializedLazyObject($obj), }; } diff --git a/src/Utility/LifecycleEventManager.php b/src/Utility/LifecycleEventManager.php index 4214c01568..b374ee60ef 100644 --- a/src/Utility/LifecycleEventManager.php +++ b/src/Utility/LifecycleEventManager.php @@ -52,9 +52,9 @@ public function enableTransactionalMode(Session $session): void * * @return bool Returns whether the exceptionDisabled flag was set */ - public function documentNotFound(object $proxy, $id): bool + public function documentNotFound(object $document, $id): bool { - $eventArgs = new DocumentNotFoundEventArgs($proxy, $this->dm, $id); + $eventArgs = new DocumentNotFoundEventArgs($document, $this->dm, $id); $this->evm->dispatchEvent(Events::documentNotFound, $eventArgs); return $eventArgs->isExceptionDisabled(); diff --git a/tests/Tests/BaseTestCase.php b/tests/Tests/BaseTestCase.php index 835c6c0e9e..db6a5c263c 100644 --- a/tests/Tests/BaseTestCase.php +++ b/tests/Tests/BaseTestCase.php @@ -8,7 +8,6 @@ use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Mapping\Driver\AttributeDriver; use Doctrine\ODM\MongoDB\Proxy\Factory\NativeLazyObjectFactory; -use Doctrine\ODM\MongoDB\Proxy\InternalProxy; use Doctrine\ODM\MongoDB\Tests\Query\Filter\Filter; use Doctrine\ODM\MongoDB\UnitOfWork; use Doctrine\Persistence\Mapping\Driver\FileClassLocator; @@ -20,7 +19,6 @@ use MongoDB\Driver\Server; use MongoDB\Model\DatabaseInfo; use PHPUnit\Framework\TestCase; -use ProxyManager\Proxy\LazyLoadingInterface; use function array_key_exists; use function array_map; @@ -97,8 +95,6 @@ protected static function getConfiguration(): Configuration { $config = new Configuration(); - $config->setProxyDir(__DIR__ . '/../Proxies'); - $config->setProxyNamespace('Proxies'); $config->setHydratorDir(__DIR__ . '/../Hydrators'); $config->setHydratorNamespace('Hydrators'); $config->setPersistentCollectionDir(__DIR__ . '/../PersistentCollections'); @@ -106,15 +102,7 @@ protected static function getConfiguration(): Configuration $config->setDefaultDB(DOCTRINE_MONGODB_DATABASE); $config->setMetadataDriverImpl(static::createMetadataDriverImpl()); - if ($_ENV['USE_NATIVE_LAZY_OBJECT']) { - $config->setUseNativeLazyObject(true); - } elseif ($_ENV['USE_LAZY_GHOST_OBJECT']) { - $config->setUseLazyGhostObject(true); - } - - if ($config->isNativeLazyObjectEnabled()) { - NativeLazyObjectFactory::enableTracking(); - } + NativeLazyObjectFactory::enableTracking(); $config->addFilter('testFilter', Filter::class); $config->addFilter('testFilter2', Filter::class); @@ -144,11 +132,7 @@ public static function assertArraySubset(array $subset, array $array, bool $chec public static function isLazyObject(object $document): bool { - if ($_ENV['USE_NATIVE_LAZY_OBJECT']) { - return NativeLazyObjectFactory::isLazyObject($document); - } - - return $document instanceof InternalProxy || $document instanceof LazyLoadingInterface; + return NativeLazyObjectFactory::isLazyObject($document); } protected static function createMetadataDriverImpl(): MappingDriver diff --git a/tests/Tests/ConfigurationTest.php b/tests/Tests/ConfigurationTest.php index 87c6757411..3320bb0516 100644 --- a/tests/Tests/ConfigurationTest.php +++ b/tests/Tests/ConfigurationTest.php @@ -4,100 +4,19 @@ namespace Doctrine\ODM\MongoDB\Tests; -use Composer\InstalledVersions; use Doctrine\ODM\MongoDB\Configuration; use Doctrine\ODM\MongoDB\ConfigurationException; use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionFactory; use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionGenerator; -use LogicException; use MongoDB\Driver\Manager; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; -use PHPUnit\Framework\Attributes\RequiresPhp; -use PHPUnit\Framework\Attributes\TestWith; use PHPUnit\Framework\TestCase; -use ProxyManager\Configuration as ProxyManagerConfiguration; use stdClass; -use Symfony\Component\VarExporter\LazyGhostTrait; use function base64_encode; -use function class_exists; use function str_repeat; -use function trait_exists; -use function version_compare; class ConfigurationTest extends TestCase { - #[RequiresPhp('< 8.4')] - public function testUseNativeLazyObjectBeforePHP84(): void - { - $c = new Configuration(); - - self::expectException(LogicException::class); - self::expectExceptionMessage('Native lazy objects require PHP 8.4 or higher.'); - - $c->setUseNativeLazyObject(true); - } - - #[IgnoreDeprecations] - public function testUseLazyGhostObject(): void - { - $c = new Configuration(); - - if (! trait_exists(LazyGhostTrait::class)) { - $this->expectException(LogicException::class); - $this->expectExceptionMessage('Package "symfony/var-exporter" >= 8.0 does not provide lazy ghost objects, use native lazy objects instead.'); - } - - self::assertFalse($c->isLazyGhostObjectEnabled()); - $c->setUseLazyGhostObject(true); - self::assertTrue($c->isLazyGhostObjectEnabled()); - - if (! class_exists(ProxyManagerConfiguration::class)) { - $this->expectException(LogicException::class); - $this->expectExceptionMessage('Package "friendsofphp/proxy-manager-lts" is required to disable LazyGhostObject.'); - } - - $c->setUseLazyGhostObject(false); - self::assertFalse($c->isLazyGhostObjectEnabled()); - } - - #[RequiresPhp('>= 8.4')] - public function testUseLazyGhostObjectWithSymfony8(): void - { - if (InstalledVersions::isInstalled('symfony/var-exporter') && version_compare(InstalledVersions::getVersion('symfony/var-exporter'), '8', '<')) { - $this->markTestSkipped('Symfony VarExporter 8 or higher is not installed.'); - } - - $c = new Configuration(); - - self::expectException(LogicException::class); - self::expectExceptionMessage('Package "symfony/var-exporter" >= 8.0 does not provide lazy ghost objects, use native lazy objects instead.'); - - $c->setUseLazyGhostObject(true); - } - - #[IgnoreDeprecations] - public function testNativeLazyObjectDeprecatedByDefault(): void - { - $c = new Configuration(); - - self::assertFalse($c->isNativeLazyObjectEnabled()); - } - - #[RequiresPhp('>= 8.4')] - #[TestWith([true])] - #[TestWith([false])] - public function testConflictingLazyObjectSettings(bool $flag): void - { - $c = new Configuration(); - $c->setUseNativeLazyObject(true); - - self::expectException(LogicException::class); - self::expectExceptionMessage('Cannot enable or disable LazyGhostObject when native lazy objects are enabled.'); - - $c->setUseLazyGhostObject($flag); - } - public function testDefaultPersistentCollectionFactory(): void { $c = new Configuration(); diff --git a/tests/Tests/DocumentManagerTest.php b/tests/Tests/DocumentManagerTest.php index a23f5612d8..2674525ae6 100644 --- a/tests/Tests/DocumentManagerTest.php +++ b/tests/Tests/DocumentManagerTest.php @@ -14,7 +14,6 @@ use Doctrine\ODM\MongoDB\Mapping\MappingException; use Doctrine\ODM\MongoDB\MongoDBException; use Doctrine\ODM\MongoDB\Proxy\Factory\ProxyFactory; -use Doctrine\ODM\MongoDB\Proxy\Resolver\ClassNameResolver; use Doctrine\ODM\MongoDB\Query\Builder as QueryBuilder; use Doctrine\ODM\MongoDB\Query\FilterCollection; use Doctrine\ODM\MongoDB\SchemaManager; @@ -35,7 +34,6 @@ use MongoDB\BSON\ObjectId; use MongoDB\Client; use PHPUnit\Framework\Attributes\DataProvider; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; use RuntimeException; use stdClass; @@ -78,7 +76,7 @@ public function testGetUnitOfWork(): void public function testGetProxyFactory(): void { - self::assertInstanceOf(ProxyFactory::class, $this->dm->getProxyFactory()); + self::assertInstanceOf(ProxyFactory::class, $this->dm->getLazyObjectFactory()); } public function testGetEventManager(): void @@ -263,13 +261,6 @@ public function testGetClassNameForAssociationReturnsTargetDocumentWithNullData( $mapping = ClassMetadataTestUtil::getFieldMapping(['targetDocument' => User::class]); self::assertEquals(User::class, $this->dm->getClassNameForAssociation($mapping, null)); } - - #[IgnoreDeprecations] - public function testGetClassNameResolver(): void - { - $resolver = $this->dm->getClassNameResolver(); - self::assertInstanceOf(ClassNameResolver::class, $resolver); - } } #[ODM\Document] diff --git a/tests/Tests/Functional/PropertyHooksTest.php b/tests/Tests/Functional/PropertyHooksTest.php index 2ffeb1ee74..d310ef3e46 100644 --- a/tests/Tests/Functional/PropertyHooksTest.php +++ b/tests/Tests/Functional/PropertyHooksTest.php @@ -13,17 +13,6 @@ #[RequiresPhp('>= 8.4.0')] class PropertyHooksTest extends BaseTestCase { - protected function setUp(): void - { - parent::setUp(); - - if ($this->dm->getConfiguration()->isNativeLazyObjectEnabled()) { - return; - } - - $this->markTestSkipped('Property hooks require native lazy objects to be enabled.'); - } - public function testMapPropertyHooks(): void { $user = new User(); diff --git a/tests/Tests/Functional/ReadOnlyPropertiesTest.php b/tests/Tests/Functional/ReadOnlyPropertiesTest.php index ff0dfd28d8..6b62115a29 100644 --- a/tests/Tests/Functional/ReadOnlyPropertiesTest.php +++ b/tests/Tests/Functional/ReadOnlyPropertiesTest.php @@ -14,11 +14,6 @@ class ReadOnlyPropertiesTest extends BaseTestCase { public function testReadOnlyDocument(): void { - $configuration = $this->dm->getConfiguration(); - if (! $configuration->isNativeLazyObjectEnabled() && ! $configuration->isLazyGhostObjectEnabled()) { - $this->markTestSkipped('Read-only properties are not supported by the legacy Proxy Manager. https://github.com/FriendsOfPHP/proxy-manager-lts/issues/26'); - } - $document = new ReadOnlyProperties('Test Name'); $document->onlyRead = new ReadOnlyProperties('Nested Name'); $this->dm->persist($document); diff --git a/tests/Tests/Functional/Ticket/GH1990Test.php b/tests/Tests/Functional/Ticket/GH1990Test.php index c1becf358b..4550b59225 100644 --- a/tests/Tests/Functional/Ticket/GH1990Test.php +++ b/tests/Tests/Functional/Ticket/GH1990Test.php @@ -14,7 +14,7 @@ public function testInitialisationOfInverseProxy(): void // Generate proxy class using generateProxyClasses to ensure it is // consistent with other proxy classes $metadata = $this->dm->getClassMetadata(GH1990Document::class); - $this->dm->getProxyFactory()->generateProxyClasses([$metadata]); + $this->dm->getLazyObjectFactory()->generateProxyClasses([$metadata]); $parent = new GH1990Document(null); $child = new GH1990Document($parent); diff --git a/tests/Tests/Mapping/PropertyAccessors/ObjectCastPropertyAccessorTest.php b/tests/Tests/Mapping/PropertyAccessors/ObjectCastPropertyAccessorTest.php deleted file mode 100644 index 62563b76a7..0000000000 --- a/tests/Tests/Mapping/PropertyAccessors/ObjectCastPropertyAccessorTest.php +++ /dev/null @@ -1,85 +0,0 @@ -setValue($object, 'value'); - - $this->assertEquals($object->property, 'value'); - $this->assertEquals('value', $accessor->getValue($object)); - } - - public function testSetGetPrivatePropertyValue(): void - { - $object = new ObjectClass(); - $accessor = ObjectCastPropertyAccessor::fromNames(ObjectClass::class, 'property2'); - - $accessor->setValue($object, 'value'); - - $this->assertEquals($object->getProperty2(), 'value'); - $this->assertEquals('value', $accessor->getValue($object)); - } - - public function testSetGetInternalProxyValue(): void - { - $object = new ObjectClassInternalProxy(); - $accessor = ObjectCastPropertyAccessor::fromNames(ObjectClassInternalProxy::class, 'property'); - - $accessor->setValue($object, 'value'); - - $this->assertEquals($object->property, 'value'); - $this->assertEquals('value', $accessor->getValue($object)); - $this->assertFalse($object->isInitialized); - $this->assertEquals(2, $object->counter); - } -} - -class ObjectClass -{ - /** @var string */ - public $property; - /** @var string */ - private $property2; - - public function getProperty2(): string - { - return $this->property2; - } -} - -/** @implements InternalProxy */ -class ObjectClassInternalProxy implements InternalProxy -{ - /** @var string */ - public $property; - public bool $isInitialized = false; - public int $counter = 0; - - public function __setInitialized(bool $initialized): void - { - $this->isInitialized = $initialized; - $this->counter++; - } - - public function __load(): void - { - } - - /** Returns whether this proxy is initialized or not. */ - public function __isInitialized(): bool - { - return $this->isInitialized; - } -} diff --git a/tests/Tests/Proxy/Factory/ProxyFactoryTest.php b/tests/Tests/Proxy/Factory/ProxyFactoryTest.php index a25575f1bb..a4a73263a9 100644 --- a/tests/Tests/Proxy/Factory/ProxyFactoryTest.php +++ b/tests/Tests/Proxy/Factory/ProxyFactoryTest.php @@ -9,7 +9,6 @@ use Doctrine\ODM\MongoDB\Event\DocumentNotFoundEventArgs; use Doctrine\ODM\MongoDB\Events; use Doctrine\ODM\MongoDB\LockException; -use Doctrine\ODM\MongoDB\Proxy\InternalProxy; use Doctrine\ODM\MongoDB\Tests\BaseTestCase; use Documents\Cart; use Documents\DocumentWithUnmappedProperties; @@ -17,7 +16,6 @@ use MongoDB\Collection; use MongoDB\Database; use PHPUnit\Framework\MockObject\MockObject; -use ProxyManager\Proxy\GhostObjectInterface; class ProxyFactoryTest extends BaseTestCase { @@ -84,14 +82,8 @@ public function testCreateProxyForDocumentWithUnmappedProperties(): void $proxy = $this->dm->getReference(DocumentWithUnmappedProperties::class, '123'); self::assertTrue(self::isLazyObject($proxy)); - // Disable initializer so we can access properties without initialising the object - if ($proxy instanceof InternalProxy) { - $proxy->__setInitialized(true); - } elseif ($proxy instanceof GhostObjectInterface) { - $proxy->setProxyInitializer(null); - } elseif ($this->dm->getConfiguration()->isNativeLazyObjectEnabled()) { - $this->dm->getClassMetadata($proxy::class)->getReflectionClass()->markLazyObjectAsInitialized($proxy); - } + // Disable initializer so we can access properties without initializing the object + $this->dm->getClassMetadata($proxy::class)->getReflectionClass()->markLazyObjectAsInitialized($proxy); self::assertSame('bar', $proxy->foo); }