vendor/doctrine/mongodb-odm/src/Configuration.php line 264

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ODM\MongoDB;
  4. use Doctrine\Common\Annotations\AnnotationReader;
  5. use Doctrine\Common\Cache\Cache;
  6. use Doctrine\Common\Cache\Psr6\CacheAdapter;
  7. use Doctrine\Common\Cache\Psr6\DoctrineProvider;
  8. use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory;
  9. use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactoryInterface;
  10. use Doctrine\ODM\MongoDB\Mapping\Driver\AnnotationDriver;
  11. use Doctrine\ODM\MongoDB\PersistentCollection\DefaultPersistentCollectionFactory;
  12. use Doctrine\ODM\MongoDB\PersistentCollection\DefaultPersistentCollectionGenerator;
  13. use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionFactory;
  14. use Doctrine\ODM\MongoDB\PersistentCollection\PersistentCollectionGenerator;
  15. use Doctrine\ODM\MongoDB\Proxy\FileLocator;
  16. use Doctrine\ODM\MongoDB\Repository\DefaultGridFSRepository;
  17. use Doctrine\ODM\MongoDB\Repository\DefaultRepositoryFactory;
  18. use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
  19. use Doctrine\ODM\MongoDB\Repository\GridFSRepository;
  20. use Doctrine\ODM\MongoDB\Repository\RepositoryFactory;
  21. use Doctrine\Persistence\Mapping\Driver\MappingDriver;
  22. use Doctrine\Persistence\ObjectRepository;
  23. use InvalidArgumentException;
  24. use Jean85\PrettyVersions;
  25. use LogicException;
  26. use MongoDB\Client;
  27. use MongoDB\Driver\Manager;
  28. use MongoDB\Driver\WriteConcern;
  29. use ProxyManager\Configuration as ProxyManagerConfiguration;
  30. use ProxyManager\Factory\LazyLoadingGhostFactory;
  31. use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
  32. use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy;
  33. use Psr\Cache\CacheItemPoolInterface;
  34. use ReflectionClass;
  35. use stdClass;
  36. use Symfony\Component\VarExporter\LazyGhostTrait;
  37. use Throwable;
  38. use function array_diff_key;
  39. use function array_intersect_key;
  40. use function array_key_exists;
  41. use function class_exists;
  42. use function interface_exists;
  43. use function is_string;
  44. use function trait_exists;
  45. use function trigger_deprecation;
  46. use function trim;
  47. use const PHP_VERSION_ID;
  48. /**
  49.  * Configuration class for the DocumentManager. When setting up your DocumentManager
  50.  * you can optionally specify an instance of this class as the second argument.
  51.  * If you do not pass a configuration object, a blank one will be created for you.
  52.  *
  53.  *     <?php
  54.  *
  55.  *     $config = new Configuration();
  56.  *     $dm = DocumentManager::create(new Connection(), $config);
  57.  *
  58.  * @phpstan-import-type CommitOptions from UnitOfWork
  59.  * @phpstan-type KmsProvider array{type: string, ...}
  60.  */
  61. class Configuration
  62. {
  63.     /**
  64.      * Never autogenerate a proxy/hydrator/persistent collection and rely that
  65.      * it was generated by some process before deployment. Copied from
  66.      * \Doctrine\Common\Proxy\AbstractProxyFactory.
  67.      */
  68.     public const AUTOGENERATE_NEVER 0;
  69.     /**
  70.      * Always generates a new proxy/hydrator/persistent collection in every request.
  71.      *
  72.      * This is only sane during development.
  73.      * Copied from \Doctrine\Common\Proxy\AbstractProxyFactory.
  74.      */
  75.     public const AUTOGENERATE_ALWAYS 1;
  76.     /**
  77.      * Autogenerate the proxy/hydrator/persistent collection class when the file does not exist.
  78.      *
  79.      * This strategy causes a file exists call whenever any proxy/hydrator is used the
  80.      * first time in a request. Copied from \Doctrine\Common\Proxy\AbstractProxyFactory.
  81.      */
  82.     public const AUTOGENERATE_FILE_NOT_EXISTS 2;
  83.     /**
  84.      * Generate the proxy/hydrator/persistent collection classes using eval().
  85.      *
  86.      * This strategy is only sane for development.
  87.      * Copied from \Doctrine\Common\Proxy\AbstractProxyFactory.
  88.      */
  89.     public const AUTOGENERATE_EVAL 3;
  90.     /**
  91.      * Autogenerate the proxy class when the proxy file does not exist or
  92.      * when the proxied file changed.
  93.      *
  94.      * This strategy causes a file_exists() call whenever any proxy is used the
  95.      * first time in a request. When the proxied file is changed, the proxy will
  96.      * be updated.
  97.      */
  98.     public const AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED 4;
  99.     /**
  100.      * Array of attributes for this configuration instance.
  101.      *
  102.      * @phpstan-var array{
  103.      *      autoGenerateHydratorClasses?: self::AUTOGENERATE_*,
  104.      *      autoGeneratePersistentCollectionClasses?: self::AUTOGENERATE_*,
  105.      *      autoGenerateProxyClasses?: self::AUTOGENERATE_*,
  106.      *      classMetadataFactoryName?: class-string<ClassMetadataFactoryInterface>,
  107.      *      defaultCommitOptions?: CommitOptions,
  108.      *      defaultDocumentRepositoryClassName?: class-string<ObjectRepository<object>>,
  109.      *      defaultGridFSRepositoryClassName?: class-string<GridFSRepository<object>>,
  110.      *      defaultDB?: string,
  111.      *      documentNamespaces?: array<string, string>,
  112.      *      filters?: array<string, array{
  113.      *          class: class-string,
  114.      *          parameters: array<string, mixed>
  115.      *      }>,
  116.      *      hydratorDir?: string,
  117.      *      hydratorNamespace?: string,
  118.      *      metadataCacheImpl?: Cache,
  119.      *      metadataDriverImpl?: MappingDriver,
  120.      *      persistentCollectionFactory?: PersistentCollectionFactory,
  121.      *      persistentCollectionGenerator?: PersistentCollectionGenerator,
  122.      *      persistentCollectionDir?: string,
  123.      *      persistentCollectionNamespace?: string,
  124.      *      proxyDir?: string,
  125.      *      proxyNamespace?: string,
  126.      *      repositoryFactory?: RepositoryFactory,
  127.      *      kmsProvider?: KmsProvider,
  128.      *      defaultMasterKey?: array<string, mixed>|null,
  129.      *      autoEncryption?: array<string, mixed>,
  130.      * }
  131.      */
  132.     private array $attributes = [];
  133.     private ?CacheItemPoolInterface $metadataCache null;
  134.     /** @deprecated */
  135.     private ProxyManagerConfiguration $proxyManagerConfiguration;
  136.     private bool $useTransactionalFlush false;
  137.     private bool $lazyGhostObject  false;
  138.     private bool $nativeLazyObject false;
  139.     private static string $version;
  140.     /**
  141.      * Provides the driver options to be used when creating the MongoDB client.
  142.      *
  143.      * @return array<string, mixed>
  144.      */
  145.     public function getDriverOptions(): array
  146.     {
  147.         $driverOptions = [
  148.             'driver' => [
  149.                 'name' => 'doctrine-odm',
  150.                 'version' => self::getVersion(),
  151.             ],
  152.         ];
  153.         if (isset($this->attributes['kmsProvider'])) {
  154.             $driverOptions['autoEncryption'] = $this->getAutoEncryptionOptions();
  155.         }
  156.         return $driverOptions;
  157.     }
  158.     /**
  159.      * Get options to create a ClientEncryption instance.
  160.      *
  161.      * @see https://www.php.net/manual/en/mongodb-driver-clientencryption.construct.php
  162.      *
  163.      * @return array{keyVaultClient?: Client|Manager, keyVaultNamespace: string, kmsProviders: array<string, mixed>, tlsOptions?: array<string, mixed>}
  164.      */
  165.     public function getClientEncryptionOptions(): array
  166.     {
  167.         if (! isset($this->attributes['kmsProvider'])) {
  168.             throw ConfigurationException::clientEncryptionOptionsNotSet();
  169.         }
  170.         return array_intersect_key($this->getAutoEncryptionOptions(), [
  171.             'keyVaultClient' => 1,
  172.             'keyVaultNamespace' => 1,
  173.             'kmsProviders' => 1,
  174.             'tlsOptions' => 1,
  175.         ]);
  176.     }
  177.     /**
  178.      * Adds a namespace under a certain alias.
  179.      *
  180.      * @deprecated Document short aliases are deprecated - use ::class constant instead.
  181.      */
  182.     public function addDocumentNamespace(string $aliasstring $namespace): void
  183.     {
  184.         trigger_deprecation(
  185.             'doctrine/mongodb-odm',
  186.             '2.3',
  187.             'Document short namespace aliases such as "%s" are deprecated, use ::class constant instead.',
  188.             $alias,
  189.         );
  190.         $this->attributes['documentNamespaces'][$alias] = $namespace;
  191.     }
  192.     /**
  193.      * Resolves a registered namespace alias to the full namespace.
  194.      *
  195.      * @deprecated Document short aliases are deprecated - use ::class constant instead.
  196.      *
  197.      * @throws MongoDBException
  198.      */
  199.     public function getDocumentNamespace(string $documentNamespaceAlias): string
  200.     {
  201.         trigger_deprecation(
  202.             'doctrine/mongodb-odm',
  203.             '2.3',
  204.             'Document short namespace aliases such as "%s" are deprecated, use ::class constant instead.',
  205.             $documentNamespaceAlias,
  206.         );
  207.         if (! isset($this->attributes['documentNamespaces'][$documentNamespaceAlias])) {
  208.             throw MongoDBException::unknownDocumentNamespace($documentNamespaceAlias);
  209.         }
  210.         return trim($this->attributes['documentNamespaces'][$documentNamespaceAlias], '\\');
  211.     }
  212.     /**
  213.      * Retrieves the list of registered document namespace aliases.
  214.      *
  215.      * @deprecated Document short aliases are deprecated - use ::class constant instead.
  216.      *
  217.      * @return array<string, string>
  218.      */
  219.     public function getDocumentNamespaces(): array
  220.     {
  221.         trigger_deprecation(
  222.             'doctrine/mongodb-odm',
  223.             '2.3',
  224.             'Document short namespace aliases are deprecated, use ::class constant instead.',
  225.         );
  226.         return $this->attributes['documentNamespaces'];
  227.     }
  228.     /**
  229.      * Set the document alias map
  230.      *
  231.      * @deprecated Document short aliases are deprecated - use ::class constant instead.
  232.      *
  233.      * @param array<string, string> $documentNamespaces
  234.      */
  235.     public function setDocumentNamespaces(array $documentNamespaces): void
  236.     {
  237.         trigger_deprecation(
  238.             'doctrine/mongodb-odm',
  239.             '2.3',
  240.             'Document short namespace aliases are deprecated, use ::class constant instead.',
  241.         );
  242.         $this->attributes['documentNamespaces'] = $documentNamespaces;
  243.     }
  244.     /**
  245.      * Sets the cache driver implementation that is used for metadata caching.
  246.      *
  247.      * @todo Force parameter to be a Closure to ensure lazy evaluation
  248.      *       (as soon as a metadata cache is in effect, the driver never needs to initialize).
  249.      */
  250.     public function setMetadataDriverImpl(MappingDriver $driverImpl): void
  251.     {
  252.         $this->attributes['metadataDriverImpl'] = $driverImpl;
  253.     }
  254.     /**
  255.      * Add a new default annotation driver with a correctly configured annotation reader.
  256.      *
  257.      * @param string[] $paths
  258.      */
  259.     public function newDefaultAnnotationDriver(array $paths = []): AnnotationDriver
  260.     {
  261.         $reader = new AnnotationReader();
  262.         return new AnnotationDriver($reader$paths);
  263.     }
  264.     /**
  265.      * Gets the cache driver implementation that is used for the mapping metadata.
  266.      */
  267.     public function getMetadataDriverImpl(): ?MappingDriver
  268.     {
  269.         return $this->attributes['metadataDriverImpl'] ?? null;
  270.     }
  271.     public function getMetadataCacheImpl(): ?Cache
  272.     {
  273.         trigger_deprecation(
  274.             'doctrine/mongodb-odm',
  275.             '2.2',
  276.             'Using "%s" is deprecated. Please use "%s::getMetadataCache" instead.',
  277.             __METHOD__,
  278.             self::class,
  279.         );
  280.         return $this->attributes['metadataCacheImpl'] ?? null;
  281.     }
  282.     public function setMetadataCacheImpl(Cache $cacheImpl): void
  283.     {
  284.         trigger_deprecation(
  285.             'doctrine/mongodb-odm',
  286.             '2.2',
  287.             'Using "%s" is deprecated. Please use "%s::setMetadataCache" instead.',
  288.             __METHOD__,
  289.             self::class,
  290.         );
  291.         $this->attributes['metadataCacheImpl'] = $cacheImpl;
  292.         $this->metadataCache                   CacheAdapter::wrap($cacheImpl);
  293.     }
  294.     public function getMetadataCache(): ?CacheItemPoolInterface
  295.     {
  296.         return $this->metadataCache;
  297.     }
  298.     public function setMetadataCache(CacheItemPoolInterface $cache): void
  299.     {
  300.         $this->metadataCache                   $cache;
  301.         $this->attributes['metadataCacheImpl'] = DoctrineProvider::wrap($cache);
  302.     }
  303.     /**
  304.      * Sets the directory where Doctrine generates any necessary proxy class files.
  305.      */
  306.     public function setProxyDir(string $dir): void
  307.     {
  308.         $this->attributes['proxyDir'] = $dir;
  309.         unset($this->proxyManagerConfiguration);
  310.     }
  311.     /**
  312.      * Gets the directory where Doctrine generates any necessary proxy class files.
  313.      */
  314.     public function getProxyDir(): ?string
  315.     {
  316.         return $this->attributes['proxyDir'] ?? null;
  317.     }
  318.     /**
  319.      * Gets an int flag that indicates whether proxy classes should always be regenerated
  320.      * during each script execution.
  321.      *
  322.      * @return self::AUTOGENERATE_*
  323.      */
  324.     public function getAutoGenerateProxyClasses(): int
  325.     {
  326.         return $this->attributes['autoGenerateProxyClasses'] ?? self::AUTOGENERATE_FILE_NOT_EXISTS;
  327.     }
  328.     /**
  329.      * Sets an int flag that indicates whether proxy classes should always be regenerated
  330.      * during each script execution.
  331.      *
  332.      * @param self::AUTOGENERATE_* $mode
  333.      */
  334.     public function setAutoGenerateProxyClasses(int $mode): void
  335.     {
  336.         $this->attributes['autoGenerateProxyClasses'] = $mode;
  337.         unset($this->proxyManagerConfiguration);
  338.     }
  339.     public function getProxyNamespace(): ?string
  340.     {
  341.         return $this->attributes['proxyNamespace'] ?? null;
  342.     }
  343.     public function setProxyNamespace(string $ns): void
  344.     {
  345.         $this->attributes['proxyNamespace'] = $ns;
  346.         unset($this->proxyManagerConfiguration);
  347.     }
  348.     public function setHydratorDir(string $dir): void
  349.     {
  350.         $this->attributes['hydratorDir'] = $dir;
  351.     }
  352.     public function getHydratorDir(): ?string
  353.     {
  354.         return $this->attributes['hydratorDir'] ?? null;
  355.     }
  356.     /**
  357.      * Gets an int flag that indicates whether hydrator classes should always be regenerated
  358.      * during each script execution.
  359.      *
  360.      * @return self::AUTOGENERATE_*
  361.      */
  362.     public function getAutoGenerateHydratorClasses(): int
  363.     {
  364.         return $this->attributes['autoGenerateHydratorClasses'] ?? self::AUTOGENERATE_ALWAYS;
  365.     }
  366.     /**
  367.      * Sets an int flag that indicates whether hydrator classes should always be regenerated
  368.      * during each script execution.
  369.      *
  370.      * @param self::AUTOGENERATE_* $mode
  371.      */
  372.     public function setAutoGenerateHydratorClasses(int $mode): void
  373.     {
  374.         $this->attributes['autoGenerateHydratorClasses'] = $mode;
  375.     }
  376.     public function getHydratorNamespace(): ?string
  377.     {
  378.         return $this->attributes['hydratorNamespace'] ?? null;
  379.     }
  380.     public function setHydratorNamespace(string $ns): void
  381.     {
  382.         $this->attributes['hydratorNamespace'] = $ns;
  383.     }
  384.     public function setPersistentCollectionDir(string $dir): void
  385.     {
  386.         $this->attributes['persistentCollectionDir'] = $dir;
  387.     }
  388.     public function getPersistentCollectionDir(): ?string
  389.     {
  390.         return $this->attributes['persistentCollectionDir'] ?? null;
  391.     }
  392.     /**
  393.      * Gets a integer flag that indicates how and when persistent collection
  394.      * classes should be generated.
  395.      *
  396.      * @return self::AUTOGENERATE_*
  397.      */
  398.     public function getAutoGeneratePersistentCollectionClasses(): int
  399.     {
  400.         return $this->attributes['autoGeneratePersistentCollectionClasses'] ?? self::AUTOGENERATE_ALWAYS;
  401.     }
  402.     /**
  403.      * Sets a integer flag that indicates how and when persistent collection
  404.      * classes should be generated.
  405.      *
  406.      * @param self::AUTOGENERATE_* $mode
  407.      */
  408.     public function setAutoGeneratePersistentCollectionClasses(int $mode): void
  409.     {
  410.         $this->attributes['autoGeneratePersistentCollectionClasses'] = $mode;
  411.     }
  412.     public function getPersistentCollectionNamespace(): ?string
  413.     {
  414.         return $this->attributes['persistentCollectionNamespace'] ?? null;
  415.     }
  416.     public function setPersistentCollectionNamespace(string $ns): void
  417.     {
  418.         $this->attributes['persistentCollectionNamespace'] = $ns;
  419.     }
  420.     /**
  421.      * Sets the default DB to use for all Documents that do not specify
  422.      * a database.
  423.      */
  424.     public function setDefaultDB(string $defaultDB): void
  425.     {
  426.         $this->attributes['defaultDB'] = $defaultDB;
  427.     }
  428.     /**
  429.      * Gets the default DB to use for all Documents that do not specify a database.
  430.      */
  431.     public function getDefaultDB(): ?string
  432.     {
  433.         return $this->attributes['defaultDB'] ?? null;
  434.     }
  435.     /**
  436.      * @param class-string<ClassMetadataFactoryInterface> $cmfName
  437.      *
  438.      * @throws MongoDBException If is not a ClassMetadataFactoryInterface.
  439.      */
  440.     public function setClassMetadataFactoryName(string $cmfName): void
  441.     {
  442.         $reflectionClass = new ReflectionClass($cmfName);
  443.         if (! $reflectionClass->implementsInterface(ClassMetadataFactoryInterface::class)) {
  444.             throw MongoDBException::invalidClassMetadataFactory($cmfName);
  445.         }
  446.         $this->attributes['classMetadataFactoryName'] = $cmfName;
  447.     }
  448.     /** @return class-string<ClassMetadataFactoryInterface> */
  449.     public function getClassMetadataFactoryName(): string
  450.     {
  451.         if (! isset($this->attributes['classMetadataFactoryName'])) {
  452.             $this->attributes['classMetadataFactoryName'] = ClassMetadataFactory::class;
  453.         }
  454.         return $this->attributes['classMetadataFactoryName'];
  455.     }
  456.     /** @phpstan-return CommitOptions */
  457.     public function getDefaultCommitOptions(): array
  458.     {
  459.         if (! isset($this->attributes['defaultCommitOptions'])) {
  460.             $this->attributes['defaultCommitOptions'] = ['writeConcern' => new WriteConcern(1)];
  461.         }
  462.         return $this->attributes['defaultCommitOptions'];
  463.     }
  464.     /** @phpstan-param CommitOptions $defaultCommitOptions */
  465.     public function setDefaultCommitOptions(array $defaultCommitOptions): void
  466.     {
  467.         foreach (UnitOfWork::DEPRECATED_WRITE_OPTIONS as $deprecatedOption) {
  468.             if (array_key_exists($deprecatedOption$defaultCommitOptions)) {
  469.                 trigger_deprecation(
  470.                     'doctrine/mongodb-odm',
  471.                     '2.6',
  472.                     'The "%s" commit option used in the configuration is deprecated.',
  473.                     $deprecatedOption,
  474.                 );
  475.             }
  476.         }
  477.         $this->attributes['defaultCommitOptions'] = $defaultCommitOptions;
  478.     }
  479.     /**
  480.      * Add a filter to the list of possible filters.
  481.      *
  482.      * @param array<string, mixed> $parameters
  483.      * @param class-string         $className
  484.      */
  485.     public function addFilter(string $namestring $className, array $parameters = []): void
  486.     {
  487.         $this->attributes['filters'][$name] = [
  488.             'class' => $className,
  489.             'parameters' => $parameters,
  490.         ];
  491.     }
  492.     /** @return class-string|null */
  493.     public function getFilterClassName(string $name): ?string
  494.     {
  495.         return isset($this->attributes['filters'][$name])
  496.             ? $this->attributes['filters'][$name]['class']
  497.             : null;
  498.     }
  499.     /** @return array<string, mixed> */
  500.     public function getFilterParameters(string $name): array
  501.     {
  502.         return isset($this->attributes['filters'][$name])
  503.             ? $this->attributes['filters'][$name]['parameters']
  504.             : [];
  505.     }
  506.     /**
  507.      * @param class-string<ObjectRepository<object>> $className
  508.      *
  509.      * @throws MongoDBException If is not an ObjectRepository.
  510.      */
  511.     public function setDefaultDocumentRepositoryClassName(string $className): void
  512.     {
  513.         $reflectionClass = new ReflectionClass($className);
  514.         if (! $reflectionClass->implementsInterface(ObjectRepository::class)) {
  515.             throw MongoDBException::invalidDocumentRepository($className);
  516.         }
  517.         $this->attributes['defaultDocumentRepositoryClassName'] = $className;
  518.     }
  519.     /** @return class-string<ObjectRepository<object>> */
  520.     public function getDefaultDocumentRepositoryClassName(): string
  521.     {
  522.         return $this->attributes['defaultDocumentRepositoryClassName'] ?? DocumentRepository::class;
  523.     }
  524.     /**
  525.      * @param class-string<GridFSRepository<object>> $className
  526.      *
  527.      * @throws MongoDBException If the class does not implement the GridFSRepository interface.
  528.      */
  529.     public function setDefaultGridFSRepositoryClassName(string $className): void
  530.     {
  531.         $reflectionClass = new ReflectionClass($className);
  532.         if (! $reflectionClass->implementsInterface(GridFSRepository::class)) {
  533.             throw MongoDBException::invalidGridFSRepository($className);
  534.         }
  535.         $this->attributes['defaultGridFSRepositoryClassName'] = $className;
  536.     }
  537.     /** @return class-string<GridFSRepository<object>> */
  538.     public function getDefaultGridFSRepositoryClassName(): string
  539.     {
  540.         return $this->attributes['defaultGridFSRepositoryClassName'] ?? DefaultGridFSRepository::class;
  541.     }
  542.     public function setRepositoryFactory(RepositoryFactory $repositoryFactory): void
  543.     {
  544.         $this->attributes['repositoryFactory'] = $repositoryFactory;
  545.     }
  546.     public function getRepositoryFactory(): RepositoryFactory
  547.     {
  548.         return $this->attributes['repositoryFactory'] ?? new DefaultRepositoryFactory();
  549.     }
  550.     public function setPersistentCollectionFactory(PersistentCollectionFactory $persistentCollectionFactory): void
  551.     {
  552.         $this->attributes['persistentCollectionFactory'] = $persistentCollectionFactory;
  553.     }
  554.     public function getPersistentCollectionFactory(): PersistentCollectionFactory
  555.     {
  556.         if (! isset($this->attributes['persistentCollectionFactory'])) {
  557.             $this->attributes['persistentCollectionFactory'] = new DefaultPersistentCollectionFactory();
  558.         }
  559.         return $this->attributes['persistentCollectionFactory'];
  560.     }
  561.     public function setPersistentCollectionGenerator(PersistentCollectionGenerator $persistentCollectionGenerator): void
  562.     {
  563.         $this->attributes['persistentCollectionGenerator'] = $persistentCollectionGenerator;
  564.     }
  565.     public function getPersistentCollectionGenerator(): PersistentCollectionGenerator
  566.     {
  567.         if (! isset($this->attributes['persistentCollectionGenerator'])) {
  568.             if ($this->getPersistentCollectionDir() === null) {
  569.                 throw ConfigurationException::persistentCollectionDirMissing();
  570.             }
  571.             if ($this->getPersistentCollectionNamespace() === null) {
  572.                 throw ConfigurationException::persistentCollectionNamespaceMissing();
  573.             }
  574.             $this->attributes['persistentCollectionGenerator'] = new DefaultPersistentCollectionGenerator(
  575.                 $this->getPersistentCollectionDir(),
  576.                 $this->getPersistentCollectionNamespace(),
  577.             );
  578.         }
  579.         return $this->attributes['persistentCollectionGenerator'];
  580.     }
  581.     /** @deprecated */
  582.     public function buildGhostObjectFactory(): LazyLoadingGhostFactory
  583.     {
  584.         return new LazyLoadingGhostFactory($this->getProxyManagerConfiguration());
  585.     }
  586.     /** @deprecated */
  587.     public function getProxyManagerConfiguration(): ProxyManagerConfiguration
  588.     {
  589.         if (isset($this->proxyManagerConfiguration)) {
  590.             return $this->proxyManagerConfiguration;
  591.         }
  592.         $proxyManagerConfiguration = new ProxyManagerConfiguration();
  593.         $proxyManagerConfiguration->setProxiesTargetDir($this->getProxyDir());
  594.         $proxyManagerConfiguration->setProxiesNamespace($this->getProxyNamespace());
  595.         switch ($this->getAutoGenerateProxyClasses()) {
  596.             case self::AUTOGENERATE_FILE_NOT_EXISTS:
  597.                 $proxyManagerConfiguration->setGeneratorStrategy(new FileWriterGeneratorStrategy(
  598.                     new FileLocator($proxyManagerConfiguration->getProxiesTargetDir()),
  599.                 ));
  600.                 break;
  601.             case self::AUTOGENERATE_EVAL:
  602.                 $proxyManagerConfiguration->setGeneratorStrategy(new EvaluatingGeneratorStrategy());
  603.                 break;
  604.             default:
  605.                 throw new InvalidArgumentException('Invalid proxy generation strategy given - only AUTOGENERATE_FILE_NOT_EXISTS and AUTOGENERATE_EVAL are supported.');
  606.         }
  607.         return $this->proxyManagerConfiguration $proxyManagerConfiguration;
  608.     }
  609.     public function setUseTransactionalFlush(bool $useTransactionalFlush): void
  610.     {
  611.         $this->useTransactionalFlush $useTransactionalFlush;
  612.     }
  613.     public function isTransactionalFlushEnabled(): bool
  614.     {
  615.         return $this->useTransactionalFlush;
  616.     }
  617.     /**
  618.      * Generate proxy classes using Symfony VarExporter's LazyGhostTrait if true.
  619.      * Otherwise, use ProxyManager's LazyLoadingGhostFactory (deprecated)
  620.      */
  621.     public function setUseLazyGhostObject(bool $flag): void
  622.     {
  623.         if ($this->nativeLazyObject) {
  624.             throw new LogicException('Cannot enable or disable LazyGhostObject when native lazy objects are enabled.');
  625.         }
  626.         if ($flag && ! trait_exists(LazyGhostTrait::class)) {
  627.             throw new LogicException('Package "symfony/var-exporter" >= 8.0 does not provide lazy ghost objects, use native lazy objects instead.');
  628.         }
  629.         if (! $flag) {
  630.             if (! class_exists(ProxyManagerConfiguration::class)) {
  631.                 throw new LogicException('Package "friendsofphp/proxy-manager-lts" is required to disable LazyGhostObject.');
  632.             }
  633.             if (PHP_VERSION_ID 80400) {
  634.                 trigger_deprecation('doctrine/mongodb-odm''2.10''Using "friendsofphp/proxy-manager-lts" is deprecated. Use "symfony/var-exporter" LazyGhostObjects instead.');
  635.             }
  636.         }
  637.         $this->lazyGhostObject $flag;
  638.     }
  639.     public function isLazyGhostObjectEnabled(): bool
  640.     {
  641.         // Always false if native lazy objects are enabled
  642.         return $this->lazyGhostObject && ! $this->nativeLazyObject;
  643.     }
  644.     public function setUseNativeLazyObject(bool $nativeLazyObject): void
  645.     {
  646.         if (PHP_VERSION_ID 80400 && $nativeLazyObject) {
  647.             throw new LogicException('Native lazy objects require PHP 8.4 or higher.');
  648.         }
  649.         $this->nativeLazyObject $nativeLazyObject;
  650.     }
  651.     public function isNativeLazyObjectEnabled(): bool
  652.     {
  653.         if (PHP_VERSION_ID >= 80400 && ! $this->nativeLazyObject) {
  654.             trigger_deprecation('doctrine/mongodb-odm''2.14''Not using native lazy objects is deprecated and will be impossible in Doctrine MongoDB ODM 3.0.');
  655.         }
  656.         return $this->nativeLazyObject;
  657.     }
  658.     /**
  659.      * Set the KMS provider to use for auto-encryption. The name of the KMS provider
  660.      * must be specified in the 'type' key of the array.
  661.      *
  662.      * @see https://www.php.net/manual/en/mongodb-driver-clientencryption.construct.php
  663.      *
  664.      * @param KmsProvider $kmsProvider
  665.      */
  666.     public function setKmsProvider(array $kmsProvider): void
  667.     {
  668.         if (! isset($kmsProvider['type'])) {
  669.             throw ConfigurationException::kmsProviderTypeRequired();
  670.         }
  671.         if (! is_string($kmsProvider['type'])) {
  672.             throw ConfigurationException::kmsProviderTypeMustBeString();
  673.         }
  674.         $this->attributes['kmsProvider'] = $kmsProvider;
  675.     }
  676.     /**
  677.      * Set the default master key to use when creating encrypted collections.
  678.      *
  679.      * @param array<string, mixed>|null $masterKey
  680.      */
  681.     public function setDefaultMasterKey(?array $masterKey): void
  682.     {
  683.         $this->attributes['defaultMasterKey'] = $masterKey;
  684.     }
  685.     /**
  686.      * Set the options for auto-encryption.
  687.      *
  688.      * @see https://www.php.net/manual/en/mongodb-driver-manager.construct.php#mongodb-driver-manager.construct-autoencryption
  689.      *
  690.      * @param array{ keyVaultClient?: Client|Manager, keyVaultNamespace?: string, tlsOptions?: array<string, mixed>, schemaMap?: array<string, mixed>, bypassAutoEncryption?: bool, bypassQueryAnalysis?: bool, encryptedFieldsMap?: array<string,mixed>, extraOptions?: array<string, mixed>} $options
  691.      */
  692.     public function setAutoEncryption(array $options): void
  693.     {
  694.         if (isset($options['kmsProviders'])) {
  695.             throw ConfigurationException::kmsProvidersOptionMustUseSetter();
  696.         }
  697.         $this->attributes['autoEncryption'] = $options;
  698.     }
  699.     /**
  700.      * Get the default KMS provider name used when creating encrypted collections.
  701.      */
  702.     public function getDefaultKmsProvider(): ?string
  703.     {
  704.         return $this->attributes['kmsProvider']['type'] ?? null;
  705.     }
  706.     /**
  707.      * Get the default master key used when creating encrypted collections.
  708.      *
  709.      * @return array<string, mixed>|null
  710.      */
  711.     public function getDefaultMasterKey(): ?array
  712.     {
  713.         if (! isset($this->attributes['kmsProvider']) || $this->attributes['kmsProvider']['type'] === 'local') {
  714.             return null;
  715.         }
  716.         return $this->attributes['defaultMasterKey'] ?? throw ConfigurationException::masterKeyRequired($this->attributes['kmsProvider']['type']);
  717.     }
  718.     private static function getVersion(): string
  719.     {
  720.         if (! isset(self::$version)) {
  721.             try {
  722.                 self::$version PrettyVersions::getVersion('doctrine/mongodb-odm')->getPrettyVersion();
  723.             } catch (Throwable) {
  724.                 return self::$version 'unknown';
  725.             }
  726.         }
  727.         return self::$version;
  728.     }
  729.     /** @return array<string, mixed> */
  730.     private function getAutoEncryptionOptions(): array
  731.     {
  732.         $kmsProviderName $this->attributes['kmsProvider']['type'];
  733.         $kmsProviderOpts array_diff_key($this->attributes['kmsProvider'], ['type' => 0]);
  734.         // To use "Automatic Credentials", the provider options must be an empty document.
  735.         // Fix the empty array to an empty stdClass object, as the driver expects it.
  736.         if ($kmsProviderOpts === []) {
  737.             $kmsProviderOpts = new stdClass();
  738.         }
  739.         return [
  740.             // Each kmsProvider must be an object, it can be empty
  741.             'kmsProviders' => [$kmsProviderName => $kmsProviderOpts],
  742.             'keyVaultNamespace' => $this->getDefaultDB() . '.datakeys',
  743.             ...$this->attributes['autoEncryption'] ?? [],
  744.         ];
  745.     }
  746.     /**
  747.      * Pipelines using a search index that does not exist or is not queryable
  748.      * will return zero documents. By enabling this feature, an additional query
  749.      * is performed when the pipeline doesn't return any results to check if the
  750.      * search index exists. If the index does not exist, an exception is thrown.
  751.      * This feature is enabled by default.
  752.      * This applies to $search, $searchMeta and $vectorSearch pipelines.
  753.      */
  754.     public function setAssertSearchIndexExistsForEmptyResult(bool $enabled): void
  755.     {
  756.         $this->attributes['assertSearchIndexExistsForEmptyResult'] = $enabled;
  757.     }
  758.     public function assertSearchIndexExistsForEmptyResult(): bool
  759.     {
  760.         return $this->attributes['assertSearchIndexExistsForEmptyResult'] ?? true;
  761.     }
  762. }
  763. interface_exists(MappingDriver::class);