vendor/doctrine/doctrine-bundle/src/Repository/ContainerRepositoryFactory.php line 47

  1. <?php
  2. namespace Doctrine\Bundle\DoctrineBundle\Repository;
  3. use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass;
  4. use Doctrine\ORM\EntityManagerInterface;
  5. use Doctrine\ORM\EntityRepository;
  6. use Doctrine\ORM\Mapping\ClassMetadata;
  7. use Doctrine\ORM\Repository\RepositoryFactory;
  8. use Doctrine\Persistence\ObjectRepository;
  9. use Psr\Container\ContainerInterface;
  10. use RuntimeException;
  11. use function class_exists;
  12. use function get_debug_type;
  13. use function is_a;
  14. use function spl_object_hash;
  15. use function sprintf;
  16. use function trigger_deprecation;
  17. /**
  18.  * Fetches repositories from the container or falls back to normal creation.
  19.  */
  20. final class ContainerRepositoryFactory implements RepositoryFactory
  21. {
  22.     use RepositoryFactoryCompatibility;
  23.     /** @var array<string, ObjectRepository> */
  24.     private array $managedRepositories = [];
  25.     private ContainerInterface $container;
  26.     /** @param ContainerInterface $container A service locator containing the repositories */
  27.     public function __construct(ContainerInterface $container)
  28.     {
  29.         $this->container $container;
  30.     }
  31.     /**
  32.      * @param class-string<T> $entityName
  33.      *
  34.      * @return ObjectRepository<T>
  35.      * @psalm-return ($strictTypeCheck is true ? EntityRepository<T> : ObjectRepository<T>)
  36.      *
  37.      * @template T of object
  38.      */
  39.     private function doGetRepository(EntityManagerInterface $entityManagerstring $entityNamebool $strictTypeCheck): ObjectRepository
  40.     {
  41.         $metadata            $entityManager->getClassMetadata($entityName);
  42.         $repositoryServiceId $metadata->customRepositoryClassName;
  43.         $customRepositoryName $metadata->customRepositoryClassName;
  44.         if ($customRepositoryName !== null) {
  45.             // fetch from the container
  46.             if ($this->container->has($customRepositoryName)) {
  47.                 $repository $this->container->get($customRepositoryName);
  48.                 if (! $repository instanceof EntityRepository && $strictTypeCheck) {
  49.                     throw new RuntimeException(sprintf('The service "%s" must extend EntityRepository (e.g. by extending ServiceEntityRepository), "%s" given.'$repositoryServiceIdget_debug_type($repository)));
  50.                 }
  51.                 if (! $repository instanceof ObjectRepository) {
  52.                     throw new RuntimeException(sprintf('The service "%s" must implement ObjectRepository (or extend a base class, like ServiceEntityRepository), "%s" given.'$repositoryServiceIdget_debug_type($repository)));
  53.                 }
  54.                 if (! $repository instanceof EntityRepository) {
  55.                     trigger_deprecation('doctrine/doctrine-bundle''2.11''The service "%s" of type "%s" should extend "%s", not doing so is deprecated.'$repositoryServiceIdget_debug_type($repository), EntityRepository::class);
  56.                 }
  57.                 /** @psalm-var ObjectRepository<T> */
  58.                 return $repository;
  59.             }
  60.             // if not in the container but the class/id implements the interface, throw an error
  61.             if (is_a($customRepositoryNameServiceEntityRepositoryInterface::class, true)) {
  62.                 throw new RuntimeException(sprintf('The "%s" entity repository implements "%s", but its service could not be found. Make sure the service exists and is tagged with "%s".'$customRepositoryNameServiceEntityRepositoryInterface::class, ServiceRepositoryCompilerPass::REPOSITORY_SERVICE_TAG));
  63.             }
  64.             if (! class_exists($customRepositoryName)) {
  65.                 throw new RuntimeException(sprintf('The "%s" entity has a repositoryClass set to "%s", but this is not a valid class. Check your class naming. If this is meant to be a service id, make sure this service exists and is tagged with "%s".'$metadata->name$customRepositoryNameServiceRepositoryCompilerPass::REPOSITORY_SERVICE_TAG));
  66.             }
  67.             // allow the repository to be created below
  68.         }
  69.         return $this->getOrCreateRepository($entityManager$metadata);
  70.     }
  71.     /**
  72.      * @param ClassMetadata<TEntity> $metadata
  73.      *
  74.      * @return ObjectRepository<TEntity>
  75.      *
  76.      * @template TEntity of object
  77.      */
  78.     private function getOrCreateRepository(
  79.         EntityManagerInterface $entityManager,
  80.         ClassMetadata $metadata
  81.     ): ObjectRepository {
  82.         $repositoryHash $metadata->getName() . spl_object_hash($entityManager);
  83.         if (isset($this->managedRepositories[$repositoryHash])) {
  84.             /** @psalm-var ObjectRepository<TEntity> */
  85.             return $this->managedRepositories[$repositoryHash];
  86.         }
  87.         $repositoryClassName $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
  88.         /** @psalm-var ObjectRepository<TEntity> */
  89.         return $this->managedRepositories[$repositoryHash] = new $repositoryClassName($entityManager$metadata);
  90.     }
  91. }