vendor/doctrine/mongodb-odm/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataFactory.php line 175

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ODM\MongoDB\Mapping;
  4. use Doctrine\Common\EventManager;
  5. use Doctrine\ODM\MongoDB\Configuration;
  6. use Doctrine\ODM\MongoDB\ConfigurationException;
  7. use Doctrine\ODM\MongoDB\DocumentManager;
  8. use Doctrine\ODM\MongoDB\Event\LoadClassMetadataEventArgs;
  9. use Doctrine\ODM\MongoDB\Event\OnClassMetadataNotFoundEventArgs;
  10. use Doctrine\ODM\MongoDB\Events;
  11. use Doctrine\ODM\MongoDB\Id\AlnumGenerator;
  12. use Doctrine\ODM\MongoDB\Id\AutoGenerator;
  13. use Doctrine\ODM\MongoDB\Id\IdGenerator;
  14. use Doctrine\ODM\MongoDB\Id\IncrementGenerator;
  15. use Doctrine\ODM\MongoDB\Id\UuidGenerator;
  16. use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
  17. use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
  18. use Doctrine\Persistence\Mapping\Driver\MappingDriver;
  19. use Doctrine\Persistence\Mapping\ReflectionService;
  20. use ReflectionException;
  21. use function assert;
  22. use function get_class;
  23. use function get_class_methods;
  24. use function in_array;
  25. use function interface_exists;
  26. use function trigger_deprecation;
  27. use function ucfirst;
  28. /**
  29.  * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
  30.  * metadata mapping informations of a class which describes how a class should be mapped
  31.  * to a document database.
  32.  *
  33.  * @internal
  34.  *
  35.  * @method list<ClassMetadata> getAllMetadata()
  36.  * @method ClassMetadata[] getLoadedMetadata()
  37.  * @method ClassMetadata getMetadataFor($className)
  38.  */
  39. final class ClassMetadataFactory extends AbstractClassMetadataFactory
  40. {
  41.     /** @var string */
  42.     protected $cacheSalt '$MONGODBODMCLASSMETADATA';
  43.     /** @var DocumentManager The DocumentManager instance */
  44.     private $dm;
  45.     /** @var Configuration The Configuration instance */
  46.     private $config;
  47.     /** @var MappingDriver The used metadata driver. */
  48.     private $driver;
  49.     /** @var EventManager The event manager instance */
  50.     private $evm;
  51.     public function setDocumentManager(DocumentManager $dm): void
  52.     {
  53.         $this->dm $dm;
  54.     }
  55.     public function setConfiguration(Configuration $config): void
  56.     {
  57.         $this->config $config;
  58.     }
  59.     /**
  60.      * Lazy initialization of this stuff, especially the metadata driver,
  61.      * since these are not needed at all when a metadata cache is active.
  62.      */
  63.     protected function initialize(): void
  64.     {
  65.         $driver $this->config->getMetadataDriverImpl();
  66.         if ($driver === null) {
  67.             throw ConfigurationException::noMetadataDriverConfigured();
  68.         }
  69.         $this->driver      $driver;
  70.         $this->evm         $this->dm->getEventManager();
  71.         $this->initialized true;
  72.     }
  73.     /**
  74.      * @param string $className
  75.      */
  76.     protected function onNotFoundMetadata($className)
  77.     {
  78.         if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) {
  79.             return null;
  80.         }
  81.         $eventArgs = new OnClassMetadataNotFoundEventArgs($className$this->dm);
  82.         $this->evm->dispatchEvent(Events::onClassMetadataNotFound$eventArgs);
  83.         return $eventArgs->getFoundMetadata();
  84.     }
  85.     /**
  86.      * @deprecated
  87.      *
  88.      * @param string $namespaceAlias
  89.      * @param string $simpleClassName
  90.      */
  91.     protected function getFqcnFromAlias($namespaceAlias$simpleClassName): string
  92.     {
  93.         return $this->config->getDocumentNamespace($namespaceAlias) . '\\' $simpleClassName;
  94.     }
  95.     protected function getDriver(): MappingDriver
  96.     {
  97.         return $this->driver;
  98.     }
  99.     protected function wakeupReflection(ClassMetadataInterface $classReflectionService $reflService): void
  100.     {
  101.     }
  102.     protected function initializeReflection(ClassMetadataInterface $classReflectionService $reflService): void
  103.     {
  104.     }
  105.     protected function isEntity(ClassMetadataInterface $class): bool
  106.     {
  107.         assert($class instanceof ClassMetadata);
  108.         return ! $class->isMappedSuperclass && ! $class->isEmbeddedDocument && ! $class->isQueryResultDocument && ! $class->isView();
  109.     }
  110.     /**
  111.      * @param bool $rootEntityFound
  112.      */
  113.     protected function doLoadMetadata($class$parent$rootEntityFound, array $nonSuperclassParents = []): void
  114.     {
  115.         assert($class instanceof ClassMetadata);
  116.         if ($parent instanceof ClassMetadata) {
  117.             $class->setInheritanceType($parent->inheritanceType);
  118.             $class->setDiscriminatorField($parent->discriminatorField);
  119.             $class->setDiscriminatorMap($parent->discriminatorMap);
  120.             $class->setDefaultDiscriminatorValue($parent->defaultDiscriminatorValue);
  121.             $class->setIdGeneratorType($parent->generatorType);
  122.             $this->addInheritedFields($class$parent);
  123.             $this->addInheritedRelations($class$parent);
  124.             $this->addInheritedIndexes($class$parent);
  125.             $this->setInheritedShardKey($class$parent);
  126.             $class->setIdentifier($parent->identifier);
  127.             $class->setVersioned($parent->isVersioned);
  128.             $class->setVersionField($parent->versionField);
  129.             $class->setLifecycleCallbacks($parent->lifecycleCallbacks);
  130.             $class->setAlsoLoadMethods($parent->alsoLoadMethods);
  131.             $class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
  132.             $class->setReadPreference($parent->readPreference$parent->readPreferenceTags);
  133.             $class->setWriteConcern($parent->writeConcern);
  134.             if ($parent->isMappedSuperclass) {
  135.                 $class->setCustomRepositoryClass($parent->customRepositoryClassName);
  136.             }
  137.             if ($parent->isFile) {
  138.                 $class->isFile true;
  139.                 $class->setBucketName($parent->bucketName);
  140.                 if ($parent->chunkSizeBytes !== null) {
  141.                     $class->setChunkSizeBytes($parent->chunkSizeBytes);
  142.                 }
  143.             }
  144.         }
  145.         // Invoke driver
  146.         try {
  147.             $this->driver->loadMetadataForClass($class->getName(), $class);
  148.         } catch (ReflectionException $e) {
  149.             throw MappingException::reflectionFailure($class->getName(), $e);
  150.         }
  151.         $this->validateIdentifier($class);
  152.         if ($parent instanceof ClassMetadata && $rootEntityFound && $parent->generatorType === $class->generatorType) {
  153.             if ($parent->generatorType) {
  154.                 $class->setIdGeneratorType($parent->generatorType);
  155.             }
  156.             if ($parent->generatorOptions) {
  157.                 $class->setIdGeneratorOptions($parent->generatorOptions);
  158.             }
  159.             if ($parent->idGenerator) {
  160.                 $class->setIdGenerator($parent->idGenerator);
  161.             }
  162.         } else {
  163.             $this->completeIdGeneratorMapping($class);
  164.         }
  165.         if ($parent instanceof ClassMetadata && $parent->isInheritanceTypeSingleCollection()) {
  166.             $class->setDatabase($parent->getDatabase());
  167.             $class->setCollection($parent->getCollection());
  168.         }
  169.         $class->setParentClasses($nonSuperclassParents);
  170.         if (! $this->evm->hasListeners(Events::loadClassMetadata)) {
  171.             return;
  172.         }
  173.         $eventArgs = new LoadClassMetadataEventArgs($class$this->dm);
  174.         $this->evm->dispatchEvent(Events::loadClassMetadata$eventArgs);
  175.         // phpcs:ignore SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed
  176.         if ($class->isChangeTrackingNotify()) {
  177.             trigger_deprecation(
  178.                 'doctrine/mongodb-odm',
  179.                 '2.4',
  180.                 'NOTIFY tracking policy used in class "%s" is deprecated. Please use DEFERRED_EXPLICIT instead.',
  181.                 $class->name
  182.             );
  183.         }
  184.     }
  185.     /**
  186.      * Validates the identifier mapping.
  187.      *
  188.      * @throws MappingException
  189.      */
  190.     protected function validateIdentifier(ClassMetadata $class): void
  191.     {
  192.         if (! $class->identifier && $this->isEntity($class)) {
  193.             throw MappingException::identifierRequired($class->name);
  194.         }
  195.     }
  196.     protected function newClassMetadataInstance($className): ClassMetadata
  197.     {
  198.         return new ClassMetadata($className);
  199.     }
  200.     private function completeIdGeneratorMapping(ClassMetadata $class): void
  201.     {
  202.         $idGenOptions $class->generatorOptions;
  203.         switch ($class->generatorType) {
  204.             case ClassMetadata::GENERATOR_TYPE_AUTO:
  205.                 $class->setIdGenerator(new AutoGenerator());
  206.                 break;
  207.             case ClassMetadata::GENERATOR_TYPE_INCREMENT:
  208.                 $incrementGenerator = new IncrementGenerator();
  209.                 if (isset($idGenOptions['key'])) {
  210.                     $incrementGenerator->setKey((string) $idGenOptions['key']);
  211.                 }
  212.                 if (isset($idGenOptions['collection'])) {
  213.                     $incrementGenerator->setCollection((string) $idGenOptions['collection']);
  214.                 }
  215.                 if (isset($idGenOptions['startingId'])) {
  216.                     $incrementGenerator->setStartingId((int) $idGenOptions['startingId']);
  217.                 }
  218.                 $class->setIdGenerator($incrementGenerator);
  219.                 break;
  220.             case ClassMetadata::GENERATOR_TYPE_UUID:
  221.                 $uuidGenerator = new UuidGenerator();
  222.                 if (isset($idGenOptions['salt'])) {
  223.                     $uuidGenerator->setSalt((string) $idGenOptions['salt']);
  224.                 }
  225.                 $class->setIdGenerator($uuidGenerator);
  226.                 break;
  227.             case ClassMetadata::GENERATOR_TYPE_ALNUM:
  228.                 $alnumGenerator = new AlnumGenerator();
  229.                 if (isset($idGenOptions['pad'])) {
  230.                     $alnumGenerator->setPad((int) $idGenOptions['pad']);
  231.                 }
  232.                 if (isset($idGenOptions['chars'])) {
  233.                     $alnumGenerator->setChars((string) $idGenOptions['chars']);
  234.                 } elseif (isset($idGenOptions['awkwardSafe'])) {
  235.                     $alnumGenerator->setAwkwardSafeMode((bool) $idGenOptions['awkwardSafe']);
  236.                 }
  237.                 $class->setIdGenerator($alnumGenerator);
  238.                 break;
  239.             case ClassMetadata::GENERATOR_TYPE_CUSTOM:
  240.                 if (empty($idGenOptions['class'])) {
  241.                     throw MappingException::missingIdGeneratorClass($class->name);
  242.                 }
  243.                 $customGenerator = new $idGenOptions['class']();
  244.                 unset($idGenOptions['class']);
  245.                 if (! $customGenerator instanceof IdGenerator) {
  246.                     throw MappingException::classIsNotAValidGenerator(get_class($customGenerator));
  247.                 }
  248.                 $methods get_class_methods($customGenerator);
  249.                 foreach ($idGenOptions as $name => $value) {
  250.                     $method 'set' ucfirst($name);
  251.                     if (! in_array($method$methods)) {
  252.                         throw MappingException::missingGeneratorSetter(get_class($customGenerator), $name);
  253.                     }
  254.                     $customGenerator->$method($value);
  255.                 }
  256.                 $class->setIdGenerator($customGenerator);
  257.                 break;
  258.             case ClassMetadata::GENERATOR_TYPE_NONE:
  259.                 break;
  260.             default:
  261.                 throw new MappingException('Unknown generator type: ' $class->generatorType);
  262.         }
  263.     }
  264.     /**
  265.      * Adds inherited fields to the subclass mapping.
  266.      */
  267.     private function addInheritedFields(ClassMetadata $subClassClassMetadata $parentClass): void
  268.     {
  269.         foreach ($parentClass->fieldMappings as $fieldName => $mapping) {
  270.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  271.                 $mapping['inherited'] = $parentClass->name;
  272.             }
  273.             if (! isset($mapping['declared'])) {
  274.                 $mapping['declared'] = $parentClass->name;
  275.             }
  276.             $subClass->addInheritedFieldMapping($mapping);
  277.         }
  278.         foreach ($parentClass->reflFields as $name => $field) {
  279.             $subClass->reflFields[$name] = $field;
  280.         }
  281.     }
  282.     /**
  283.      * Adds inherited association mappings to the subclass mapping.
  284.      *
  285.      * @throws MappingException
  286.      */
  287.     private function addInheritedRelations(ClassMetadata $subClassClassMetadata $parentClass): void
  288.     {
  289.         foreach ($parentClass->associationMappings as $field => $mapping) {
  290.             if ($parentClass->isMappedSuperclass) {
  291.                 $mapping['sourceDocument'] = $subClass->name;
  292.             }
  293.             if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
  294.                 $mapping['inherited'] = $parentClass->name;
  295.             }
  296.             if (! isset($mapping['declared'])) {
  297.                 $mapping['declared'] = $parentClass->name;
  298.             }
  299.             $subClass->addInheritedAssociationMapping($mapping);
  300.         }
  301.     }
  302.     /**
  303.      * Adds inherited indexes to the subclass mapping.
  304.      */
  305.     private function addInheritedIndexes(ClassMetadata $subClassClassMetadata $parentClass): void
  306.     {
  307.         foreach ($parentClass->indexes as $index) {
  308.             $subClass->addIndex($index['keys'], $index['options']);
  309.         }
  310.     }
  311.     /**
  312.      * Adds inherited shard key to the subclass mapping.
  313.      */
  314.     private function setInheritedShardKey(ClassMetadata $subClassClassMetadata $parentClass): void
  315.     {
  316.         if (! $parentClass->isSharded()) {
  317.             return;
  318.         }
  319.         $subClass->setShardKey(
  320.             $parentClass->shardKey['keys'],
  321.             $parentClass->shardKey['options']
  322.         );
  323.     }
  324. }
  325. interface_exists(ClassMetadataInterface::class);
  326. interface_exists(ReflectionService::class);