Complex classes like ClassMetadataFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ClassMetadataFactory, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 32 | class ClassMetadataFactory extends AbstractClassMetadataFactory |
||
| 33 | { |
||
| 34 | /** |
||
| 35 | * @var EntityManagerInterface|null |
||
| 36 | */ |
||
| 37 | private $em; |
||
| 38 | |||
| 39 | /** |
||
| 40 | * @var \Doctrine\DBAL\Platforms\AbstractPlatform |
||
| 41 | */ |
||
| 42 | private $targetPlatform; |
||
| 43 | |||
| 44 | /** |
||
| 45 | * @var Driver\MappingDriver |
||
| 46 | */ |
||
| 47 | private $driver; |
||
| 48 | |||
| 49 | /** |
||
| 50 | * @var \Doctrine\Common\EventManager |
||
| 51 | */ |
||
| 52 | private $evm; |
||
| 53 | |||
| 54 | /** |
||
| 55 | * @var array |
||
| 56 | */ |
||
| 57 | private $embeddablesActiveNesting = []; |
||
| 58 | |||
| 59 | /** |
||
| 60 | * {@inheritDoc} |
||
| 61 | */ |
||
| 62 | protected function loadMetadata(string $name, ClassMetadataBuildingContext $metadataBuildingContext) |
||
| 63 | { |
||
| 64 | $loaded = parent::loadMetadata($name, $metadataBuildingContext); |
||
| 65 | |||
| 66 | array_map([$this, 'resolveDiscriminatorValue'], array_map([$this, 'getMetadataFor'], $loaded)); |
||
| 67 | |||
| 68 | return $loaded; |
||
| 69 | } |
||
| 70 | |||
| 71 | /** |
||
| 72 | * @param EntityManagerInterface $em |
||
| 73 | */ |
||
| 74 | public function setEntityManager(EntityManagerInterface $em) |
||
| 78 | |||
| 79 | 380 | /** |
|
| 80 | * {@inheritDoc} |
||
| 81 | 380 | */ |
|
| 82 | protected function initialize() |
||
| 88 | |||
| 89 | 2292 | /** |
|
| 90 | 2292 | * {@inheritDoc} |
|
| 91 | */ |
||
| 92 | protected function onNotFoundMetadata($className, ClassMetadataBuildingContext $metadataBuildingContext) |
||
| 93 | { |
||
| 94 | if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) { |
||
| 95 | 465 | return; |
|
| 96 | } |
||
| 97 | 465 | ||
| 98 | 465 | $eventArgs = new OnClassMetadataNotFoundEventArgs($className, $metadataBuildingContext, $this->em); |
|
|
|
|||
| 99 | 465 | ||
| 100 | 465 | $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs); |
|
| 101 | |||
| 102 | return $eventArgs->getFoundMetadata(); |
||
| 103 | } |
||
| 104 | |||
| 105 | 2 | /** |
|
| 106 | * {@inheritdoc} |
||
| 107 | 2 | */ |
|
| 108 | protected function doLoadMetadata( |
||
| 109 | ClassMetadata $class, |
||
| 110 | ClassMetadataBuildingContext $metadataBuildingContext, |
||
| 111 | 2 | bool $rootEntityFound |
|
| 112 | ) : void |
||
| 113 | 2 | { |
|
| 114 | |||
| 115 | 2 | /* @var $class ClassMetadata */ |
|
| 116 | /* @var $parent ClassMetadata|null */ |
||
| 117 | $parent = $class->getParent(); |
||
| 118 | |||
| 119 | if ($parent) { |
||
| 120 | if ($parent->inheritanceType === InheritanceType::SINGLE_TABLE) { |
||
| 121 | 395 | $class->setTable($parent->table); |
|
| 122 | } |
||
| 123 | |||
| 124 | $this->addInheritedProperties($class, $parent); |
||
| 125 | 395 | $this->addInheritedEmbeddedClasses($class, $parent); |
|
| 126 | 108 | ||
| 127 | 29 | $class->setInheritanceType($parent->inheritanceType); |
|
| 128 | $class->setIdentifier($parent->identifier); |
||
| 129 | |||
| 130 | 108 | if ($parent->discriminatorColumn) { |
|
| 131 | 108 | $class->setDiscriminatorColumn($parent->discriminatorColumn); |
|
| 132 | 107 | $class->setDiscriminatorMap($parent->discriminatorMap); |
|
| 133 | } |
||
| 134 | 107 | ||
| 135 | 107 | $class->setLifecycleCallbacks($parent->lifecycleCallbacks); |
|
| 136 | 107 | $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); |
|
| 137 | |||
| 138 | 107 | if ($parent->isMappedSuperclass && ! $class->getCustomRepositoryClassName()) { |
|
| 139 | 4 | $class->setCustomRepositoryClassName($parent->getCustomRepositoryClassName()); |
|
| 140 | } |
||
| 141 | |||
| 142 | 107 | } |
|
| 143 | 65 | ||
| 144 | 65 | // Invoke driver |
|
| 145 | try { |
||
| 146 | $this->driver->loadMetadataForClass($class->getClassName(), $class, $metadataBuildingContext); |
||
| 147 | 107 | } catch (ReflectionException $e) { |
|
| 148 | 107 | throw MappingException::reflectionFailure($class->getClassName(), $e); |
|
| 149 | } |
||
| 150 | 107 | ||
| 151 | 1 | $this->completeIdentifierGeneratorMappings($class); |
|
| 152 | |||
| 153 | /*if ( ! $class->isMappedSuperclass) { |
||
| 154 | 107 | foreach ($class->embeddedClasses as $property => $embeddableClass) { |
|
| 155 | 39 | if (isset($embeddableClass['inherited'])) { |
|
| 156 | continue; |
||
| 157 | } |
||
| 158 | |||
| 159 | if ( ! (isset($embeddableClass['class']) && $embeddableClass['class'])) { |
||
| 160 | throw MappingException::missingEmbeddedClass($property); |
||
| 161 | 395 | } |
|
| 162 | 2 | ||
| 163 | if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) { |
||
| 164 | throw MappingException::infiniteEmbeddableNesting($class->getClassName(), $property); |
||
| 165 | } |
||
| 166 | |||
| 167 | $this->embeddablesActiveNesting[$class->getClassName()] = true; |
||
| 168 | |||
| 169 | 393 | $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); |
|
| 170 | 74 | ||
| 171 | if ($embeddableMetadata->isEmbeddedClass) { |
||
| 172 | 389 | $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property); |
|
| 173 | } |
||
| 174 | |||
| 175 | $identifier = $embeddableMetadata->getIdentifier(); |
||
| 176 | |||
| 177 | if (! empty($identifier)) { |
||
| 178 | $this->inheritIdGeneratorMapping($class, $embeddableMetadata); |
||
| 179 | } |
||
| 180 | |||
| 181 | $class->inlineEmbeddable($property, $embeddableMetadata); |
||
| 182 | |||
| 183 | unset($this->embeddablesActiveNesting[$class->getClassName()]); |
||
| 184 | } |
||
| 185 | }*/ |
||
| 186 | |||
| 187 | if ($parent) { |
||
| 188 | if ($parent->inheritanceType === InheritanceType::SINGLE_TABLE) { |
||
| 189 | $class->setTable($parent->table); |
||
| 190 | } |
||
| 191 | |||
| 192 | $this->addInheritedIndexes($class, $parent); |
||
| 193 | $this->addInheritedNamedQueries($class, $parent); |
||
| 194 | |||
| 195 | if ($parent->getCache()) { |
||
| 196 | $class->setCache(clone $parent->getCache()); |
||
| 197 | } |
||
| 198 | |||
| 199 | if ( ! empty($parent->namedNativeQueries)) { |
||
| 200 | $this->addInheritedNamedNativeQueries($class, $parent); |
||
| 201 | } |
||
| 202 | |||
| 203 | if ( ! empty($parent->sqlResultSetMappings)) { |
||
| 204 | $this->addInheritedSqlResultSetMappings($class, $parent); |
||
| 205 | } |
||
| 206 | |||
| 207 | if ( ! empty($parent->entityListeners) && empty($class->entityListeners)) { |
||
| 208 | $class->entityListeners = $parent->entityListeners; |
||
| 209 | 391 | } |
|
| 210 | 107 | } |
|
| 211 | 29 | ||
| 212 | if ($class->isRootEntity() && $class->inheritanceType !== InheritanceType::NONE && ! $class->discriminatorMap) { |
||
| 213 | $this->addDefaultDiscriminatorMap($class); |
||
| 214 | 107 | } |
|
| 215 | |||
| 216 | 107 | $this->completeRuntimeMetadata($class, $parent); |
|
| 217 | 3 | ||
| 218 | if ($this->evm->hasListeners(Events::loadClassMetadata)) { |
||
| 219 | $eventArgs = new LoadClassMetadataEventArgs($class, $this->em); |
||
| 220 | 107 | ||
| 221 | $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); |
||
| 222 | } |
||
| 223 | |||
| 224 | 107 | $this->buildValueGenerationPlan($class); |
|
| 225 | 1 | $this->validateRuntimeMetadata($class, $parent); |
|
| 226 | } |
||
| 227 | |||
| 228 | 107 | /** |
|
| 229 | 8 | * @param ClassMetadata $class |
|
| 230 | * @param ClassMetadata|null $parent |
||
| 231 | * |
||
| 232 | 107 | * @return void |
|
| 233 | 8 | */ |
|
| 234 | protected function completeRuntimeMetadata(ClassMetadata $class, ClassMetadata $parent = null) |
||
| 275 | 1 | ||
| 276 | /** |
||
| 277 | * Validate runtime metadata is correctly defined. |
||
| 278 | 39 | * |
|
| 279 | * @param ClassMetadata $class |
||
| 280 | * @param ClassMetadata|null $parent |
||
| 281 | 39 | * |
|
| 282 | 39 | * @return void |
|
| 283 | * |
||
| 284 | * @throws MappingException |
||
| 285 | */ |
||
| 286 | 39 | protected function validateRuntimeMetadata(ClassMetadata $class, ClassMetadata $parent = null) |
|
| 313 | |||
| 314 | 390 | /** |
|
| 315 | * {@inheritdoc} |
||
| 316 | 5 | */ |
|
| 317 | protected function newClassMetadataInstance( |
||
| 324 | 381 | ||
| 325 | 67 | /** |
|
| 326 | 63 | * {@inheritdoc} |
|
| 327 | */ |
||
| 328 | protected function newClassMetadataBuildingContext() : ClassMetadataBuildingContext |
||
| 332 | |||
| 333 | /** |
||
| 334 | 349 | * Populates the discriminator value of the given metadata (if not set) by iterating over discriminator |
|
| 335 | * map classes and looking for a fitting one. |
||
| 336 | 1 | * |
|
| 337 | * @param ClassMetadata $metadata |
||
| 338 | 380 | * |
|
| 339 | * @return void |
||
| 340 | * |
||
| 341 | * @throws MappingException |
||
| 342 | */ |
||
| 343 | 390 | private function resolveDiscriminatorValue(ClassMetadata $metadata) |
|
| 370 | 5 | ||
| 371 | /** |
||
| 372 | * Adds a default discriminator map if no one is given |
||
| 373 | * |
||
| 374 | * If an entity is of any inheritance type and does not contain a |
||
| 375 | 2 | * discriminator map, then the map is generated automatically. This process |
|
| 376 | 2 | * is expensive computation wise. |
|
| 377 | 1 | * |
|
| 378 | * The automatically generated discriminator map contains the lowercase short name of |
||
| 379 | 2 | * each class as key. |
|
| 380 | * |
||
| 381 | * @param \Doctrine\ORM\Mapping\ClassMetadata $class |
||
| 382 | * |
||
| 383 | 1 | * @throws MappingException |
|
| 384 | */ |
||
| 385 | private function addDefaultDiscriminatorMap(ClassMetadata $class) |
||
| 410 | |||
| 411 | 1 | /** |
|
| 412 | * Gets the lower-case short name of a class. |
||
| 413 | * |
||
| 414 | * @param string $className |
||
| 415 | 1 | * |
|
| 416 | * @return string |
||
| 417 | */ |
||
| 418 | private function getShortName($className) |
||
| 428 | |||
| 429 | /** |
||
| 430 | * Adds inherited fields to the subclass mapping. |
||
| 431 | * |
||
| 432 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
| 433 | 1 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
|
| 434 | * |
||
| 435 | 1 | * @return void |
|
| 436 | */ |
||
| 437 | private function addInheritedProperties(ClassMetadata $subClass, ClassMetadata $parentClass) |
||
| 449 | |||
| 450 | /** |
||
| 451 | * Adds inherited embedded mappings to the subclass mapping. |
||
| 452 | 108 | * |
|
| 453 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
| 454 | 108 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
|
| 455 | 92 | * |
|
| 456 | * @return void |
||
| 457 | */ |
||
| 458 | 108 | private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
| 472 | |||
| 473 | 108 | /** |
|
| 474 | * Adds nested embedded classes metadata to a parent class. |
||
| 475 | 108 | * |
|
| 476 | * @param ClassMetadata $subClass Sub embedded class metadata to add nested embedded classes metadata from. |
||
| 477 | 108 | * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to. |
|
| 478 | 40 | * @param string $prefix Embedded classes' prefix to use for nested embedded classes field names. |
|
| 479 | 6 | */ |
|
| 480 | 1 | private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix) |
|
| 502 | |||
| 503 | /** |
||
| 504 | * Copy the table indices from the parent class superclass to the child class |
||
| 505 | * |
||
| 506 | * @param ClassMetadata $subClass |
||
| 507 | * @param ClassMetadata $parentClass |
||
| 508 | * |
||
| 509 | * @return void |
||
| 510 | */ |
||
| 511 | 107 | private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
| 533 | |||
| 534 | /** |
||
| 535 | * Adds inherited named queries to the subclass mapping. |
||
| 536 | * |
||
| 537 | * @since 2.2 |
||
| 538 | * |
||
| 539 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
| 540 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
||
| 541 | * |
||
| 542 | * @return void |
||
| 543 | */ |
||
| 544 | private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass) |
||
| 554 | |||
| 555 | /** |
||
| 556 | * Adds inherited named native queries to the subclass mapping. |
||
| 557 | * |
||
| 558 | * @since 2.3 |
||
| 559 | * |
||
| 560 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
| 561 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
||
| 562 | 107 | * |
|
| 563 | * @return void |
||
| 564 | 107 | */ |
|
| 565 | 74 | private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
| 582 | |||
| 583 | /** |
||
| 584 | * Adds inherited sql result set mappings to the subclass mapping. |
||
| 585 | * |
||
| 586 | * @since 2.3 |
||
| 587 | * |
||
| 588 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
| 589 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
||
| 590 | * |
||
| 591 | * @return void |
||
| 592 | */ |
||
| 593 | 1 | private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
| 619 | 8 | ||
| 620 | 8 | /** |
|
| 621 | 4 | * Completes the ID generator mapping. If "auto" is specified we choose the generator |
|
| 622 | * most appropriate for the targeted database platform. |
||
| 623 | * |
||
| 624 | 8 | * @param ClassMetadata $class |
|
| 625 | 8 | * |
|
| 626 | 8 | * @return void |
|
| 627 | 8 | * |
|
| 628 | 8 | * @throws ORMException |
|
| 629 | 8 | */ |
|
| 630 | private function completeIdentifierGeneratorMappings(ClassMetadata $class) |
||
| 640 | |||
| 641 | private function completeFieldIdentifierGeneratorMapping(FieldMetadata $field) |
||
| 713 | |||
| 714 | /** |
||
| 715 | 290 | * {@inheritDoc} |
|
| 716 | */ |
||
| 717 | 290 | protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService) |
|
| 721 | 6 | ||
| 722 | /** |
||
| 723 | 6 | * {@inheritDoc} |
|
| 724 | */ |
||
| 725 | protected function initializeReflection(ClassMetadata $class, ReflectionService $reflService) |
||
| 729 | |||
| 730 | /** |
||
| 731 | * {@inheritDoc} |
||
| 732 | */ |
||
| 733 | protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) |
||
| 737 | |||
| 738 | 6 | /** |
|
| 739 | 6 | * {@inheritDoc} |
|
| 740 | */ |
||
| 741 | 140 | protected function getDriver() |
|
| 745 | 6 | ||
| 746 | 2 | /** |
|
| 747 | 2 | * {@inheritDoc} |
|
| 748 | */ |
||
| 749 | 4 | protected function isEntity(ClassMetadata $class) |
|
| 753 | 4 | ||
| 754 | 4 | /** |
|
| 755 | * @return Platforms\AbstractPlatform |
||
| 756 | 4 | */ |
|
| 757 | 2 | private function getTargetPlatform() |
|
| 765 | |||
| 766 | 387 | private function buildValueGenerationPlan(ClassMetadata $class): void |
|
| 802 | |||
| 803 | 395 | private function createPropertyValueGenerator(ClassMetadata $class, LocalColumnMetadata $property): Sequencing\Generator |
|
| 840 | } |
||
| 841 |
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: