vendor/doctrine/doctrine-bundle/Repository/ContainerRepositoryFactory.php line 40

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\Mapping\ClassMetadata;
  6. use Doctrine\ORM\Repository\RepositoryFactory;
  7. use Doctrine\Persistence\ObjectRepository;
  8. use Psr\Container\ContainerInterface;
  9. use RuntimeException;
  10. use function class_exists;
  11. use function is_a;
  12. use function spl_object_hash;
  13. use function sprintf;
  14. /**
  15. * Fetches repositories from the container or falls back to normal creation.
  16. */
  17. final class ContainerRepositoryFactory implements RepositoryFactory
  18. {
  19. /** @var array<string, ObjectRepository> */
  20. private $managedRepositories = [];
  21. /** @var ContainerInterface */
  22. private $container;
  23. /** @param ContainerInterface $container A service locator containing the repositories */
  24. public function __construct(ContainerInterface $container)
  25. {
  26. $this->container = $container;
  27. }
  28. /**
  29. * {@inheritdoc}
  30. *
  31. * @template T of object
  32. */
  33. public function getRepository(EntityManagerInterface $entityManager, $entityName): ObjectRepository
  34. {
  35. $metadata = $entityManager->getClassMetadata($entityName);
  36. $repositoryServiceId = $metadata->customRepositoryClassName;
  37. $customRepositoryName = $metadata->customRepositoryClassName;
  38. if ($customRepositoryName !== null) {
  39. // fetch from the container
  40. if ($this->container->has($customRepositoryName)) {
  41. $repository = $this->container->get($customRepositoryName);
  42. if (! $repository instanceof ObjectRepository) {
  43. throw new RuntimeException(sprintf('The service "%s" must implement ObjectRepository (or extend a base class, like ServiceEntityRepository).', $repositoryServiceId));
  44. }
  45. /** @psalm-var ObjectRepository<T> */
  46. return $repository;
  47. }
  48. // if not in the container but the class/id implements the interface, throw an error
  49. if (is_a($customRepositoryName, ServiceEntityRepositoryInterface::class, true)) {
  50. 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));
  51. }
  52. if (! class_exists($customRepositoryName)) {
  53. 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));
  54. }
  55. // allow the repository to be created below
  56. }
  57. return $this->getOrCreateRepository($entityManager, $metadata);
  58. }
  59. /**
  60. * @param ClassMetadata<TEntity> $metadata
  61. *
  62. * @return ObjectRepository<TEntity>
  63. *
  64. * @template TEntity of object
  65. */
  66. private function getOrCreateRepository(
  67. EntityManagerInterface $entityManager,
  68. ClassMetadata $metadata
  69. ): ObjectRepository {
  70. $repositoryHash = $metadata->getName() . spl_object_hash($entityManager);
  71. if (isset($this->managedRepositories[$repositoryHash])) {
  72. /** @psalm-var ObjectRepository<TEntity> */
  73. return $this->managedRepositories[$repositoryHash];
  74. }
  75. $repositoryClassName = $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
  76. /** @psalm-var ObjectRepository<TEntity> */
  77. return $this->managedRepositories[$repositoryHash] = new $repositoryClassName($entityManager, $metadata);
  78. }
  79. }