vendor/doctrine/orm/lib/Doctrine/ORM/Tools/ResolveTargetEntityListener.php line 61

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ORM\Tools;
  4. use Doctrine\Common\EventSubscriber;
  5. use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
  6. use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
  7. use Doctrine\ORM\Events;
  8. use Doctrine\ORM\Mapping\ClassMetadata;
  9. use function array_key_exists;
  10. use function array_replace_recursive;
  11. use function ltrim;
  12. /**
  13.  * ResolveTargetEntityListener
  14.  *
  15.  * Mechanism to overwrite interfaces or classes specified as association
  16.  * targets.
  17.  *
  18.  * @psalm-import-type AssociationMapping from ClassMetadata
  19.  */
  20. class ResolveTargetEntityListener implements EventSubscriber
  21. {
  22.     /** @var mixed[][] indexed by original entity name */
  23.     private $resolveTargetEntities = [];
  24.     /**
  25.      * {@inheritDoc}
  26.      */
  27.     public function getSubscribedEvents()
  28.     {
  29.         return [
  30.             Events::loadClassMetadata,
  31.             Events::onClassMetadataNotFound,
  32.         ];
  33.     }
  34.     /**
  35.      * Adds a target-entity class name to resolve to a new class name.
  36.      *
  37.      * @param string $originalEntity
  38.      * @param string $newEntity
  39.      * @psalm-param array<string, mixed> $mapping
  40.      *
  41.      * @return void
  42.      */
  43.     public function addResolveTargetEntity($originalEntity$newEntity, array $mapping)
  44.     {
  45.         $mapping['targetEntity']                                   = ltrim($newEntity'\\');
  46.         $this->resolveTargetEntities[ltrim($originalEntity'\\')] = $mapping;
  47.     }
  48.     /**
  49.      * @internal this is an event callback, and should not be called directly
  50.      *
  51.      * @return void
  52.      */
  53.     public function onClassMetadataNotFound(OnClassMetadataNotFoundEventArgs $args)
  54.     {
  55.         if (array_key_exists($args->getClassName(), $this->resolveTargetEntities)) {
  56.             $args->setFoundMetadata(
  57.                 $args
  58.                     ->getObjectManager()
  59.                     ->getClassMetadata($this->resolveTargetEntities[$args->getClassName()]['targetEntity'])
  60.             );
  61.         }
  62.     }
  63.     /**
  64.      * Processes event and resolves new target entity names.
  65.      *
  66.      * @internal this is an event callback, and should not be called directly
  67.      *
  68.      * @return void
  69.      */
  70.     public function loadClassMetadata(LoadClassMetadataEventArgs $args)
  71.     {
  72.         $cm $args->getClassMetadata();
  73.         foreach ($cm->associationMappings as $mapping) {
  74.             if (isset($this->resolveTargetEntities[$mapping['targetEntity']])) {
  75.                 $this->remapAssociation($cm$mapping);
  76.             }
  77.         }
  78.         foreach ($this->resolveTargetEntities as $interface => $data) {
  79.             if ($data['targetEntity'] === $cm->getName()) {
  80.                 $args->getEntityManager()->getMetadataFactory()->setMetadataFor($interface$cm);
  81.             }
  82.         }
  83.         foreach ($cm->discriminatorMap as $value => $class) {
  84.             if (isset($this->resolveTargetEntities[$class])) {
  85.                 $cm->addDiscriminatorMapClass($value$this->resolveTargetEntities[$class]['targetEntity']);
  86.             }
  87.         }
  88.     }
  89.     /** @param AssociationMapping $mapping */
  90.     private function remapAssociation(ClassMetadata $classMetadata, array $mapping): void
  91.     {
  92.         $newMapping              $this->resolveTargetEntities[$mapping['targetEntity']];
  93.         $newMapping              array_replace_recursive($mapping$newMapping);
  94.         $newMapping['fieldName'] = $mapping['fieldName'];
  95.         unset($classMetadata->associationMappings[$mapping['fieldName']]);
  96.         switch ($mapping['type']) {
  97.             case ClassMetadata::MANY_TO_MANY:
  98.                 $classMetadata->mapManyToMany($newMapping);
  99.                 break;
  100.             case ClassMetadata::MANY_TO_ONE:
  101.                 $classMetadata->mapManyToOne($newMapping);
  102.                 break;
  103.             case ClassMetadata::ONE_TO_MANY:
  104.                 $classMetadata->mapOneToMany($newMapping);
  105.                 break;
  106.             case ClassMetadata::ONE_TO_ONE:
  107.                 $classMetadata->mapOneToOne($newMapping);
  108.                 break;
  109.         }
  110.     }
  111. }