From 41ace4f455009f570b7463120a373b8b948ddd2e Mon Sep 17 00:00:00 2001 From: pink6440 <11294673+pink6440@users.noreply.github.com> Date: Thu, 12 Jun 2025 10:56:18 +0200 Subject: [PATCH 01/11] Update DoctrineEntityHydrationExtension.php, support for interface aliased to an entity Doctrine have the feature to use interface aliased to a concrete entity class. This PR propose a small modification to ensure that is will also supported by the doctrine hydrator --- .../Hydration/DoctrineEntityHydrationExtension.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index 53f6b0be7a9..b255e7e76d0 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -81,15 +81,21 @@ public function dehydrate(object $object): mixed private function objectManagerFor(string $class): ?ObjectManager { - if (!class_exists($class)) { + if (!interface_exist($class) && !class_exists($class)) { return null; } // todo cache/warmup an array of classes that are "doctrine objects" foreach ($this->managerRegistries as $registry) { - if ($om = $registry->getManagerForClass($class)) { - return self::ensureManagedObject($om, $class); + foreach($registry->getManagers() as $om) { + // this way, it resolves the interface + if ($om->getClassMetadata($class)) { + return self::ensureManagedObject($om, $class); + } } + // if ($om = $registry->getManagerForClass($class)) { + // return self::ensureManagedObject($om, $class); + // } } return null; From c971111fc4e2a527523139c869929fbaf9ee68ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Thu, 12 Jun 2025 15:20:58 +0200 Subject: [PATCH 02/11] Updating hydrator Making tests --- .../DoctrineEntityHydrationExtension.php | 36 ++++++++++++----- .../tests/Fixtures/Dto/Aliased.php | 9 +++++ .../tests/Fixtures/Entity/AliasedEntity.php | 27 +++++++++++++ .../Entity/AliasedEntityInterface.php | 7 ++++ src/LiveComponent/tests/Fixtures/Kernel.php | 4 ++ .../DoctrineEntityHydrationExtensionTest.php | 40 +++++++++++++++++++ 6 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 src/LiveComponent/tests/Fixtures/Dto/Aliased.php create mode 100644 src/LiveComponent/tests/Fixtures/Entity/AliasedEntity.php create mode 100644 src/LiveComponent/tests/Fixtures/Entity/AliasedEntityInterface.php diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index b255e7e76d0..b8e75257a21 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -14,6 +14,7 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; +use Doctrine\Persistence\Mapping\MappingException; /** * Handles hydration of Doctrine entities. @@ -27,7 +28,8 @@ class DoctrineEntityHydrationExtension implements HydrationExtensionInterface */ public function __construct( private iterable $managerRegistries, - ) { + ) + { } public function supports(string $className): bool @@ -61,11 +63,10 @@ public function dehydrate(object $object): mixed $id = $this ->objectManagerFor($class = $object::class) ->getClassMetadata($class) - ->getIdentifierValues($object) - ; + ->getIdentifierValues($object); // Dehydrate ID values in case they are other entities - $id = array_map(fn ($id) => \is_object($id) && $this->supports($id::class) ? $this->dehydrate($id) : $id, $id); + $id = array_map(fn($id) => \is_object($id) && $this->supports($id::class) ? $this->dehydrate($id) : $id, $id); switch (\count($id)) { case 0: @@ -81,21 +82,34 @@ public function dehydrate(object $object): mixed private function objectManagerFor(string $class): ?ObjectManager { - if (!interface_exist($class) && !class_exists($class)) { + if (!interface_exists($class) && !class_exists($class)) { return null; } // todo cache/warmup an array of classes that are "doctrine objects" foreach ($this->managerRegistries as $registry) { - foreach($registry->getManagers() as $om) { - // this way, it resolves the interface - if ($om->getClassMetadata($class)) { - return self::ensureManagedObject($om, $class); - } - } + + // The doctrine registry does not resolve aliased interface // if ($om = $registry->getManagerForClass($class)) { // return self::ensureManagedObject($om, $class); // } + + foreach ($registry->getManagers() as $om) { + // But we can resolve nicely by trying to ask each manager to get the metadata + try { + if ($om->getClassMetadata($class) !== null) { + return self::ensureManagedObject($om, $class); + } + + } catch (MappingException $e) { + // I did not find a nice way to check if it is because the class is really unknown + // It is good to check for a specific exception ? + // eg: \Doctrine\Persistence\Mapping\MappingException + // Maybe not needed, because it does not failed even when the class does not exist at all + throw $e; + } + + } } return null; diff --git a/src/LiveComponent/tests/Fixtures/Dto/Aliased.php b/src/LiveComponent/tests/Fixtures/Dto/Aliased.php new file mode 100644 index 00000000000..fa88ed42002 --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/Dto/Aliased.php @@ -0,0 +1,9 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\LiveComponent\Tests\Fixtures\Entity; + +use Doctrine\ORM\Mapping as ORM; +use Doctrine\ORM\Mapping\Column; + +#[ORM\Entity] +class AliasedEntity implements AliasedEntityInterface +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: 'integer')] + public $id; + + #[Column(type: 'string')] + public ?string $name = null; +} diff --git a/src/LiveComponent/tests/Fixtures/Entity/AliasedEntityInterface.php b/src/LiveComponent/tests/Fixtures/Entity/AliasedEntityInterface.php new file mode 100644 index 00000000000..add24a9366e --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/Entity/AliasedEntityInterface.php @@ -0,0 +1,7 @@ + 'XML', ], ], + 'resolve_target_entities' => [ + AliasedEntityInterface::class => AliasedEntity::class], ], ]; diff --git a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php index 1b9de696f8b..443b9502bf8 100644 --- a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php +++ b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php @@ -11,8 +11,15 @@ namespace Symfony\UX\LiveComponent\Tests\Integration\Hydration; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Tools\ResolveTargetEntityListener; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Service\Attribute\Required; use Symfony\UX\LiveComponent\Hydration\DoctrineEntityHydrationExtension; +use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntity; +use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntityInterface; use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\CompositeIdEntity; use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\ForeignKeyIdEntity; use Symfony\UX\LiveComponent\Tests\Fixtures\Factory\CompositeIdEntityFactory; @@ -50,4 +57,37 @@ public function testForeignKeyId(): void self::assertSame($foreignKeyIdEntity->id->id, $dehydrated); self::assertSame($foreignKeyIdEntity, $extension->hydrate($dehydrated, ForeignKeyIdEntity::class)); } + + + public function testSupportInterface(): void + { + /** @var DoctrineEntityHydrationExtension $extension */ + $extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension'); + + self::assertTrue($extension->supports(AliasedEntityInterface::class),"AliasedEntityInterface should be supported"); + self::assertTrue($extension->supports(AliasedEntity::class),"AliasedEntity should be supported"); + self::assertFalse($extension->supports('UnknownClass'),"UnknownClass should not be supported"); + } + + public function testHydrationFromInterface(): void + { + /** @var DoctrineEntityHydrationExtension $extension */ + $extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension'); + $em = self::getContainer()->get(EntityManagerInterface::class); + + $a = new AliasedEntity(); + $a->name = 'foo'; + + $em->persist($a); + $em->flush(); + + $dehydratedData = $extension->dehydrate($a); + + $a2 = $extension->hydrate($dehydratedData, AliasedEntityInterface::class); + + self::assertSame($a, $a2,"instance should be the same"); + self::assertNull($extension->hydrate(null, AliasedEntityInterface::class),"should return null if null is passed"); + + + } } From 75df169d04d45943661836d302b2d1bad8b13433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Thu, 12 Jun 2025 18:52:13 +0200 Subject: [PATCH 03/11] Optimization --- .../src/Hydration/DoctrineEntityHydrationExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index b8e75257a21..c633aa0e92a 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -82,7 +82,7 @@ public function dehydrate(object $object): mixed private function objectManagerFor(string $class): ?ObjectManager { - if (!interface_exists($class) && !class_exists($class)) { + if (!class_exists($class) && !interface_exists($class)) { return null; } From 2efae98c6b5ab053dd214add8eb9198bb3487e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Thu, 12 Jun 2025 19:04:04 +0200 Subject: [PATCH 04/11] Code styling --- .../DoctrineEntityHydrationExtensionTest.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php index 443b9502bf8..d1f035b4b21 100644 --- a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php +++ b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php @@ -11,12 +11,9 @@ namespace Symfony\UX\LiveComponent\Tests\Integration\Hydration; -use Doctrine\ORM\EntityManager; + use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Tools\ResolveTargetEntityListener; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Contracts\Service\Attribute\Required; use Symfony\UX\LiveComponent\Hydration\DoctrineEntityHydrationExtension; use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntity; use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntityInterface; @@ -75,19 +72,17 @@ public function testHydrationFromInterface(): void $extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension'); $em = self::getContainer()->get(EntityManagerInterface::class); - $a = new AliasedEntity(); - $a->name = 'foo'; + $existingEntity = new AliasedEntity(); + $existingEntity->name = 'foo'; - $em->persist($a); + $em->persist($existingEntity); $em->flush(); - $dehydratedData = $extension->dehydrate($a); + $dehydratedData = $extension->dehydrate($existingEntity); - $a2 = $extension->hydrate($dehydratedData, AliasedEntityInterface::class); + $entityFromDehydratation = $extension->hydrate($dehydratedData, AliasedEntityInterface::class); - self::assertSame($a, $a2,"instance should be the same"); + self::assertSame($existingEntity, $entityFromDehydratation,"instance should be the same"); self::assertNull($extension->hydrate(null, AliasedEntityInterface::class),"should return null if null is passed"); - - } } From e9afa14399a73bc3014853d8151ced4acaeb1fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Thu, 12 Jun 2025 21:12:33 +0200 Subject: [PATCH 05/11] Code styling --- .../src/Hydration/DoctrineEntityHydrationExtension.php | 2 +- .../Hydration/DoctrineEntityHydrationExtensionTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index c633aa0e92a..6e1f982e643 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -106,7 +106,7 @@ private function objectManagerFor(string $class): ?ObjectManager // It is good to check for a specific exception ? // eg: \Doctrine\Persistence\Mapping\MappingException // Maybe not needed, because it does not failed even when the class does not exist at all - throw $e; +// throw $e; } } diff --git a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php index d1f035b4b21..391676054c5 100644 --- a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php +++ b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php @@ -82,7 +82,7 @@ public function testHydrationFromInterface(): void $entityFromDehydratation = $extension->hydrate($dehydratedData, AliasedEntityInterface::class); - self::assertSame($existingEntity, $entityFromDehydratation,"instance should be the same"); - self::assertNull($extension->hydrate(null, AliasedEntityInterface::class),"should return null if null is passed"); + self::assertSame($existingEntity, $entityFromDehydratation,'instance should be the same'); + self::assertNull($extension->hydrate(null, AliasedEntityInterface::class),'should return null if null is passed'); } } From ed2b787bd7d2d53fa3d6c511b1b1d5940674c17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Thu, 12 Jun 2025 21:15:45 +0200 Subject: [PATCH 06/11] Code styling --- .../src/Hydration/DoctrineEntityHydrationExtension.php | 10 +++------- .../Hydration/DoctrineEntityHydrationExtensionTest.php | 7 +++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index 6e1f982e643..e5517e06dc4 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -66,7 +66,7 @@ public function dehydrate(object $object): mixed ->getIdentifierValues($object); // Dehydrate ID values in case they are other entities - $id = array_map(fn($id) => \is_object($id) && $this->supports($id::class) ? $this->dehydrate($id) : $id, $id); + $id = array_map(fn ($id) => \is_object($id) && $this->supports($id::class) ? $this->dehydrate($id) : $id, $id); switch (\count($id)) { case 0: @@ -88,27 +88,23 @@ private function objectManagerFor(string $class): ?ObjectManager // todo cache/warmup an array of classes that are "doctrine objects" foreach ($this->managerRegistries as $registry) { - // The doctrine registry does not resolve aliased interface // if ($om = $registry->getManagerForClass($class)) { // return self::ensureManagedObject($om, $class); // } - foreach ($registry->getManagers() as $om) { // But we can resolve nicely by trying to ask each manager to get the metadata try { - if ($om->getClassMetadata($class) !== null) { + if (null !== $om->getClassMetadata($class)) { return self::ensureManagedObject($om, $class); } - } catch (MappingException $e) { // I did not find a nice way to check if it is because the class is really unknown // It is good to check for a specific exception ? // eg: \Doctrine\Persistence\Mapping\MappingException // Maybe not needed, because it does not failed even when the class does not exist at all -// throw $e; + // throw $e; } - } } diff --git a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php index 391676054c5..c3dafe92526 100644 --- a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php +++ b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php @@ -55,15 +55,14 @@ public function testForeignKeyId(): void self::assertSame($foreignKeyIdEntity, $extension->hydrate($dehydrated, ForeignKeyIdEntity::class)); } - public function testSupportInterface(): void { /** @var DoctrineEntityHydrationExtension $extension */ $extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension'); - self::assertTrue($extension->supports(AliasedEntityInterface::class),"AliasedEntityInterface should be supported"); - self::assertTrue($extension->supports(AliasedEntity::class),"AliasedEntity should be supported"); - self::assertFalse($extension->supports('UnknownClass'),"UnknownClass should not be supported"); + self::assertTrue($extension->supports(AliasedEntityInterface::class),'AliasedEntityInterface should be supported'); + self::assertTrue($extension->supports(AliasedEntity::class),'AliasedEntity should be supported'); + self::assertFalse($extension->supports('UnknownClass'),'UnknownClass should not be supported'); } public function testHydrationFromInterface(): void From afcaa5eacb36394e92bbbb6d0b3d29bc3cab3b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Thu, 12 Jun 2025 21:19:47 +0200 Subject: [PATCH 07/11] Code styling --- .../Hydration/DoctrineEntityHydrationExtension.php | 3 +-- .../DoctrineEntityHydrationExtensionTest.php | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index e5517e06dc4..3333408e3f2 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -28,8 +28,7 @@ class DoctrineEntityHydrationExtension implements HydrationExtensionInterface */ public function __construct( private iterable $managerRegistries, - ) - { + ) { } public function supports(string $className): bool diff --git a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php index c3dafe92526..1bdb55436f7 100644 --- a/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php +++ b/src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php @@ -11,7 +11,6 @@ namespace Symfony\UX\LiveComponent\Tests\Integration\Hydration; - use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\UX\LiveComponent\Hydration\DoctrineEntityHydrationExtension; @@ -60,9 +59,9 @@ public function testSupportInterface(): void /** @var DoctrineEntityHydrationExtension $extension */ $extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension'); - self::assertTrue($extension->supports(AliasedEntityInterface::class),'AliasedEntityInterface should be supported'); - self::assertTrue($extension->supports(AliasedEntity::class),'AliasedEntity should be supported'); - self::assertFalse($extension->supports('UnknownClass'),'UnknownClass should not be supported'); + self::assertTrue($extension->supports(AliasedEntityInterface::class), 'AliasedEntityInterface should be supported'); + self::assertTrue($extension->supports(AliasedEntity::class), 'AliasedEntity should be supported'); + self::assertFalse($extension->supports('UnknownClass'), 'UnknownClass should not be supported'); } public function testHydrationFromInterface(): void @@ -81,7 +80,7 @@ public function testHydrationFromInterface(): void $entityFromDehydratation = $extension->hydrate($dehydratedData, AliasedEntityInterface::class); - self::assertSame($existingEntity, $entityFromDehydratation,'instance should be the same'); - self::assertNull($extension->hydrate(null, AliasedEntityInterface::class),'should return null if null is passed'); + self::assertSame($existingEntity, $entityFromDehydratation, 'instance should be the same'); + self::assertNull($extension->hydrate(null, AliasedEntityInterface::class), 'should return null if null is passed'); } } From 8b2cc83699d6df8a0a35c077b0bd6edb2c49f308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Thu, 12 Jun 2025 21:21:10 +0200 Subject: [PATCH 08/11] Code styling --- .../src/Hydration/DoctrineEntityHydrationExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index 3333408e3f2..7c56d480c16 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -13,8 +13,8 @@ use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; -use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\Mapping\MappingException; +use Doctrine\Persistence\ObjectManager; /** * Handles hydration of Doctrine entities. From bbe77167f3db795d1fc4b6a714d074968ae271f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Fri, 13 Jun 2025 22:14:37 +0200 Subject: [PATCH 09/11] Refactored : explicit separation between classes and interfaces --- .../DoctrineEntityHydrationExtension.php | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index 7c56d480c16..2ba2c366dc4 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -81,28 +81,42 @@ public function dehydrate(object $object): mixed private function objectManagerFor(string $class): ?ObjectManager { - if (!class_exists($class) && !interface_exists($class)) { + if (class_exists($class)) { + // Keep the standard way for a class + // todo cache/warmup an array of classes that are "doctrine objects" + foreach ($this->managerRegistries as $registry) { + if ($om = $registry->getManagerForClass($class)) { + return self::ensureManagedObject($om, $class); + } + } return null; } - // todo cache/warmup an array of classes that are "doctrine objects" - foreach ($this->managerRegistries as $registry) { - // The doctrine registry does not resolve aliased interface - // if ($om = $registry->getManagerForClass($class)) { - // return self::ensureManagedObject($om, $class); - // } - foreach ($registry->getManagers() as $om) { - // But we can resolve nicely by trying to ask each manager to get the metadata - try { - if (null !== $om->getClassMetadata($class)) { - return self::ensureManagedObject($om, $class); + if (interface_exists($class)) { + // special handler for interfaces + // For use cases : @see https://symfony.com/doc/current/doctrine/resolve_target_entity.html + // As today, getManagerForClass don't resolve nicely aliased interfaces + // The workaround is to enum over each object manager and trying to get metadata + // The metadata are indeed, resolved nicely + // Fore more details : + // @see \Doctrine\ORM\Tools\ResolveTargetEntityListener + + // todo cache/warmup an array of interfaces that are resolved "doctrine objects" + foreach ($this->managerRegistries as $registry) { + foreach ($registry->getManagers() as $om) { + // the getClassMetaData can indeed throw an exception + // so, we + try { + if (null !== $om->getClassMetadata($class)) { + return self::ensureManagedObject($om, $class); + } + } catch (MappingException $e) { + // I did not find a nice way to check if it is because the class is really unknown + // It is good to check for a specific exception ? + // eg: \Doctrine\Persistence\Mapping\MappingException + // @see \Doctrine\Persistence\Mapping\AbstractClassMetadataFactory::getMetadataFor + // throw $e; } - } catch (MappingException $e) { - // I did not find a nice way to check if it is because the class is really unknown - // It is good to check for a specific exception ? - // eg: \Doctrine\Persistence\Mapping\MappingException - // Maybe not needed, because it does not failed even when the class does not exist at all - // throw $e; } } } From b134d9f8ae5c710877942c505c27741b8ecfd438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Sat, 14 Jun 2025 08:58:26 +0200 Subject: [PATCH 10/11] Code styling --- .../src/Hydration/DoctrineEntityHydrationExtension.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index 2ba2c366dc4..9f3264fc224 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -85,9 +85,9 @@ private function objectManagerFor(string $class): ?ObjectManager // Keep the standard way for a class // todo cache/warmup an array of classes that are "doctrine objects" foreach ($this->managerRegistries as $registry) { - if ($om = $registry->getManagerForClass($class)) { - return self::ensureManagedObject($om, $class); - } + if ($om = $registry->getManagerForClass($class)) { + return self::ensureManagedObject($om, $class); + } } return null; } From 7c3bdd9611b7868aec81668635f12e16431f03aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20COTON?= Date: Sat, 14 Jun 2025 09:00:02 +0200 Subject: [PATCH 11/11] Code styling --- .../src/Hydration/DoctrineEntityHydrationExtension.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php index 9f3264fc224..583717bfc0d 100644 --- a/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php +++ b/src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php @@ -86,9 +86,10 @@ private function objectManagerFor(string $class): ?ObjectManager // todo cache/warmup an array of classes that are "doctrine objects" foreach ($this->managerRegistries as $registry) { if ($om = $registry->getManagerForClass($class)) { - return self::ensureManagedObject($om, $class); + return self::ensureManagedObject($om, $class); } } + return null; }