Skip to content

Commit c971111

Browse files
committed
Updating hydrator
Making tests
1 parent 41ace4f commit c971111

File tree

6 files changed

+112
-11
lines changed

6 files changed

+112
-11
lines changed

src/LiveComponent/src/Hydration/DoctrineEntityHydrationExtension.php

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Doctrine\ORM\EntityManagerInterface;
1515
use Doctrine\Persistence\ManagerRegistry;
1616
use Doctrine\Persistence\ObjectManager;
17+
use Doctrine\Persistence\Mapping\MappingException;
1718

1819
/**
1920
* Handles hydration of Doctrine entities.
@@ -27,7 +28,8 @@ class DoctrineEntityHydrationExtension implements HydrationExtensionInterface
2728
*/
2829
public function __construct(
2930
private iterable $managerRegistries,
30-
) {
31+
)
32+
{
3133
}
3234

3335
public function supports(string $className): bool
@@ -61,11 +63,10 @@ public function dehydrate(object $object): mixed
6163
$id = $this
6264
->objectManagerFor($class = $object::class)
6365
->getClassMetadata($class)
64-
->getIdentifierValues($object)
65-
;
66+
->getIdentifierValues($object);
6667

6768
// Dehydrate ID values in case they are other entities
68-
$id = array_map(fn ($id) => \is_object($id) && $this->supports($id::class) ? $this->dehydrate($id) : $id, $id);
69+
$id = array_map(fn($id) => \is_object($id) && $this->supports($id::class) ? $this->dehydrate($id) : $id, $id);
6970

7071
switch (\count($id)) {
7172
case 0:
@@ -81,21 +82,34 @@ public function dehydrate(object $object): mixed
8182

8283
private function objectManagerFor(string $class): ?ObjectManager
8384
{
84-
if (!interface_exist($class) && !class_exists($class)) {
85+
if (!interface_exists($class) && !class_exists($class)) {
8586
return null;
8687
}
8788

8889
// todo cache/warmup an array of classes that are "doctrine objects"
8990
foreach ($this->managerRegistries as $registry) {
90-
foreach($registry->getManagers() as $om) {
91-
// this way, it resolves the interface
92-
if ($om->getClassMetadata($class)) {
93-
return self::ensureManagedObject($om, $class);
94-
}
95-
}
91+
92+
// The doctrine registry does not resolve aliased interface
9693
// if ($om = $registry->getManagerForClass($class)) {
9794
// return self::ensureManagedObject($om, $class);
9895
// }
96+
97+
foreach ($registry->getManagers() as $om) {
98+
// But we can resolve nicely by trying to ask each manager to get the metadata
99+
try {
100+
if ($om->getClassMetadata($class) !== null) {
101+
return self::ensureManagedObject($om, $class);
102+
}
103+
104+
} catch (MappingException $e) {
105+
// I did not find a nice way to check if it is because the class is really unknown
106+
// It is good to check for a specific exception ?
107+
// eg: \Doctrine\Persistence\Mapping\MappingException
108+
// Maybe not needed, because it does not failed even when the class does not exist at all
109+
throw $e;
110+
}
111+
112+
}
99113
}
100114

101115
return null;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Symfony\UX\LiveComponent\Tests\Fixtures\Dto;
4+
5+
class Aliased
6+
{
7+
// public string $address;
8+
public string $name;
9+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\LiveComponent\Tests\Fixtures\Entity;
13+
14+
use Doctrine\ORM\Mapping as ORM;
15+
use Doctrine\ORM\Mapping\Column;
16+
17+
#[ORM\Entity]
18+
class AliasedEntity implements AliasedEntityInterface
19+
{
20+
#[ORM\Id]
21+
#[ORM\GeneratedValue]
22+
#[ORM\Column(type: 'integer')]
23+
public $id;
24+
25+
#[Column(type: 'string')]
26+
public ?string $name = null;
27+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\UX\LiveComponent\Tests\Fixtures\Entity;
4+
5+
interface AliasedEntityInterface {
6+
7+
}

src/LiveComponent/tests/Fixtures/Kernel.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
use Symfony\Component\Security\Core\User\InMemoryUser;
3030
use Symfony\UX\LiveComponent\LiveComponentBundle;
3131
use Symfony\UX\LiveComponent\Tests\Fixtures\Component\Component1;
32+
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntity;
33+
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntityInterface;
3234
use Symfony\UX\LiveComponent\Tests\Fixtures\Serializer\Entity2Normalizer;
3335
use Symfony\UX\LiveComponent\Tests\Fixtures\Serializer\MoneyNormalizer;
3436
use Symfony\UX\StimulusBundle\StimulusBundle;
@@ -170,6 +172,8 @@ protected function configureContainer(ContainerConfigurator $c): void
170172
'alias' => 'XML',
171173
],
172174
],
175+
'resolve_target_entities' => [
176+
AliasedEntityInterface::class => AliasedEntity::class],
173177
],
174178
];
175179

src/LiveComponent/tests/Integration/Hydration/DoctrineEntityHydrationExtensionTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,15 @@
1111

1212
namespace Symfony\UX\LiveComponent\Tests\Integration\Hydration;
1313

14+
use Doctrine\ORM\EntityManager;
15+
use Doctrine\ORM\EntityManagerInterface;
16+
use Doctrine\ORM\Tools\ResolveTargetEntityListener;
1417
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
18+
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
19+
use Symfony\Contracts\Service\Attribute\Required;
1520
use Symfony\UX\LiveComponent\Hydration\DoctrineEntityHydrationExtension;
21+
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntity;
22+
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntityInterface;
1623
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\CompositeIdEntity;
1724
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\ForeignKeyIdEntity;
1825
use Symfony\UX\LiveComponent\Tests\Fixtures\Factory\CompositeIdEntityFactory;
@@ -50,4 +57,37 @@ public function testForeignKeyId(): void
5057
self::assertSame($foreignKeyIdEntity->id->id, $dehydrated);
5158
self::assertSame($foreignKeyIdEntity, $extension->hydrate($dehydrated, ForeignKeyIdEntity::class));
5259
}
60+
61+
62+
public function testSupportInterface(): void
63+
{
64+
/** @var DoctrineEntityHydrationExtension $extension */
65+
$extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension');
66+
67+
self::assertTrue($extension->supports(AliasedEntityInterface::class),"AliasedEntityInterface should be supported");
68+
self::assertTrue($extension->supports(AliasedEntity::class),"AliasedEntity should be supported");
69+
self::assertFalse($extension->supports('UnknownClass'),"UnknownClass should not be supported");
70+
}
71+
72+
public function testHydrationFromInterface(): void
73+
{
74+
/** @var DoctrineEntityHydrationExtension $extension */
75+
$extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension');
76+
$em = self::getContainer()->get(EntityManagerInterface::class);
77+
78+
$a = new AliasedEntity();
79+
$a->name = 'foo';
80+
81+
$em->persist($a);
82+
$em->flush();
83+
84+
$dehydratedData = $extension->dehydrate($a);
85+
86+
$a2 = $extension->hydrate($dehydratedData, AliasedEntityInterface::class);
87+
88+
self::assertSame($a, $a2,"instance should be the same");
89+
self::assertNull($extension->hydrate(null, AliasedEntityInterface::class),"should return null if null is passed");
90+
91+
92+
}
5393
}

0 commit comments

Comments
 (0)