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

Open in your IDE?
  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. * @phpstan-return ($strictTypeCheck is true ? EntityRepository<T> : ObjectRepository<T>)
  36. *
  37. * @template T of object
  38. */
  39. private function doGetRepository(EntityManagerInterface $entityManager, string $entityName, bool $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.', $repositoryServiceId, get_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.', $repositoryServiceId, get_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.', $repositoryServiceId, get_debug_type($repository), EntityRepository::class);
  56. }
  57. /** @phpstan-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($customRepositoryName, ServiceEntityRepositoryInterface::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".', $customRepositoryName, ServiceEntityRepositoryInterface::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, $customRepositoryName, ServiceRepositoryCompilerPass::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. /** @phpstan-var ObjectRepository<TEntity> */
  85. return $this->managedRepositories[$repositoryHash];
  86. }
  87. $repositoryClassName = $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
  88. /** @phpstan-var ObjectRepository<TEntity> */
  89. return $this->managedRepositories[$repositoryHash] = new $repositoryClassName($entityManager, $metadata);
  90. }
  91. }