From 31e14d190d0e05f77fbb79cdcd5b30911f0882f9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 13 Nov 2023 19:10:38 +0100 Subject: [PATCH] Don't rely on LazyProxyTrait in LazyServiceEntityRepository --- Repository/LazyServiceEntityRepository.php | 75 ++++++++++++++------ Repository/LegacyServiceEntityRepository.php | 38 ---------- Repository/ServiceEntityRepository.php | 66 ++++++----------- 3 files changed, 72 insertions(+), 107 deletions(-) delete mode 100644 Repository/LegacyServiceEntityRepository.php diff --git a/Repository/LazyServiceEntityRepository.php b/Repository/LazyServiceEntityRepository.php index bc9d6813..aa9fd63f 100644 --- a/Repository/LazyServiceEntityRepository.php +++ b/Repository/LazyServiceEntityRepository.php @@ -5,11 +5,13 @@ use Doctrine\ORM\EntityRepository; use Doctrine\Persistence\ManagerRegistry; use LogicException; -use Symfony\Component\VarExporter\LazyGhostTrait; use Symfony\Component\VarExporter\LazyObjectInterface; +use function debug_backtrace; use function sprintf; +use const DEBUG_BACKTRACE_IGNORE_ARGS; + /** * @internal Extend {@see ServiceEntityRepository} instead. * @@ -18,9 +20,8 @@ */ class LazyServiceEntityRepository extends EntityRepository implements ServiceEntityRepositoryInterface { - use LazyGhostTrait { - createLazyGhost as private; - } + private ManagerRegistry $registry; + private string $entityClass; /** * @param string $entityClass The class name of the entity this repository manages @@ -28,31 +29,59 @@ class LazyServiceEntityRepository extends EntityRepository implements ServiceEnt */ public function __construct(ManagerRegistry $registry, string $entityClass) { - $initializer = function ($instance, $property) use ($registry, $entityClass) { - $manager = $registry->getManagerForClass($entityClass); + $this->registry = $registry; + $this->entityClass = $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.', - $entityClass, - )); - } + if ($this instanceof LazyObjectInterface) { + $this->initialize(); - parent::__construct($manager, $manager->getClassMetadata($entityClass)); + return; + } - return $this->$property; - }; + unset($this->_em); + unset($this->_class); + unset($this->_entityName); + } - if ($this instanceof LazyObjectInterface) { - $initializer($this, '_entityName'); + /** + * @param string|int $name + * + * @return mixed + */ + public function __get($name) + { + $this->initialize(); - return; + $scope = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['class'] ?? null; + + return (function () use ($name) { + return $this->$name; + })->bindTo($this, $scope)(); + } + + /** @param string|int $name */ + public function __isset($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, + )); } - self::createLazyGhost([ - "\0*\0_em" => $initializer, - "\0*\0_class" => $initializer, - "\0*\0_entityName" => $initializer, - ], null, $this); + parent::__construct($manager, $manager->getClassMetadata($this->entityClass)); } } diff --git a/Repository/LegacyServiceEntityRepository.php b/Repository/LegacyServiceEntityRepository.php deleted file mode 100644 index d405572f..00000000 --- a/Repository/LegacyServiceEntityRepository.php +++ /dev/null @@ -1,38 +0,0 @@ - - */ -class LegacyServiceEntityRepository extends EntityRepository implements ServiceEntityRepositoryInterface -{ - /** - * @param string $entityClass The class name of the entity this repository manages - * @psalm-param class-string $entityClass - */ - public function __construct(ManagerRegistry $registry, string $entityClass) - { - $manager = $registry->getManagerForClass($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.', - $entityClass, - )); - } - - parent::__construct($manager, $manager->getClassMetadata($entityClass)); - } -} diff --git a/Repository/ServiceEntityRepository.php b/Repository/ServiceEntityRepository.php index b4ea102d..d4c59e2e 100644 --- a/Repository/ServiceEntityRepository.php +++ b/Repository/ServiceEntityRepository.php @@ -3,56 +3,30 @@ namespace Doctrine\Bundle\DoctrineBundle\Repository; use Doctrine\ORM\EntityRepository; -use Symfony\Component\VarExporter\LazyGhostTrait; use function property_exists; -use function trait_exists; if (property_exists(EntityRepository::class, '_entityName')) { - if (trait_exists(LazyGhostTrait::class)) { - // ORM 2 with VarExporter - /** - * 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 - */ - class ServiceEntityRepository extends LazyServiceEntityRepository - { - } - } else { - // ORM 2 without VarExporter - /** - * 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 LegacyServiceEntityRepository - */ - class ServiceEntityRepository extends LegacyServiceEntityRepository - { - } + // 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 + */ + class ServiceEntityRepository extends LazyServiceEntityRepository + { } } else { // ORM 3