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

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