vendor/easycorp/easyadmin-bundle/src/Factory/EntityFactory.php line 70

  1. <?php
  2. namespace EasyCorp\Bundle\EasyAdminBundle\Factory;
  3. use Doctrine\ORM\Mapping\ClassMetadata;
  4. use Doctrine\Persistence\ManagerRegistry;
  5. use Doctrine\Persistence\ObjectManager;
  6. use Doctrine\Persistence\Proxy;
  7. use EasyCorp\Bundle\EasyAdminBundle\Collection\ActionCollection;
  8. use EasyCorp\Bundle\EasyAdminBundle\Collection\EntityCollection;
  9. use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
  10. use EasyCorp\Bundle\EasyAdminBundle\Dto\ActionConfigDto;
  11. use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
  12. use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityBuiltEvent;
  13. use EasyCorp\Bundle\EasyAdminBundle\Exception\EntityNotFoundException;
  14. use EasyCorp\Bundle\EasyAdminBundle\Security\Permission;
  15. use Symfony\Component\ExpressionLanguage\Expression;
  16. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  17. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  18. /**
  19.  * @author Javier Eguiluz <javier.eguiluz@gmail.com>
  20.  */
  21. final class EntityFactory
  22. {
  23.     private FieldFactory $fieldFactory;
  24.     private ActionFactory $actionFactory;
  25.     private AuthorizationCheckerInterface $authorizationChecker;
  26.     private ManagerRegistry $doctrine;
  27.     private EventDispatcherInterface $eventDispatcher;
  28.     public function __construct(FieldFactory $fieldFactoryActionFactory $actionFactoryAuthorizationCheckerInterface $authorizationCheckerManagerRegistry $doctrineEventDispatcherInterface $eventDispatcher)
  29.     {
  30.         $this->fieldFactory $fieldFactory;
  31.         $this->actionFactory $actionFactory;
  32.         $this->authorizationChecker $authorizationChecker;
  33.         $this->doctrine $doctrine;
  34.         $this->eventDispatcher $eventDispatcher;
  35.     }
  36.     public function processFields(EntityDto $entityDtoFieldCollection $fields): void
  37.     {
  38.         $this->fieldFactory->processFields($entityDto$fields);
  39.     }
  40.     public function processFieldsForAll(EntityCollection $entitiesFieldCollection $fields): void
  41.     {
  42.         foreach ($entities as $entity) {
  43.             $this->processFields($entity, clone $fields);
  44.             $entities->set($entity);
  45.         }
  46.     }
  47.     public function processActions(EntityDto $entityDtoActionConfigDto $actionConfigDto): void
  48.     {
  49.         $this->actionFactory->processEntityActions($entityDto$actionConfigDto);
  50.     }
  51.     public function processActionsForAll(EntityCollection $entitiesActionConfigDto $actionConfigDto): ActionCollection
  52.     {
  53.         foreach ($entities as $entity) {
  54.             $this->processActions($entity, clone $actionConfigDto);
  55.         }
  56.         return $this->actionFactory->processGlobalActions($actionConfigDto);
  57.     }
  58.     public function create(string $entityFqcn$entityId nullstring|Expression|null $entityPermission null): EntityDto
  59.     {
  60.         return $this->doCreate($entityFqcn$entityId$entityPermission);
  61.     }
  62.     public function createForEntityInstance($entityInstance): EntityDto
  63.     {
  64.         return $this->doCreate(nullnullnull$entityInstance);
  65.     }
  66.     public function createCollection(EntityDto $entityDto, ?iterable $entityInstances): EntityCollection
  67.     {
  68.         $entityDtos = [];
  69.         foreach ($entityInstances as $entityInstance) {
  70.             $newEntityDto $entityDto->newWithInstance($entityInstance);
  71.             $newEntityId $newEntityDto->getPrimaryKeyValueAsString();
  72.             if (!$this->authorizationChecker->isGranted(Permission::EA_ACCESS_ENTITY$newEntityDto)) {
  73.                 $newEntityDto->markAsInaccessible();
  74.             }
  75.             $entityDtos[$newEntityId] = $newEntityDto;
  76.         }
  77.         return EntityCollection::new($entityDtos);
  78.     }
  79.     public function getEntityMetadata(string $entityFqcn): ClassMetadata
  80.     {
  81.         $entityManager $this->getEntityManager($entityFqcn);
  82.         /** @var ClassMetadata $entityMetadata */
  83.         $entityMetadata $entityManager->getClassMetadata($entityFqcn);
  84.         if (!== \count($entityMetadata->getIdentifierFieldNames())) {
  85.             throw new \RuntimeException(sprintf('EasyAdmin does not support Doctrine entities with composite primary keys (such as the ones used in the "%s" entity).'$entityFqcn));
  86.         }
  87.         return $entityMetadata;
  88.     }
  89.     private function doCreate(?string $entityFqcn null$entityId nullstring|Expression|null $entityPermission null$entityInstance null): EntityDto
  90.     {
  91.         if (null === $entityInstance && null !== $entityFqcn) {
  92.             $entityInstance null === $entityId null $this->getEntityInstance($entityFqcn$entityId);
  93.         }
  94.         if (null !== $entityInstance && null === $entityFqcn) {
  95.             if ($entityInstance instanceof Proxy) {
  96.                 $entityInstance->__load();
  97.             }
  98.             $entityFqcn $this->getRealClass($entityInstance::class);
  99.         }
  100.         $entityMetadata $this->getEntityMetadata($entityFqcn);
  101.         $entityDto = new EntityDto($entityFqcn$entityMetadata$entityPermission$entityInstance);
  102.         if (!$this->authorizationChecker->isGranted(Permission::EA_ACCESS_ENTITY$entityDto)) {
  103.             $entityDto->markAsInaccessible();
  104.         }
  105.         $this->eventDispatcher->dispatch(new AfterEntityBuiltEvent($entityDto));
  106.         return $entityDto;
  107.     }
  108.     private function getEntityManager(string $entityFqcn): ObjectManager
  109.     {
  110.         if (null === $entityManager $this->doctrine->getManagerForClass($entityFqcn)) {
  111.             throw new \RuntimeException(sprintf('There is no Doctrine Entity Manager defined for the "%s" class'$entityFqcn));
  112.         }
  113.         return $entityManager;
  114.     }
  115.     private function getEntityInstance(string $entityFqcn$entityIdValue): object
  116.     {
  117.         $entityManager $this->getEntityManager($entityFqcn);
  118.         if (null === $entityInstance $entityManager->getRepository($entityFqcn)->find($entityIdValue)) {
  119.             $entityIdName $entityManager->getClassMetadata($entityFqcn)->getIdentifierFieldNames()[0];
  120.             throw new EntityNotFoundException(['entity_name' => $entityFqcn'entity_id_name' => $entityIdName'entity_id_value' => $entityIdValue]);
  121.         }
  122.         return $entityInstance;
  123.     }
  124.     /**
  125.      * Code copied from Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser
  126.      * because Doctrine ORM 3.x removed the ClassUtil class where this method was defined
  127.      * (c) Fabien Potencier <fabien@symfony.com> - MIT License.
  128.      */
  129.     private function getRealClass(string $class): string
  130.     {
  131.         if (false === $pos strrpos($class'\\'.Proxy::MARKER.'\\')) {
  132.             return $class;
  133.         }
  134.         return substr($class$pos Proxy::MARKER_LENGTH 2);
  135.     }
  136. }