Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\Mapping\MappingException;
use Doctrine\Persistence\ObjectManager;

/**
Expand Down Expand Up @@ -61,8 +62,7 @@ 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);
Expand All @@ -81,14 +81,36 @@ public function dehydrate(object $object): mixed

private function objectManagerFor(string $class): ?ObjectManager
{
if (!class_exists($class)) {
if (class_exists($class)) {
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) {
if ($om = $registry->getManagerForClass($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 :
Comment on lines +95 to +100
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we turn this into two or three lines, insisting more on what we "do" than on what "was" the problem ?

// @see \Doctrine\ORM\Tools\ResolveTargetEntityListener

foreach ($this->managerRegistries as $registry) {
foreach ($registry->getManagers() as $om) {

try {
if (null !== $om->getClassMetadata($class)) {
return self::ensureManagedObject($om, $class);
}
} catch (MappingException $e) {
// Catching Excpetion in case of the $class does not match a valid classname or a valid interface name
}
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/LiveComponent/tests/Fixtures/Dto/Aliased.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Symfony\UX\LiveComponent\Tests\Fixtures\Dto;

class Aliased
{
public string $name;
}
27 changes: 27 additions & 0 deletions src/LiveComponent/tests/Fixtures/Entity/AliasedEntity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* 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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace Symfony\UX\LiveComponent\Tests\Fixtures\Entity;

interface AliasedEntityInterface {
}
5 changes: 5 additions & 0 deletions src/LiveComponent/tests/Fixtures/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
use Symfony\Component\Security\Core\User\InMemoryUser;
use Symfony\UX\LiveComponent\LiveComponentBundle;
use Symfony\UX\LiveComponent\Tests\Fixtures\Component\Component1;
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntity;
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\AliasedEntityInterface;
use Symfony\UX\LiveComponent\Tests\Fixtures\Serializer\Entity2Normalizer;
use Symfony\UX\LiveComponent\Tests\Fixtures\Serializer\MoneyNormalizer;
use Symfony\UX\StimulusBundle\StimulusBundle;
Expand Down Expand Up @@ -170,6 +172,9 @@ protected function configureContainer(ContainerConfigurator $c): void
'alias' => 'XML',
],
],
'resolve_target_entities' => [
AliasedEntityInterface::class => AliasedEntity::class,
],
],
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@

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

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
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;
Expand Down Expand Up @@ -50,4 +53,34 @@ public function testForeignKeyId(): void
self::assertSame($foreignKeyIdEntity->id->id, $dehydrated);
self::assertSame($foreignKeyIdEntity, $extension->hydrate($dehydrated, ForeignKeyIdEntity::class));
}

public function testSupportInterface()
{
/** @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()
{
/** @var DoctrineEntityHydrationExtension $extension */
$extension = self::getContainer()->get('ux.live_component.doctrine_entity_hydration_extension');
$em = self::getContainer()->get(EntityManagerInterface::class);

$existingEntity = new AliasedEntity();
$existingEntity->name = 'foo';

$em->persist($existingEntity);
$em->flush();

$dehydratedData = $extension->dehydrate($existingEntity);

$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');
}
}
Loading