welcome back to dyb-tech
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Bundle\DoctrineBundle\Repository;
|
||||
|
||||
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use RuntimeException;
|
||||
|
||||
use function class_exists;
|
||||
use function get_debug_type;
|
||||
use function is_a;
|
||||
use function spl_object_hash;
|
||||
use function sprintf;
|
||||
use function trigger_deprecation;
|
||||
|
||||
/**
|
||||
* Fetches repositories from the container or falls back to normal creation.
|
||||
*/
|
||||
final class ContainerRepositoryFactory implements RepositoryFactory
|
||||
{
|
||||
use RepositoryFactoryCompatibility;
|
||||
|
||||
/** @var array<string, ObjectRepository> */
|
||||
private array $managedRepositories = [];
|
||||
|
||||
private ContainerInterface $container;
|
||||
|
||||
/** @param ContainerInterface $container A service locator containing the repositories */
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<T> $entityName
|
||||
*
|
||||
* @return ObjectRepository<T>
|
||||
* @psalm-return ($strictTypeCheck is true ? EntityRepository<T> : ObjectRepository<T>)
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
private function doGetRepository(EntityManagerInterface $entityManager, string $entityName, bool $strictTypeCheck): ObjectRepository
|
||||
{
|
||||
$metadata = $entityManager->getClassMetadata($entityName);
|
||||
$repositoryServiceId = $metadata->customRepositoryClassName;
|
||||
|
||||
$customRepositoryName = $metadata->customRepositoryClassName;
|
||||
if ($customRepositoryName !== null) {
|
||||
// fetch from the container
|
||||
if ($this->container->has($customRepositoryName)) {
|
||||
$repository = $this->container->get($customRepositoryName);
|
||||
|
||||
if (! $repository instanceof EntityRepository && $strictTypeCheck) {
|
||||
throw new RuntimeException(sprintf('The service "%s" must extend EntityRepository (e.g. by extending ServiceEntityRepository), "%s" given.', $repositoryServiceId, get_debug_type($repository)));
|
||||
}
|
||||
|
||||
if (! $repository instanceof ObjectRepository) {
|
||||
throw new RuntimeException(sprintf('The service "%s" must implement ObjectRepository (or extend a base class, like ServiceEntityRepository), "%s" given.', $repositoryServiceId, get_debug_type($repository)));
|
||||
}
|
||||
|
||||
if (! $repository instanceof EntityRepository) {
|
||||
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);
|
||||
}
|
||||
|
||||
/** @psalm-var ObjectRepository<T> */
|
||||
return $repository;
|
||||
}
|
||||
|
||||
// if not in the container but the class/id implements the interface, throw an error
|
||||
if (is_a($customRepositoryName, ServiceEntityRepositoryInterface::class, true)) {
|
||||
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));
|
||||
}
|
||||
|
||||
if (! class_exists($customRepositoryName)) {
|
||||
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));
|
||||
}
|
||||
|
||||
// allow the repository to be created below
|
||||
}
|
||||
|
||||
return $this->getOrCreateRepository($entityManager, $metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMetadata<TEntity> $metadata
|
||||
*
|
||||
* @return ObjectRepository<TEntity>
|
||||
*
|
||||
* @template TEntity of object
|
||||
*/
|
||||
private function getOrCreateRepository(
|
||||
EntityManagerInterface $entityManager,
|
||||
ClassMetadata $metadata
|
||||
): ObjectRepository {
|
||||
$repositoryHash = $metadata->getName() . spl_object_hash($entityManager);
|
||||
if (isset($this->managedRepositories[$repositoryHash])) {
|
||||
/** @psalm-var ObjectRepository<TEntity> */
|
||||
return $this->managedRepositories[$repositoryHash];
|
||||
}
|
||||
|
||||
$repositoryClassName = $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();
|
||||
|
||||
/** @psalm-var ObjectRepository<TEntity> */
|
||||
return $this->managedRepositories[$repositoryHash] = new $repositoryClassName($entityManager, $metadata);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Bundle\DoctrineBundle\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use LogicException;
|
||||
use Symfony\Component\VarExporter\LazyObjectInterface;
|
||||
|
||||
use function debug_backtrace;
|
||||
use function sprintf;
|
||||
|
||||
use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
|
||||
/**
|
||||
* @internal Extend {@see ServiceEntityRepository} instead.
|
||||
*
|
||||
* @template T of object
|
||||
* @template-extends EntityRepository<T>
|
||||
*/
|
||||
class LazyServiceEntityRepository extends EntityRepository implements ServiceEntityRepositoryInterface
|
||||
{
|
||||
private ManagerRegistry $registry;
|
||||
private string $entityClass;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The class name of the entity this repository manages
|
||||
* @psalm-param class-string<T> $entityClass
|
||||
*/
|
||||
public function __construct(ManagerRegistry $registry, string $entityClass)
|
||||
{
|
||||
$this->registry = $registry;
|
||||
$this->entityClass = $entityClass;
|
||||
|
||||
if ($this instanceof LazyObjectInterface) {
|
||||
$this->initialize();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unset($this->_em);
|
||||
unset($this->_class);
|
||||
unset($this->_entityName);
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
public function __get(string $name)
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$scope = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['class'] ?? null;
|
||||
|
||||
return (function () use ($name) {
|
||||
return $this->$name;
|
||||
})->bindTo($this, $scope)();
|
||||
}
|
||||
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$scope = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['class'] ?? null;
|
||||
|
||||
return (function () use ($name) {
|
||||
return isset($this->$name);
|
||||
})->bindTo($this, $scope)();
|
||||
}
|
||||
|
||||
private function initialize(): void
|
||||
{
|
||||
$manager = $this->registry->getManagerForClass($this->entityClass);
|
||||
|
||||
if ($manager === null) {
|
||||
throw new LogicException(sprintf(
|
||||
'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.',
|
||||
$this->entityClass,
|
||||
));
|
||||
}
|
||||
|
||||
parent::__construct($manager, $manager->getClassMetadata($this->entityClass));
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Bundle\DoctrineBundle\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use ReflectionMethod;
|
||||
|
||||
if ((new ReflectionMethod(RepositoryFactory::class, 'getRepository'))->hasReturnType()) {
|
||||
// ORM >= 3
|
||||
/** @internal */
|
||||
trait RepositoryFactoryCompatibility
|
||||
{
|
||||
/**
|
||||
* Gets the repository for an entity class.
|
||||
*
|
||||
* @param class-string<T> $entityName
|
||||
*
|
||||
* @return EntityRepository<T>
|
||||
*
|
||||
* @template T of object
|
||||
*
|
||||
* @psalm-suppress MethodSignatureMismatch
|
||||
*/
|
||||
public function getRepository(EntityManagerInterface $entityManager, string $entityName): EntityRepository
|
||||
{
|
||||
return $this->doGetRepository($entityManager, $entityName, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ORM 2
|
||||
/** @internal */
|
||||
trait RepositoryFactoryCompatibility
|
||||
{
|
||||
/** {@inheritDoc} */
|
||||
public function getRepository(EntityManagerInterface $entityManager, $entityName): ObjectRepository
|
||||
{
|
||||
return $this->doGetRepository($entityManager, $entityName, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Bundle\DoctrineBundle\Repository;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
use function property_exists;
|
||||
|
||||
if (property_exists(EntityRepository::class, '_entityName')) {
|
||||
// ORM 2
|
||||
/**
|
||||
* Optional EntityRepository base class with a simplified constructor (for autowiring).
|
||||
*
|
||||
* To use in your class, inject the "registry" service and call
|
||||
* the parent constructor. For example:
|
||||
*
|
||||
* class YourEntityRepository extends ServiceEntityRepository
|
||||
* {
|
||||
* public function __construct(ManagerRegistry $registry)
|
||||
* {
|
||||
* parent::__construct($registry, YourEntity::class);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @template T of object
|
||||
* @template-extends LazyServiceEntityRepository<T>
|
||||
*/
|
||||
class ServiceEntityRepository extends LazyServiceEntityRepository
|
||||
{
|
||||
}
|
||||
} else {
|
||||
// ORM 3
|
||||
/**
|
||||
* Optional EntityRepository base class with a simplified constructor (for autowiring).
|
||||
*
|
||||
* To use in your class, inject the "registry" service and call
|
||||
* the parent constructor. For example:
|
||||
*
|
||||
* class YourEntityRepository extends ServiceEntityRepository
|
||||
* {
|
||||
* public function __construct(ManagerRegistry $registry)
|
||||
* {
|
||||
* parent::__construct($registry, YourEntity::class);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @template T of object
|
||||
* @template-extends ServiceEntityRepositoryProxy<T>
|
||||
*/
|
||||
class ServiceEntityRepository extends ServiceEntityRepositoryProxy
|
||||
{
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Bundle\DoctrineBundle\Repository;
|
||||
|
||||
/**
|
||||
* This interface signals that your repository should be loaded from the container.
|
||||
*/
|
||||
interface ServiceEntityRepositoryInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Bundle\DoctrineBundle\Repository;
|
||||
|
||||
use Doctrine\Common\Collections\AbstractLazyCollection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use LogicException;
|
||||
use Symfony\Component\VarExporter\LazyObjectInterface;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal Extend {@see ServiceEntityRepository} instead.
|
||||
*
|
||||
* @template T of object
|
||||
* @template-extends EntityRepository<T>
|
||||
*/
|
||||
class ServiceEntityRepositoryProxy extends EntityRepository implements ServiceEntityRepositoryInterface
|
||||
{
|
||||
private ?EntityRepository $repository = null;
|
||||
|
||||
/** @param class-string<T> $entityClass The class name of the entity this repository manages */
|
||||
public function __construct(
|
||||
private readonly ManagerRegistry $registry,
|
||||
private readonly string $entityClass,
|
||||
) {
|
||||
if (! $this instanceof LazyObjectInterface) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->repository = $this->resolveRepository();
|
||||
}
|
||||
|
||||
/** @psalm-suppress MethodSignatureMismatch This proxy is used only in combination with newer parent class */
|
||||
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())
|
||||
->createQueryBuilder($alias, $indexBy);
|
||||
}
|
||||
|
||||
/** @psalm-suppress MethodSignatureMismatch This proxy is used only in combination with newer parent class */
|
||||
public function createResultSetMappingBuilder(string $alias): ResultSetMappingBuilder
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())
|
||||
->createResultSetMappingBuilder($alias);
|
||||
}
|
||||
|
||||
/** @psalm-suppress MethodSignatureMismatch This proxy is used only in combination with newer parent class */
|
||||
public function find(mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
{
|
||||
/** @psalm-suppress InvalidReturnStatement This proxy is used only in combination with newer parent class */
|
||||
return ($this->repository ??= $this->resolveRepository())
|
||||
->find($id, $lockMode, $lockVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-suppress InvalidReturnStatement This proxy is used only in combination with newer parent class
|
||||
* @psalm-suppress MethodSignatureMismatch This proxy is used only in combination with newer parent class
|
||||
* @psalm-suppress InvalidReturnType This proxy is used only in combination with newer parent class
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())
|
||||
->findBy($criteria, $orderBy, $limit, $offset);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function findOneBy(array $criteria, ?array $orderBy = null): object|null
|
||||
{
|
||||
/** @psalm-suppress InvalidReturnStatement This proxy is used only in combination with newer parent class */
|
||||
return ($this->repository ??= $this->resolveRepository())
|
||||
->findOneBy($criteria, $orderBy);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function count(array $criteria = []): int
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())->count($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-suppress MethodSignatureMismatch This proxy is used only in combination with newer parent class
|
||||
*/
|
||||
public function __call(string $method, array $arguments): mixed
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())->$method(...$arguments);
|
||||
}
|
||||
|
||||
protected function getEntityName(): string
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())->getEntityName();
|
||||
}
|
||||
|
||||
protected function getEntityManager(): EntityManagerInterface
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())->getEntityManager();
|
||||
}
|
||||
|
||||
/** @psalm-suppress InvalidReturnType This proxy is used only in combination with newer parent class */
|
||||
protected function getClassMetadata(): ClassMetadata
|
||||
{
|
||||
/** @psalm-suppress InvalidReturnStatement This proxy is used only in combination with newer parent class */
|
||||
return ($this->repository ??= $this->resolveRepository())->getClassMetadata();
|
||||
}
|
||||
|
||||
public function matching(Criteria $criteria): AbstractLazyCollection&Selectable
|
||||
{
|
||||
return ($this->repository ??= $this->resolveRepository())->matching($criteria);
|
||||
}
|
||||
|
||||
private function resolveRepository(): EntityRepository
|
||||
{
|
||||
$manager = $this->registry->getManagerForClass($this->entityClass);
|
||||
|
||||
if ($manager === null) {
|
||||
throw new LogicException(sprintf(
|
||||
'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.',
|
||||
$this->entityClass,
|
||||
));
|
||||
}
|
||||
|
||||
return new EntityRepository($manager, $manager->getClassMetadata($this->entityClass));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user