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