AnnotationDriver.php
9 months ago
AttributeDriver.php
9 months ago
AttributeReader.php
9 months ago
CompatibilityAnnotationDriver.php
9 months ago
DriverChain.php
9 months ago
PHPDriver.php
9 months ago
ReflectionBasedDriver.php
9 months ago
RepeatableAttributeCollection.php
9 months ago
StaticPHPDriver.php
9 months ago
index.php
9 months ago
AttributeDriver.php
457 lines
| 1 | <?php |
| 2 | declare (strict_types=1); |
| 3 | namespace MailPoetVendor\Doctrine\ORM\Mapping\Driver; |
| 4 | if (!defined('ABSPATH')) exit; |
| 5 | use MailPoetVendor\Doctrine\Deprecations\Deprecation; |
| 6 | use MailPoetVendor\Doctrine\ORM\Events; |
| 7 | use MailPoetVendor\Doctrine\ORM\Mapping; |
| 8 | use MailPoetVendor\Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; |
| 9 | use MailPoetVendor\Doctrine\ORM\Mapping\ClassMetadata; |
| 10 | use MailPoetVendor\Doctrine\ORM\Mapping\MappingAttribute; |
| 11 | use MailPoetVendor\Doctrine\ORM\Mapping\MappingException; |
| 12 | use MailPoetVendor\Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata; |
| 13 | use MailPoetVendor\Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver; |
| 14 | use LogicException; |
| 15 | use ReflectionClass; |
| 16 | use ReflectionMethod; |
| 17 | use function class_exists; |
| 18 | use function constant; |
| 19 | use function defined; |
| 20 | use function get_class; |
| 21 | use const PHP_VERSION_ID; |
| 22 | class AttributeDriver extends CompatibilityAnnotationDriver |
| 23 | { |
| 24 | use ColocatedMappingDriver; |
| 25 | use ReflectionBasedDriver; |
| 26 | private const ENTITY_ATTRIBUTE_CLASSES = [Mapping\Entity::class => 1, Mapping\MappedSuperclass::class => 2]; |
| 27 | protected $entityAnnotationClasses = self::ENTITY_ATTRIBUTE_CLASSES; |
| 28 | protected $reader; |
| 29 | public function __construct(array $paths, bool $reportFieldsWhereDeclared = \false) |
| 30 | { |
| 31 | if (PHP_VERSION_ID < 80000) { |
| 32 | throw new LogicException('The attribute metadata driver cannot be enabled on PHP 7. Please upgrade to PHP 8 or choose a different' . ' metadata driver.'); |
| 33 | } |
| 34 | $this->reader = new AttributeReader(); |
| 35 | $this->addPaths($paths); |
| 36 | // @phpstan-ignore property.deprecated |
| 37 | if ($this->entityAnnotationClasses !== self::ENTITY_ATTRIBUTE_CLASSES) { |
| 38 | Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/10204', 'Changing the value of %s::$entityAnnotationClasses is deprecated and will have no effect in Doctrine ORM 3.0.', self::class); |
| 39 | } |
| 40 | if (!$reportFieldsWhereDeclared) { |
| 41 | Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/10455', 'In ORM 3.0, the AttributeDriver will report fields for the classes where they are declared. This may uncover invalid mapping configurations. To opt into the new mode today, set the "reportFieldsWhereDeclared" constructor parameter to true.', self::class); |
| 42 | } |
| 43 | $this->reportFieldsWhereDeclared = $reportFieldsWhereDeclared; |
| 44 | } |
| 45 | public function getReader() |
| 46 | { |
| 47 | Deprecation::trigger('doctrine/orm', 'https://github.com/doctrine/orm/pull/9587', '%s is deprecated with no replacement', __METHOD__); |
| 48 | return $this->reader; |
| 49 | } |
| 50 | public function isTransient($className) |
| 51 | { |
| 52 | $classAttributes = $this->reader->getClassAttributes(new ReflectionClass($className)); |
| 53 | foreach ($classAttributes as $a) { |
| 54 | $attr = $a instanceof RepeatableAttributeCollection ? $a[0] : $a; |
| 55 | // @phpstan-ignore property.deprecated |
| 56 | if (isset($this->entityAnnotationClasses[get_class($attr)])) { |
| 57 | return \false; |
| 58 | } |
| 59 | } |
| 60 | return \true; |
| 61 | } |
| 62 | public function loadMetadataForClass($className, PersistenceClassMetadata $metadata) : void |
| 63 | { |
| 64 | $reflectionClass = $metadata->getReflectionClass() ?? new ReflectionClass($metadata->name); |
| 65 | $classAttributes = $this->reader->getClassAttributes($reflectionClass); |
| 66 | // Evaluate Entity attribute |
| 67 | if (isset($classAttributes[Mapping\Entity::class])) { |
| 68 | $entityAttribute = $classAttributes[Mapping\Entity::class]; |
| 69 | if ($entityAttribute->repositoryClass !== null) { |
| 70 | $metadata->setCustomRepositoryClass($entityAttribute->repositoryClass); |
| 71 | } |
| 72 | if ($entityAttribute->readOnly) { |
| 73 | $metadata->markReadOnly(); |
| 74 | } |
| 75 | } elseif (isset($classAttributes[Mapping\MappedSuperclass::class])) { |
| 76 | $mappedSuperclassAttribute = $classAttributes[Mapping\MappedSuperclass::class]; |
| 77 | $metadata->setCustomRepositoryClass($mappedSuperclassAttribute->repositoryClass); |
| 78 | $metadata->isMappedSuperclass = \true; |
| 79 | } elseif (isset($classAttributes[Mapping\Embeddable::class])) { |
| 80 | $metadata->isEmbeddedClass = \true; |
| 81 | } else { |
| 82 | throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className); |
| 83 | } |
| 84 | $primaryTable = []; |
| 85 | if (isset($classAttributes[Mapping\Table::class])) { |
| 86 | $tableAnnot = $classAttributes[Mapping\Table::class]; |
| 87 | $primaryTable['name'] = $tableAnnot->name; |
| 88 | $primaryTable['schema'] = $tableAnnot->schema; |
| 89 | if ($tableAnnot->options) { |
| 90 | $primaryTable['options'] = $tableAnnot->options; |
| 91 | } |
| 92 | } |
| 93 | if (isset($classAttributes[Mapping\Index::class])) { |
| 94 | foreach ($classAttributes[Mapping\Index::class] as $idx => $indexAnnot) { |
| 95 | $index = []; |
| 96 | if (!empty($indexAnnot->columns)) { |
| 97 | $index['columns'] = $indexAnnot->columns; |
| 98 | } |
| 99 | if (!empty($indexAnnot->fields)) { |
| 100 | $index['fields'] = $indexAnnot->fields; |
| 101 | } |
| 102 | if (isset($index['columns'], $index['fields']) || !isset($index['columns']) && !isset($index['fields'])) { |
| 103 | throw MappingException::invalidIndexConfiguration($className, (string) ($indexAnnot->name ?? $idx)); |
| 104 | } |
| 105 | if (!empty($indexAnnot->flags)) { |
| 106 | $index['flags'] = $indexAnnot->flags; |
| 107 | } |
| 108 | if (!empty($indexAnnot->options)) { |
| 109 | $index['options'] = $indexAnnot->options; |
| 110 | } |
| 111 | if (!empty($indexAnnot->name)) { |
| 112 | $primaryTable['indexes'][$indexAnnot->name] = $index; |
| 113 | } else { |
| 114 | $primaryTable['indexes'][] = $index; |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | if (isset($classAttributes[Mapping\UniqueConstraint::class])) { |
| 119 | foreach ($classAttributes[Mapping\UniqueConstraint::class] as $idx => $uniqueConstraintAnnot) { |
| 120 | $uniqueConstraint = []; |
| 121 | if (!empty($uniqueConstraintAnnot->columns)) { |
| 122 | $uniqueConstraint['columns'] = $uniqueConstraintAnnot->columns; |
| 123 | } |
| 124 | if (!empty($uniqueConstraintAnnot->fields)) { |
| 125 | $uniqueConstraint['fields'] = $uniqueConstraintAnnot->fields; |
| 126 | } |
| 127 | if (isset($uniqueConstraint['columns'], $uniqueConstraint['fields']) || !isset($uniqueConstraint['columns']) && !isset($uniqueConstraint['fields'])) { |
| 128 | throw MappingException::invalidUniqueConstraintConfiguration($className, (string) ($uniqueConstraintAnnot->name ?? $idx)); |
| 129 | } |
| 130 | if (!empty($uniqueConstraintAnnot->options)) { |
| 131 | $uniqueConstraint['options'] = $uniqueConstraintAnnot->options; |
| 132 | } |
| 133 | if (!empty($uniqueConstraintAnnot->name)) { |
| 134 | $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint; |
| 135 | } else { |
| 136 | $primaryTable['uniqueConstraints'][] = $uniqueConstraint; |
| 137 | } |
| 138 | } |
| 139 | } |
| 140 | $metadata->setPrimaryTable($primaryTable); |
| 141 | // Evaluate #[Cache] attribute |
| 142 | if (isset($classAttributes[Mapping\Cache::class])) { |
| 143 | $cacheAttribute = $classAttributes[Mapping\Cache::class]; |
| 144 | $cacheMap = ['region' => $cacheAttribute->region, 'usage' => constant('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::CACHE_USAGE_' . $cacheAttribute->usage)]; |
| 145 | $metadata->enableCache($cacheMap); |
| 146 | } |
| 147 | // Evaluate InheritanceType attribute |
| 148 | if (isset($classAttributes[Mapping\InheritanceType::class])) { |
| 149 | $inheritanceTypeAttribute = $classAttributes[Mapping\InheritanceType::class]; |
| 150 | $metadata->setInheritanceType(constant('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAttribute->value)); |
| 151 | if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { |
| 152 | // Evaluate DiscriminatorColumn attribute |
| 153 | if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) { |
| 154 | $discrColumnAttribute = $classAttributes[Mapping\DiscriminatorColumn::class]; |
| 155 | $columnDef = ['name' => isset($discrColumnAttribute->name) ? (string) $discrColumnAttribute->name : null, 'type' => isset($discrColumnAttribute->type) ? (string) $discrColumnAttribute->type : 'string', 'length' => isset($discrColumnAttribute->length) ? (int) $discrColumnAttribute->length : 255, 'columnDefinition' => isset($discrColumnAttribute->columnDefinition) ? (string) $discrColumnAttribute->columnDefinition : null, 'enumType' => isset($discrColumnAttribute->enumType) ? (string) $discrColumnAttribute->enumType : null]; |
| 156 | if ($discrColumnAttribute->options) { |
| 157 | $columnDef['options'] = (array) $discrColumnAttribute->options; |
| 158 | } |
| 159 | $metadata->setDiscriminatorColumn($columnDef); |
| 160 | } else { |
| 161 | $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]); |
| 162 | } |
| 163 | // Evaluate DiscriminatorMap attribute |
| 164 | if (isset($classAttributes[Mapping\DiscriminatorMap::class])) { |
| 165 | $discrMapAttribute = $classAttributes[Mapping\DiscriminatorMap::class]; |
| 166 | $metadata->setDiscriminatorMap($discrMapAttribute->value); |
| 167 | } |
| 168 | } |
| 169 | } |
| 170 | // Evaluate DoctrineChangeTrackingPolicy attribute |
| 171 | if (isset($classAttributes[Mapping\ChangeTrackingPolicy::class])) { |
| 172 | $changeTrackingAttribute = $classAttributes[Mapping\ChangeTrackingPolicy::class]; |
| 173 | $metadata->setChangeTrackingPolicy(constant('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::CHANGETRACKING_' . $changeTrackingAttribute->value)); |
| 174 | } |
| 175 | foreach ($reflectionClass->getProperties() as $property) { |
| 176 | if ($this->isRepeatedPropertyDeclaration($property, $metadata)) { |
| 177 | continue; |
| 178 | } |
| 179 | $mapping = []; |
| 180 | $mapping['fieldName'] = $property->name; |
| 181 | // Evaluate #[Cache] attribute |
| 182 | $cacheAttribute = $this->reader->getPropertyAttribute($property, Mapping\Cache::class); |
| 183 | if ($cacheAttribute !== null) { |
| 184 | $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], ['usage' => (int) constant('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::CACHE_USAGE_' . $cacheAttribute->usage), 'region' => $cacheAttribute->region]); |
| 185 | } |
| 186 | // Check for JoinColumn/JoinColumns attributes |
| 187 | $joinColumns = []; |
| 188 | $joinColumnAttributes = $this->reader->getPropertyAttributeCollection($property, Mapping\JoinColumn::class); |
| 189 | foreach ($joinColumnAttributes as $joinColumnAttribute) { |
| 190 | $joinColumns[] = $this->joinColumnToArray($joinColumnAttribute); |
| 191 | } |
| 192 | // Field can only be attributed with one of: |
| 193 | // Column, OneToOne, OneToMany, ManyToOne, ManyToMany, Embedded |
| 194 | $columnAttribute = $this->reader->getPropertyAttribute($property, Mapping\Column::class); |
| 195 | $oneToOneAttribute = $this->reader->getPropertyAttribute($property, Mapping\OneToOne::class); |
| 196 | $oneToManyAttribute = $this->reader->getPropertyAttribute($property, Mapping\OneToMany::class); |
| 197 | $manyToOneAttribute = $this->reader->getPropertyAttribute($property, Mapping\ManyToOne::class); |
| 198 | $manyToManyAttribute = $this->reader->getPropertyAttribute($property, Mapping\ManyToMany::class); |
| 199 | $embeddedAttribute = $this->reader->getPropertyAttribute($property, Mapping\Embedded::class); |
| 200 | if ($columnAttribute !== null) { |
| 201 | $mapping = $this->columnToArray($property->name, $columnAttribute); |
| 202 | if ($this->reader->getPropertyAttribute($property, Mapping\Id::class)) { |
| 203 | $mapping['id'] = \true; |
| 204 | } |
| 205 | $generatedValueAttribute = $this->reader->getPropertyAttribute($property, Mapping\GeneratedValue::class); |
| 206 | if ($generatedValueAttribute !== null) { |
| 207 | $metadata->setIdGeneratorType(constant('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAttribute->strategy)); |
| 208 | } |
| 209 | if ($this->reader->getPropertyAttribute($property, Mapping\Version::class)) { |
| 210 | $metadata->setVersionMapping($mapping); |
| 211 | } |
| 212 | $metadata->mapField($mapping); |
| 213 | // Check for SequenceGenerator/TableGenerator definition |
| 214 | $seqGeneratorAttribute = $this->reader->getPropertyAttribute($property, Mapping\SequenceGenerator::class); |
| 215 | $customGeneratorAttribute = $this->reader->getPropertyAttribute($property, Mapping\CustomIdGenerator::class); |
| 216 | if ($seqGeneratorAttribute !== null) { |
| 217 | $metadata->setSequenceGeneratorDefinition(['sequenceName' => $seqGeneratorAttribute->sequenceName, 'allocationSize' => $seqGeneratorAttribute->allocationSize, 'initialValue' => $seqGeneratorAttribute->initialValue]); |
| 218 | } elseif ($customGeneratorAttribute !== null) { |
| 219 | $metadata->setCustomGeneratorDefinition(['class' => $customGeneratorAttribute->class]); |
| 220 | } |
| 221 | } elseif ($oneToOneAttribute !== null) { |
| 222 | if ($this->reader->getPropertyAttribute($property, Mapping\Id::class)) { |
| 223 | $mapping['id'] = \true; |
| 224 | } |
| 225 | $mapping['targetEntity'] = $oneToOneAttribute->targetEntity; |
| 226 | $mapping['joinColumns'] = $joinColumns; |
| 227 | $mapping['mappedBy'] = $oneToOneAttribute->mappedBy; |
| 228 | $mapping['inversedBy'] = $oneToOneAttribute->inversedBy; |
| 229 | $mapping['cascade'] = $oneToOneAttribute->cascade; |
| 230 | $mapping['orphanRemoval'] = $oneToOneAttribute->orphanRemoval; |
| 231 | $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAttribute->fetch); |
| 232 | $metadata->mapOneToOne($mapping); |
| 233 | } elseif ($oneToManyAttribute !== null) { |
| 234 | $mapping['mappedBy'] = $oneToManyAttribute->mappedBy; |
| 235 | $mapping['targetEntity'] = $oneToManyAttribute->targetEntity; |
| 236 | $mapping['cascade'] = $oneToManyAttribute->cascade; |
| 237 | $mapping['indexBy'] = $oneToManyAttribute->indexBy; |
| 238 | $mapping['orphanRemoval'] = $oneToManyAttribute->orphanRemoval; |
| 239 | $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAttribute->fetch); |
| 240 | $orderByAttribute = $this->reader->getPropertyAttribute($property, Mapping\OrderBy::class); |
| 241 | if ($orderByAttribute !== null) { |
| 242 | $mapping['orderBy'] = $orderByAttribute->value; |
| 243 | } |
| 244 | $metadata->mapOneToMany($mapping); |
| 245 | } elseif ($manyToOneAttribute !== null) { |
| 246 | $idAttribute = $this->reader->getPropertyAttribute($property, Mapping\Id::class); |
| 247 | if ($idAttribute !== null) { |
| 248 | $mapping['id'] = \true; |
| 249 | } |
| 250 | $mapping['joinColumns'] = $joinColumns; |
| 251 | $mapping['cascade'] = $manyToOneAttribute->cascade; |
| 252 | $mapping['inversedBy'] = $manyToOneAttribute->inversedBy; |
| 253 | $mapping['targetEntity'] = $manyToOneAttribute->targetEntity; |
| 254 | $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAttribute->fetch); |
| 255 | $metadata->mapManyToOne($mapping); |
| 256 | } elseif ($manyToManyAttribute !== null) { |
| 257 | $joinTable = []; |
| 258 | $joinTableAttribute = $this->reader->getPropertyAttribute($property, Mapping\JoinTable::class); |
| 259 | if ($joinTableAttribute !== null) { |
| 260 | $joinTable = ['name' => $joinTableAttribute->name, 'schema' => $joinTableAttribute->schema]; |
| 261 | if ($joinTableAttribute->options) { |
| 262 | $joinTable['options'] = $joinTableAttribute->options; |
| 263 | } |
| 264 | foreach ($joinTableAttribute->joinColumns as $joinColumn) { |
| 265 | $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn); |
| 266 | } |
| 267 | foreach ($joinTableAttribute->inverseJoinColumns as $joinColumn) { |
| 268 | $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn); |
| 269 | } |
| 270 | } |
| 271 | foreach ($this->reader->getPropertyAttributeCollection($property, Mapping\JoinColumn::class) as $joinColumn) { |
| 272 | $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn); |
| 273 | } |
| 274 | foreach ($this->reader->getPropertyAttributeCollection($property, Mapping\InverseJoinColumn::class) as $joinColumn) { |
| 275 | $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn); |
| 276 | } |
| 277 | $mapping['joinTable'] = $joinTable; |
| 278 | $mapping['targetEntity'] = $manyToManyAttribute->targetEntity; |
| 279 | $mapping['mappedBy'] = $manyToManyAttribute->mappedBy; |
| 280 | $mapping['inversedBy'] = $manyToManyAttribute->inversedBy; |
| 281 | $mapping['cascade'] = $manyToManyAttribute->cascade; |
| 282 | $mapping['indexBy'] = $manyToManyAttribute->indexBy; |
| 283 | $mapping['orphanRemoval'] = $manyToManyAttribute->orphanRemoval; |
| 284 | $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAttribute->fetch); |
| 285 | $orderByAttribute = $this->reader->getPropertyAttribute($property, Mapping\OrderBy::class); |
| 286 | if ($orderByAttribute !== null) { |
| 287 | $mapping['orderBy'] = $orderByAttribute->value; |
| 288 | } |
| 289 | $metadata->mapManyToMany($mapping); |
| 290 | } elseif ($embeddedAttribute !== null) { |
| 291 | $mapping['class'] = $embeddedAttribute->class; |
| 292 | $mapping['columnPrefix'] = $embeddedAttribute->columnPrefix; |
| 293 | $metadata->mapEmbedded($mapping); |
| 294 | } |
| 295 | } |
| 296 | // Evaluate AssociationOverrides attribute |
| 297 | if (isset($classAttributes[Mapping\AssociationOverrides::class])) { |
| 298 | $associationOverride = $classAttributes[Mapping\AssociationOverrides::class]; |
| 299 | foreach ($associationOverride->overrides as $associationOverride) { |
| 300 | $override = []; |
| 301 | $fieldName = $associationOverride->name; |
| 302 | // Check for JoinColumn/JoinColumns attributes |
| 303 | if ($associationOverride->joinColumns) { |
| 304 | $joinColumns = []; |
| 305 | foreach ($associationOverride->joinColumns as $joinColumn) { |
| 306 | $joinColumns[] = $this->joinColumnToArray($joinColumn); |
| 307 | } |
| 308 | $override['joinColumns'] = $joinColumns; |
| 309 | } |
| 310 | if ($associationOverride->inverseJoinColumns) { |
| 311 | $joinColumns = []; |
| 312 | foreach ($associationOverride->inverseJoinColumns as $joinColumn) { |
| 313 | $joinColumns[] = $this->joinColumnToArray($joinColumn); |
| 314 | } |
| 315 | $override['inverseJoinColumns'] = $joinColumns; |
| 316 | } |
| 317 | // Check for JoinTable attributes |
| 318 | if ($associationOverride->joinTable) { |
| 319 | $joinTableAnnot = $associationOverride->joinTable; |
| 320 | $joinTable = ['name' => $joinTableAnnot->name, 'schema' => $joinTableAnnot->schema, 'joinColumns' => $override['joinColumns'] ?? [], 'inverseJoinColumns' => $override['inverseJoinColumns'] ?? []]; |
| 321 | unset($override['joinColumns'], $override['inverseJoinColumns']); |
| 322 | $override['joinTable'] = $joinTable; |
| 323 | } |
| 324 | // Check for inversedBy |
| 325 | if ($associationOverride->inversedBy) { |
| 326 | $override['inversedBy'] = $associationOverride->inversedBy; |
| 327 | } |
| 328 | // Check for `fetch` |
| 329 | if ($associationOverride->fetch) { |
| 330 | $override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . $associationOverride->fetch); |
| 331 | } |
| 332 | $metadata->setAssociationOverride($fieldName, $override); |
| 333 | } |
| 334 | } |
| 335 | // Evaluate AttributeOverrides attribute |
| 336 | if (isset($classAttributes[Mapping\AttributeOverrides::class])) { |
| 337 | $attributeOverridesAnnot = $classAttributes[Mapping\AttributeOverrides::class]; |
| 338 | foreach ($attributeOverridesAnnot->overrides as $attributeOverride) { |
| 339 | $mapping = $this->columnToArray($attributeOverride->name, $attributeOverride->column); |
| 340 | $metadata->setAttributeOverride($attributeOverride->name, $mapping); |
| 341 | } |
| 342 | } |
| 343 | // Evaluate EntityListeners attribute |
| 344 | if (isset($classAttributes[Mapping\EntityListeners::class])) { |
| 345 | $entityListenersAttribute = $classAttributes[Mapping\EntityListeners::class]; |
| 346 | foreach ($entityListenersAttribute->value as $item) { |
| 347 | $listenerClassName = $metadata->fullyQualifiedClassName($item); |
| 348 | if (!class_exists($listenerClassName)) { |
| 349 | throw MappingException::entityListenerClassNotFound($listenerClassName, $className); |
| 350 | } |
| 351 | $hasMapping = \false; |
| 352 | $listenerClass = new ReflectionClass($listenerClassName); |
| 353 | foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { |
| 354 | // find method callbacks. |
| 355 | $callbacks = $this->getMethodCallbacks($method); |
| 356 | $hasMapping = $hasMapping ?: !empty($callbacks); |
| 357 | foreach ($callbacks as $value) { |
| 358 | $metadata->addEntityListener($value[1], $listenerClassName, $value[0]); |
| 359 | } |
| 360 | } |
| 361 | // Evaluate the listener using naming convention. |
| 362 | if (!$hasMapping) { |
| 363 | EntityListenerBuilder::bindEntityListener($metadata, $listenerClassName); |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | // Evaluate #[HasLifecycleCallbacks] attribute |
| 368 | if (isset($classAttributes[Mapping\HasLifecycleCallbacks::class])) { |
| 369 | foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { |
| 370 | foreach ($this->getMethodCallbacks($method) as $value) { |
| 371 | $metadata->addLifecycleCallback($value[0], $value[1]); |
| 372 | } |
| 373 | } |
| 374 | } |
| 375 | } |
| 376 | private function getFetchMode(string $className, string $fetchMode) : int |
| 377 | { |
| 378 | if (!defined('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::FETCH_' . $fetchMode)) { |
| 379 | throw MappingException::invalidFetchMode($className, $fetchMode); |
| 380 | } |
| 381 | return constant('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::FETCH_' . $fetchMode); |
| 382 | } |
| 383 | private function getGeneratedMode(string $generatedMode) : int |
| 384 | { |
| 385 | if (!defined('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::GENERATED_' . $generatedMode)) { |
| 386 | throw MappingException::invalidGeneratedMode($generatedMode); |
| 387 | } |
| 388 | return constant('MailPoetVendor\\Doctrine\\ORM\\Mapping\\ClassMetadata::GENERATED_' . $generatedMode); |
| 389 | } |
| 390 | private function getMethodCallbacks(ReflectionMethod $method) : array |
| 391 | { |
| 392 | $callbacks = []; |
| 393 | $attributes = $this->reader->getMethodAttributes($method); |
| 394 | foreach ($attributes as $attribute) { |
| 395 | if ($attribute instanceof Mapping\PrePersist) { |
| 396 | $callbacks[] = [$method->name, Events::prePersist]; |
| 397 | } |
| 398 | if ($attribute instanceof Mapping\PostPersist) { |
| 399 | $callbacks[] = [$method->name, Events::postPersist]; |
| 400 | } |
| 401 | if ($attribute instanceof Mapping\PreUpdate) { |
| 402 | $callbacks[] = [$method->name, Events::preUpdate]; |
| 403 | } |
| 404 | if ($attribute instanceof Mapping\PostUpdate) { |
| 405 | $callbacks[] = [$method->name, Events::postUpdate]; |
| 406 | } |
| 407 | if ($attribute instanceof Mapping\PreRemove) { |
| 408 | $callbacks[] = [$method->name, Events::preRemove]; |
| 409 | } |
| 410 | if ($attribute instanceof Mapping\PostRemove) { |
| 411 | $callbacks[] = [$method->name, Events::postRemove]; |
| 412 | } |
| 413 | if ($attribute instanceof Mapping\PostLoad) { |
| 414 | $callbacks[] = [$method->name, Events::postLoad]; |
| 415 | } |
| 416 | if ($attribute instanceof Mapping\PreFlush) { |
| 417 | $callbacks[] = [$method->name, Events::preFlush]; |
| 418 | } |
| 419 | } |
| 420 | return $callbacks; |
| 421 | } |
| 422 | private function joinColumnToArray($joinColumn) : array |
| 423 | { |
| 424 | $mapping = ['name' => $joinColumn->name, 'unique' => $joinColumn->unique, 'nullable' => $joinColumn->nullable, 'onDelete' => $joinColumn->onDelete, 'columnDefinition' => $joinColumn->columnDefinition, 'referencedColumnName' => $joinColumn->referencedColumnName]; |
| 425 | if ($joinColumn->options) { |
| 426 | $mapping['options'] = $joinColumn->options; |
| 427 | } |
| 428 | return $mapping; |
| 429 | } |
| 430 | private function columnToArray(string $fieldName, Mapping\Column $column) : array |
| 431 | { |
| 432 | $mapping = ['fieldName' => $fieldName, 'type' => $column->type, 'scale' => $column->scale, 'length' => $column->length, 'unique' => $column->unique, 'nullable' => $column->nullable, 'precision' => $column->precision]; |
| 433 | if ($column->options) { |
| 434 | $mapping['options'] = $column->options; |
| 435 | } |
| 436 | if (isset($column->name)) { |
| 437 | $mapping['columnName'] = $column->name; |
| 438 | } |
| 439 | if (isset($column->columnDefinition)) { |
| 440 | $mapping['columnDefinition'] = $column->columnDefinition; |
| 441 | } |
| 442 | if ($column->updatable === \false) { |
| 443 | $mapping['notUpdatable'] = \true; |
| 444 | } |
| 445 | if ($column->insertable === \false) { |
| 446 | $mapping['notInsertable'] = \true; |
| 447 | } |
| 448 | if ($column->generated !== null) { |
| 449 | $mapping['generated'] = $this->getGeneratedMode($column->generated); |
| 450 | } |
| 451 | if ($column->enumType) { |
| 452 | $mapping['enumType'] = $column->enumType; |
| 453 | } |
| 454 | return $mapping; |
| 455 | } |
| 456 | } |
| 457 |