vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php line 87

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ORM\Mapping\Driver;
  4. use Doctrine\Deprecations\Deprecation;
  5. use Doctrine\ORM\Events;
  6. use Doctrine\ORM\Mapping;
  7. use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
  8. use Doctrine\ORM\Mapping\ClassMetadata;
  9. use Doctrine\ORM\Mapping\MappingException;
  10. use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
  11. use Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver;
  12. use LogicException;
  13. use ReflectionClass;
  14. use ReflectionMethod;
  15. use ReflectionProperty;
  16. use function assert;
  17. use function class_exists;
  18. use function constant;
  19. use function defined;
  20. use function get_class;
  21. use function sprintf;
  22. use const PHP_VERSION_ID;
  23. class AttributeDriver extends CompatibilityAnnotationDriver
  24. {
  25.     use ColocatedMappingDriver;
  26.     /** @var array<string,int> */
  27.     // @phpcs:ignore
  28.     protected $entityAnnotationClasses = [
  29.         Mapping\Entity::class => 1,
  30.         Mapping\MappedSuperclass::class => 2,
  31.     ];
  32.     /**
  33.      * The annotation reader.
  34.      *
  35.      * @internal this property will be private in 3.0
  36.      *
  37.      * @var AttributeReader
  38.      */
  39.     protected $reader;
  40.     /**
  41.      * @param array<string> $paths
  42.      */
  43.     public function __construct(array $paths)
  44.     {
  45.         if (PHP_VERSION_ID 80000) {
  46.             throw new LogicException(sprintf(
  47.                 'The attribute metadata driver cannot be enabled on PHP 7. Please upgrade to PHP 8 or choose a different'
  48.                 ' metadata driver.'
  49.             ));
  50.         }
  51.         $this->reader = new AttributeReader();
  52.         $this->addPaths($paths);
  53.     }
  54.     /**
  55.      * Retrieve the current annotation reader
  56.      *
  57.      * @deprecated no replacement planned.
  58.      *
  59.      * @return AttributeReader
  60.      */
  61.     public function getReader()
  62.     {
  63.         Deprecation::trigger(
  64.             'doctrine/orm',
  65.             'https://github.com/doctrine/orm/pull/9587',
  66.             '%s is deprecated with no replacement',
  67.             __METHOD__
  68.         );
  69.         return $this->reader;
  70.     }
  71.     /**
  72.      * {@inheritDoc}
  73.      */
  74.     public function isTransient($className)
  75.     {
  76.         $classAnnotations $this->reader->getClassAnnotations(new ReflectionClass($className));
  77.         foreach ($classAnnotations as $a) {
  78.             $annot $a instanceof RepeatableAttributeCollection $a[0] : $a;
  79.             if (isset($this->entityAnnotationClasses[get_class($annot)])) {
  80.                 return false;
  81.             }
  82.         }
  83.         return true;
  84.     }
  85.     /**
  86.      * {@inheritDoc}
  87.      *
  88.      * @psalm-param class-string<T> $className
  89.      * @psalm-param ClassMetadata<T> $metadata
  90.      *
  91.      * @template T of object
  92.      */
  93.     public function loadMetadataForClass($classNamePersistenceClassMetadata $metadata): void
  94.     {
  95.         $reflectionClass $metadata->getReflectionClass();
  96.         $classAttributes $this->reader->getClassAnnotations($reflectionClass);
  97.         // Evaluate Entity annotation
  98.         if (isset($classAttributes[Mapping\Entity::class])) {
  99.             $entityAttribute $classAttributes[Mapping\Entity::class];
  100.             if ($entityAttribute->repositoryClass !== null) {
  101.                 $metadata->setCustomRepositoryClass($entityAttribute->repositoryClass);
  102.             }
  103.             if ($entityAttribute->readOnly) {
  104.                 $metadata->markReadOnly();
  105.             }
  106.         } elseif (isset($classAttributes[Mapping\MappedSuperclass::class])) {
  107.             $mappedSuperclassAttribute $classAttributes[Mapping\MappedSuperclass::class];
  108.             $metadata->setCustomRepositoryClass($mappedSuperclassAttribute->repositoryClass);
  109.             $metadata->isMappedSuperclass true;
  110.         } elseif (isset($classAttributes[Mapping\Embeddable::class])) {
  111.             $metadata->isEmbeddedClass true;
  112.         } else {
  113.             throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
  114.         }
  115.         $primaryTable = [];
  116.         if (isset($classAttributes[Mapping\Table::class])) {
  117.             $tableAnnot             $classAttributes[Mapping\Table::class];
  118.             $primaryTable['name']   = $tableAnnot->name;
  119.             $primaryTable['schema'] = $tableAnnot->schema;
  120.             if ($tableAnnot->options) {
  121.                 $primaryTable['options'] = $tableAnnot->options;
  122.             }
  123.         }
  124.         if (isset($classAttributes[Mapping\Index::class])) {
  125.             foreach ($classAttributes[Mapping\Index::class] as $idx => $indexAnnot) {
  126.                 $index = [];
  127.                 if (! empty($indexAnnot->columns)) {
  128.                     $index['columns'] = $indexAnnot->columns;
  129.                 }
  130.                 if (! empty($indexAnnot->fields)) {
  131.                     $index['fields'] = $indexAnnot->fields;
  132.                 }
  133.                 if (
  134.                     isset($index['columns'], $index['fields'])
  135.                     || (
  136.                         ! isset($index['columns'])
  137.                         && ! isset($index['fields'])
  138.                     )
  139.                 ) {
  140.                     throw MappingException::invalidIndexConfiguration(
  141.                         $className,
  142.                         (string) ($indexAnnot->name ?? $idx)
  143.                     );
  144.                 }
  145.                 if (! empty($indexAnnot->flags)) {
  146.                     $index['flags'] = $indexAnnot->flags;
  147.                 }
  148.                 if (! empty($indexAnnot->options)) {
  149.                     $index['options'] = $indexAnnot->options;
  150.                 }
  151.                 if (! empty($indexAnnot->name)) {
  152.                     $primaryTable['indexes'][$indexAnnot->name] = $index;
  153.                 } else {
  154.                     $primaryTable['indexes'][] = $index;
  155.                 }
  156.             }
  157.         }
  158.         if (isset($classAttributes[Mapping\UniqueConstraint::class])) {
  159.             foreach ($classAttributes[Mapping\UniqueConstraint::class] as $idx => $uniqueConstraintAnnot) {
  160.                 $uniqueConstraint = [];
  161.                 if (! empty($uniqueConstraintAnnot->columns)) {
  162.                     $uniqueConstraint['columns'] = $uniqueConstraintAnnot->columns;
  163.                 }
  164.                 if (! empty($uniqueConstraintAnnot->fields)) {
  165.                     $uniqueConstraint['fields'] = $uniqueConstraintAnnot->fields;
  166.                 }
  167.                 if (
  168.                     isset($uniqueConstraint['columns'], $uniqueConstraint['fields'])
  169.                     || (
  170.                         ! isset($uniqueConstraint['columns'])
  171.                         && ! isset($uniqueConstraint['fields'])
  172.                     )
  173.                 ) {
  174.                     throw MappingException::invalidUniqueConstraintConfiguration(
  175.                         $className,
  176.                         (string) ($uniqueConstraintAnnot->name ?? $idx)
  177.                     );
  178.                 }
  179.                 if (! empty($uniqueConstraintAnnot->options)) {
  180.                     $uniqueConstraint['options'] = $uniqueConstraintAnnot->options;
  181.                 }
  182.                 if (! empty($uniqueConstraintAnnot->name)) {
  183.                     $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
  184.                 } else {
  185.                     $primaryTable['uniqueConstraints'][] = $uniqueConstraint;
  186.                 }
  187.             }
  188.         }
  189.         $metadata->setPrimaryTable($primaryTable);
  190.         // Evaluate @Cache annotation
  191.         if (isset($classAttributes[Mapping\Cache::class])) {
  192.             $cacheAttribute $classAttributes[Mapping\Cache::class];
  193.             $cacheMap       = [
  194.                 'region' => $cacheAttribute->region,
  195.                 'usage'  => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' $cacheAttribute->usage),
  196.             ];
  197.             $metadata->enableCache($cacheMap);
  198.         }
  199.         // Evaluate InheritanceType annotation
  200.         if (isset($classAttributes[Mapping\InheritanceType::class])) {
  201.             $inheritanceTypeAttribute $classAttributes[Mapping\InheritanceType::class];
  202.             $metadata->setInheritanceType(
  203.                 constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' $inheritanceTypeAttribute->value)
  204.             );
  205.             if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
  206.                 // Evaluate DiscriminatorColumn annotation
  207.                 if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) {
  208.                     $discrColumnAttribute $classAttributes[Mapping\DiscriminatorColumn::class];
  209.                     $metadata->setDiscriminatorColumn(
  210.                         [
  211.                             'name'             => $discrColumnAttribute->name,
  212.                             'type'             => $discrColumnAttribute->type ?: 'string',
  213.                             'length'           => $discrColumnAttribute->length ?: 255,
  214.                             'columnDefinition' => $discrColumnAttribute->columnDefinition,
  215.                         ]
  216.                     );
  217.                 } else {
  218.                     $metadata->setDiscriminatorColumn(['name' => 'dtype''type' => 'string''length' => 255]);
  219.                 }
  220.                 // Evaluate DiscriminatorMap annotation
  221.                 if (isset($classAttributes[Mapping\DiscriminatorMap::class])) {
  222.                     $discrMapAttribute $classAttributes[Mapping\DiscriminatorMap::class];
  223.                     $metadata->setDiscriminatorMap($discrMapAttribute->value);
  224.                 }
  225.             }
  226.         }
  227.         // Evaluate DoctrineChangeTrackingPolicy annotation
  228.         if (isset($classAttributes[Mapping\ChangeTrackingPolicy::class])) {
  229.             $changeTrackingAttribute $classAttributes[Mapping\ChangeTrackingPolicy::class];
  230.             $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' $changeTrackingAttribute->value));
  231.         }
  232.         foreach ($reflectionClass->getProperties() as $property) {
  233.             assert($property instanceof ReflectionProperty);
  234.             if (
  235.                 $metadata->isMappedSuperclass && ! $property->isPrivate()
  236.                 ||
  237.                 $metadata->isInheritedField($property->name)
  238.                 ||
  239.                 $metadata->isInheritedAssociation($property->name)
  240.                 ||
  241.                 $metadata->isInheritedEmbeddedClass($property->name)
  242.             ) {
  243.                 continue;
  244.             }
  245.             $mapping              = [];
  246.             $mapping['fieldName'] = $property->getName();
  247.             // Evaluate @Cache annotation
  248.             $cacheAttribute $this->reader->getPropertyAnnotation($propertyMapping\Cache::class);
  249.             if ($cacheAttribute !== null) {
  250.                 assert($cacheAttribute instanceof Mapping\Cache);
  251.                 $mapping['cache'] = $metadata->getAssociationCacheDefaults(
  252.                     $mapping['fieldName'],
  253.                     [
  254.                         'usage'  => (int) constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' $cacheAttribute->usage),
  255.                         'region' => $cacheAttribute->region,
  256.                     ]
  257.                 );
  258.             }
  259.             // Check for JoinColumn/JoinColumns annotations
  260.             $joinColumns = [];
  261.             $joinColumnAttributes $this->reader->getPropertyAnnotationCollection($propertyMapping\JoinColumn::class);
  262.             foreach ($joinColumnAttributes as $joinColumnAttribute) {
  263.                 $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute);
  264.             }
  265.             // Field can only be attributed with one of:
  266.             // Column, OneToOne, OneToMany, ManyToOne, ManyToMany, Embedded
  267.             $columnAttribute     $this->reader->getPropertyAnnotation($propertyMapping\Column::class);
  268.             $oneToOneAttribute   $this->reader->getPropertyAnnotation($propertyMapping\OneToOne::class);
  269.             $oneToManyAttribute  $this->reader->getPropertyAnnotation($propertyMapping\OneToMany::class);
  270.             $manyToOneAttribute  $this->reader->getPropertyAnnotation($propertyMapping\ManyToOne::class);
  271.             $manyToManyAttribute $this->reader->getPropertyAnnotation($propertyMapping\ManyToMany::class);
  272.             $embeddedAttribute   $this->reader->getPropertyAnnotation($propertyMapping\Embedded::class);
  273.             if ($columnAttribute !== null) {
  274.                 $mapping $this->columnToArray($property->getName(), $columnAttribute);
  275.                 if ($this->reader->getPropertyAnnotation($propertyMapping\Id::class)) {
  276.                     $mapping['id'] = true;
  277.                 }
  278.                 $generatedValueAttribute $this->reader->getPropertyAnnotation($propertyMapping\GeneratedValue::class);
  279.                 if ($generatedValueAttribute !== null) {
  280.                     $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' $generatedValueAttribute->strategy));
  281.                 }
  282.                 if ($this->reader->getPropertyAnnotation($propertyMapping\Version::class)) {
  283.                     $metadata->setVersionMapping($mapping);
  284.                 }
  285.                 $metadata->mapField($mapping);
  286.                 // Check for SequenceGenerator/TableGenerator definition
  287.                 $seqGeneratorAttribute    $this->reader->getPropertyAnnotation($propertyMapping\SequenceGenerator::class);
  288.                 $customGeneratorAttribute $this->reader->getPropertyAnnotation($propertyMapping\CustomIdGenerator::class);
  289.                 if ($seqGeneratorAttribute !== null) {
  290.                     $metadata->setSequenceGeneratorDefinition(
  291.                         [
  292.                             'sequenceName' => $seqGeneratorAttribute->sequenceName,
  293.                             'allocationSize' => $seqGeneratorAttribute->allocationSize,
  294.                             'initialValue' => $seqGeneratorAttribute->initialValue,
  295.                         ]
  296.                     );
  297.                 } elseif ($customGeneratorAttribute !== null) {
  298.                     $metadata->setCustomGeneratorDefinition(
  299.                         [
  300.                             'class' => $customGeneratorAttribute->class,
  301.                         ]
  302.                     );
  303.                 }
  304.             } elseif ($oneToOneAttribute !== null) {
  305.                 if ($this->reader->getPropertyAnnotation($propertyMapping\Id::class)) {
  306.                     $mapping['id'] = true;
  307.                 }
  308.                 $mapping['targetEntity']  = $oneToOneAttribute->targetEntity;
  309.                 $mapping['joinColumns']   = $joinColumns;
  310.                 $mapping['mappedBy']      = $oneToOneAttribute->mappedBy;
  311.                 $mapping['inversedBy']    = $oneToOneAttribute->inversedBy;
  312.                 $mapping['cascade']       = $oneToOneAttribute->cascade;
  313.                 $mapping['orphanRemoval'] = $oneToOneAttribute->orphanRemoval;
  314.                 $mapping['fetch']         = $this->getFetchMode($className$oneToOneAttribute->fetch);
  315.                 $metadata->mapOneToOne($mapping);
  316.             } elseif ($oneToManyAttribute !== null) {
  317.                 $mapping['mappedBy']      = $oneToManyAttribute->mappedBy;
  318.                 $mapping['targetEntity']  = $oneToManyAttribute->targetEntity;
  319.                 $mapping['cascade']       = $oneToManyAttribute->cascade;
  320.                 $mapping['indexBy']       = $oneToManyAttribute->indexBy;
  321.                 $mapping['orphanRemoval'] = $oneToManyAttribute->orphanRemoval;
  322.                 $mapping['fetch']         = $this->getFetchMode($className$oneToManyAttribute->fetch);
  323.                 $orderByAttribute $this->reader->getPropertyAnnotation($propertyMapping\OrderBy::class);
  324.                 if ($orderByAttribute !== null) {
  325.                     $mapping['orderBy'] = $orderByAttribute->value;
  326.                 }
  327.                 $metadata->mapOneToMany($mapping);
  328.             } elseif ($manyToOneAttribute !== null) {
  329.                 $idAttribute $this->reader->getPropertyAnnotation($propertyMapping\Id::class);
  330.                 if ($idAttribute !== null) {
  331.                     $mapping['id'] = true;
  332.                 }
  333.                 $mapping['joinColumns']  = $joinColumns;
  334.                 $mapping['cascade']      = $manyToOneAttribute->cascade;
  335.                 $mapping['inversedBy']   = $manyToOneAttribute->inversedBy;
  336.                 $mapping['targetEntity'] = $manyToOneAttribute->targetEntity;
  337.                 $mapping['fetch']        = $this->getFetchMode($className$manyToOneAttribute->fetch);
  338.                 $metadata->mapManyToOne($mapping);
  339.             } elseif ($manyToManyAttribute !== null) {
  340.                 $joinTable          = [];
  341.                 $joinTableAttribute $this->reader->getPropertyAnnotation($propertyMapping\JoinTable::class);
  342.                 if ($joinTableAttribute !== null) {
  343.                     $joinTable = [
  344.                         'name' => $joinTableAttribute->name,
  345.                         'schema' => $joinTableAttribute->schema,
  346.                     ];
  347.                 }
  348.                 foreach ($this->reader->getPropertyAnnotationCollection($propertyMapping\JoinColumn::class) as $joinColumn) {
  349.                     $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
  350.                 }
  351.                 foreach ($this->reader->getPropertyAnnotationCollection($propertyMapping\InverseJoinColumn::class) as $joinColumn) {
  352.                     $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
  353.                 }
  354.                 $mapping['joinTable']     = $joinTable;
  355.                 $mapping['targetEntity']  = $manyToManyAttribute->targetEntity;
  356.                 $mapping['mappedBy']      = $manyToManyAttribute->mappedBy;
  357.                 $mapping['inversedBy']    = $manyToManyAttribute->inversedBy;
  358.                 $mapping['cascade']       = $manyToManyAttribute->cascade;
  359.                 $mapping['indexBy']       = $manyToManyAttribute->indexBy;
  360.                 $mapping['orphanRemoval'] = $manyToManyAttribute->orphanRemoval;
  361.                 $mapping['fetch']         = $this->getFetchMode($className$manyToManyAttribute->fetch);
  362.                 $orderByAttribute $this->reader->getPropertyAnnotation($propertyMapping\OrderBy::class);
  363.                 if ($orderByAttribute !== null) {
  364.                     $mapping['orderBy'] = $orderByAttribute->value;
  365.                 }
  366.                 $metadata->mapManyToMany($mapping);
  367.             } elseif ($embeddedAttribute !== null) {
  368.                 $mapping['class']        = $embeddedAttribute->class;
  369.                 $mapping['columnPrefix'] = $embeddedAttribute->columnPrefix;
  370.                 $metadata->mapEmbedded($mapping);
  371.             }
  372.         }
  373.         // Evaluate AssociationOverrides attribute
  374.         if (isset($classAttributes[Mapping\AssociationOverrides::class])) {
  375.             $associationOverride $classAttributes[Mapping\AssociationOverrides::class];
  376.             foreach ($associationOverride->overrides as $associationOverride) {
  377.                 $override  = [];
  378.                 $fieldName $associationOverride->name;
  379.                 // Check for JoinColumn/JoinColumns attributes
  380.                 if ($associationOverride->joinColumns) {
  381.                     $joinColumns = [];
  382.                     foreach ($associationOverride->joinColumns as $joinColumn) {
  383.                         $joinColumns[] = $this->joinColumnToArray($joinColumn);
  384.                     }
  385.                     $override['joinColumns'] = $joinColumns;
  386.                 }
  387.                 if ($associationOverride->inverseJoinColumns) {
  388.                     $joinColumns = [];
  389.                     foreach ($associationOverride->inverseJoinColumns as $joinColumn) {
  390.                         $joinColumns[] = $this->joinColumnToArray($joinColumn);
  391.                     }
  392.                     $override['inverseJoinColumns'] = $joinColumns;
  393.                 }
  394.                 // Check for JoinTable attributes
  395.                 if ($associationOverride->joinTable) {
  396.                     $joinTableAnnot $associationOverride->joinTable;
  397.                     $joinTable      = [
  398.                         'name'      => $joinTableAnnot->name,
  399.                         'schema'    => $joinTableAnnot->schema,
  400.                         'joinColumns' => $override['joinColumns'] ?? [],
  401.                         'inverseJoinColumns' => $override['inverseJoinColumns'] ?? [],
  402.                     ];
  403.                     unset($override['joinColumns'], $override['inverseJoinColumns']);
  404.                     $override['joinTable'] = $joinTable;
  405.                 }
  406.                 // Check for inversedBy
  407.                 if ($associationOverride->inversedBy) {
  408.                     $override['inversedBy'] = $associationOverride->inversedBy;
  409.                 }
  410.                 // Check for `fetch`
  411.                 if ($associationOverride->fetch) {
  412.                     $override['fetch'] = constant(ClassMetadata::class . '::FETCH_' $associationOverride->fetch);
  413.                 }
  414.                 $metadata->setAssociationOverride($fieldName$override);
  415.             }
  416.         }
  417.         // Evaluate AttributeOverrides annotation
  418.         if (isset($classAttributes[Mapping\AttributeOverrides::class])) {
  419.             $attributeOverridesAnnot $classAttributes[Mapping\AttributeOverrides::class];
  420.             foreach ($attributeOverridesAnnot->overrides as $attributeOverride) {
  421.                 $mapping $this->columnToArray($attributeOverride->name$attributeOverride->column);
  422.                 $metadata->setAttributeOverride($attributeOverride->name$mapping);
  423.             }
  424.         }
  425.         // Evaluate EntityListeners annotation
  426.         if (isset($classAttributes[Mapping\EntityListeners::class])) {
  427.             $entityListenersAttribute $classAttributes[Mapping\EntityListeners::class];
  428.             foreach ($entityListenersAttribute->value as $item) {
  429.                 $listenerClassName $metadata->fullyQualifiedClassName($item);
  430.                 if (! class_exists($listenerClassName)) {
  431.                     throw MappingException::entityListenerClassNotFound($listenerClassName$className);
  432.                 }
  433.                 $hasMapping    false;
  434.                 $listenerClass = new ReflectionClass($listenerClassName);
  435.                 foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
  436.                     assert($method instanceof ReflectionMethod);
  437.                     // find method callbacks.
  438.                     $callbacks  $this->getMethodCallbacks($method);
  439.                     $hasMapping $hasMapping ?: ! empty($callbacks);
  440.                     foreach ($callbacks as $value) {
  441.                         $metadata->addEntityListener($value[1], $listenerClassName$value[0]);
  442.                     }
  443.                 }
  444.                 // Evaluate the listener using naming convention.
  445.                 if (! $hasMapping) {
  446.                     EntityListenerBuilder::bindEntityListener($metadata$listenerClassName);
  447.                 }
  448.             }
  449.         }
  450.         // Evaluate @HasLifecycleCallbacks annotation
  451.         if (isset($classAttributes[Mapping\HasLifecycleCallbacks::class])) {
  452.             foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
  453.                 assert($method instanceof ReflectionMethod);
  454.                 foreach ($this->getMethodCallbacks($method) as $value) {
  455.                     $metadata->addLifecycleCallback($value[0], $value[1]);
  456.                 }
  457.             }
  458.         }
  459.     }
  460.     /**
  461.      * Attempts to resolve the fetch mode.
  462.      *
  463.      * @param string $className The class name.
  464.      * @param string $fetchMode The fetch mode.
  465.      *
  466.      * @return ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata.
  467.      *
  468.      * @throws MappingException If the fetch mode is not valid.
  469.      */
  470.     private function getFetchMode(string $classNamestring $fetchMode): int
  471.     {
  472.         if (! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' $fetchMode)) {
  473.             throw MappingException::invalidFetchMode($className$fetchMode);
  474.         }
  475.         return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' $fetchMode);
  476.     }
  477.     /**
  478.      * Attempts to resolve the generated mode.
  479.      *
  480.      * @throws MappingException If the fetch mode is not valid.
  481.      */
  482.     private function getGeneratedMode(string $generatedMode): int
  483.     {
  484.         if (! defined('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' $generatedMode)) {
  485.             throw MappingException::invalidGeneratedMode($generatedMode);
  486.         }
  487.         return constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' $generatedMode);
  488.     }
  489.     /**
  490.      * Parses the given method.
  491.      *
  492.      * @return callable[]
  493.      */
  494.     private function getMethodCallbacks(ReflectionMethod $method): array
  495.     {
  496.         $callbacks  = [];
  497.         $attributes $this->reader->getMethodAnnotations($method);
  498.         foreach ($attributes as $attribute) {
  499.             if ($attribute instanceof Mapping\PrePersist) {
  500.                 $callbacks[] = [$method->nameEvents::prePersist];
  501.             }
  502.             if ($attribute instanceof Mapping\PostPersist) {
  503.                 $callbacks[] = [$method->nameEvents::postPersist];
  504.             }
  505.             if ($attribute instanceof Mapping\PreUpdate) {
  506.                 $callbacks[] = [$method->nameEvents::preUpdate];
  507.             }
  508.             if ($attribute instanceof Mapping\PostUpdate) {
  509.                 $callbacks[] = [$method->nameEvents::postUpdate];
  510.             }
  511.             if ($attribute instanceof Mapping\PreRemove) {
  512.                 $callbacks[] = [$method->nameEvents::preRemove];
  513.             }
  514.             if ($attribute instanceof Mapping\PostRemove) {
  515.                 $callbacks[] = [$method->nameEvents::postRemove];
  516.             }
  517.             if ($attribute instanceof Mapping\PostLoad) {
  518.                 $callbacks[] = [$method->nameEvents::postLoad];
  519.             }
  520.             if ($attribute instanceof Mapping\PreFlush) {
  521.                 $callbacks[] = [$method->nameEvents::preFlush];
  522.             }
  523.         }
  524.         return $callbacks;
  525.     }
  526.     /**
  527.      * Parse the given JoinColumn as array
  528.      *
  529.      * @param Mapping\JoinColumn|Mapping\InverseJoinColumn $joinColumn
  530.      *
  531.      * @return mixed[]
  532.      * @psalm-return array{
  533.      *                   name: string|null,
  534.      *                   unique: bool,
  535.      *                   nullable: bool,
  536.      *                   onDelete: mixed,
  537.      *                   columnDefinition: string|null,
  538.      *                   referencedColumnName: string
  539.      *               }
  540.      */
  541.     private function joinColumnToArray($joinColumn): array
  542.     {
  543.         return [
  544.             'name' => $joinColumn->name,
  545.             'unique' => $joinColumn->unique,
  546.             'nullable' => $joinColumn->nullable,
  547.             'onDelete' => $joinColumn->onDelete,
  548.             'columnDefinition' => $joinColumn->columnDefinition,
  549.             'referencedColumnName' => $joinColumn->referencedColumnName,
  550.         ];
  551.     }
  552.     /**
  553.      * Parse the given Column as array
  554.      *
  555.      * @return mixed[]
  556.      * @psalm-return array{
  557.      *                   fieldName: string,
  558.      *                   type: mixed,
  559.      *                   scale: int,
  560.      *                   length: int,
  561.      *                   unique: bool,
  562.      *                   nullable: bool,
  563.      *                   precision: int,
  564.      *                   enumType?: class-string,
  565.      *                   options?: mixed[],
  566.      *                   columnName?: string,
  567.      *                   columnDefinition?: string
  568.      *               }
  569.      */
  570.     private function columnToArray(string $fieldNameMapping\Column $column): array
  571.     {
  572.         $mapping = [
  573.             'fieldName' => $fieldName,
  574.             'type'      => $column->type,
  575.             'scale'     => $column->scale,
  576.             'length'    => $column->length,
  577.             'unique'    => $column->unique,
  578.             'nullable'  => $column->nullable,
  579.             'precision' => $column->precision,
  580.         ];
  581.         if ($column->options) {
  582.             $mapping['options'] = $column->options;
  583.         }
  584.         if (isset($column->name)) {
  585.             $mapping['columnName'] = $column->name;
  586.         }
  587.         if (isset($column->columnDefinition)) {
  588.             $mapping['columnDefinition'] = $column->columnDefinition;
  589.         }
  590.         if ($column->updatable === false) {
  591.             $mapping['notUpdatable'] = true;
  592.         }
  593.         if ($column->insertable === false) {
  594.             $mapping['notInsertable'] = true;
  595.         }
  596.         if ($column->generated !== null) {
  597.             $mapping['generated'] = $this->getGeneratedMode($column->generated);
  598.         }
  599.         if ($column->enumType) {
  600.             $mapping['enumType'] = $column->enumType;
  601.         }
  602.         return $mapping;
  603.     }
  604. }