Skip to content

Commit d5c5925

Browse files
committed
Fix real class resolve
1 parent 157de88 commit d5c5925

File tree

10 files changed

+108
-30
lines changed

10 files changed

+108
-30
lines changed

src/Turbo/config/services.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
1313

1414
use Symfony\UX\Turbo\Broadcaster\BroadcasterInterface;
15-
use Symfony\UX\Turbo\Broadcaster\DoctrineIdAccessor;
1615
use Symfony\UX\Turbo\Broadcaster\IdAccessor;
1716
use Symfony\UX\Turbo\Broadcaster\IdFormatter;
1817
use Symfony\UX\Turbo\Broadcaster\ImuxBroadcaster;
1918
use Symfony\UX\Turbo\Broadcaster\TwigBroadcaster;
2019
use Symfony\UX\Turbo\Doctrine\BroadcastListener;
20+
use Symfony\UX\Turbo\Doctrine\DoctrineClassResolver;
21+
use Symfony\UX\Turbo\Doctrine\DoctrineIdAccessor;
2122
use Symfony\UX\Turbo\Twig\TwigExtension;
2223

2324
/*
@@ -31,6 +32,11 @@
3132

3233
->alias(BroadcasterInterface::class, 'turbo.broadcaster.imux')
3334

35+
->set('turbo.doctrine_class_resolver', DoctrineClassResolver::class)
36+
->args([
37+
service('doctrine')->nullOnInvalid(),
38+
])
39+
3440
->set('turbo.id_formatter', IdFormatter::class)
3541

3642
->set('turbo.doctrine_id_accessor', DoctrineIdAccessor::class)
@@ -51,6 +57,7 @@
5157
abstract_arg('entity template prefixes'),
5258
service('turbo.id_accessor'),
5359
service('turbo.id_formatter'),
60+
service('turbo.doctrine_class_resolver'),
5461
])
5562
->decorate('turbo.broadcaster.imux')
5663

@@ -63,6 +70,7 @@
6370
service('turbo.broadcaster.imux'),
6471
service('annotation_reader')->nullOnInvalid(),
6572
service('turbo.doctrine_id_accessor'),
73+
service('turbo.doctrine_class_resolver'),
6674
])
6775
->tag('doctrine.event_listener', ['event' => 'onFlush'])
6876
->tag('doctrine.event_listener', ['event' => 'postFlush'])

src/Turbo/src/Bridge/Mercure/Broadcaster.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\UX\Turbo\Broadcaster\BroadcasterInterface;
1818
use Symfony\UX\Turbo\Broadcaster\IdFormatter;
1919
use Symfony\UX\Turbo\Doctrine\ClassUtil;
20+
use Symfony\UX\Turbo\Doctrine\DoctrineClassResolver;
2021

2122
/**
2223
* Broadcasts updates rendered using Twig with Mercure.
@@ -44,15 +45,17 @@ final class Broadcaster implements BroadcasterInterface
4445
private $name;
4546
private $hub;
4647
private $idFormatter;
48+
private $doctrineClassResolver;
4749

4850
/** @var ExpressionLanguage|null */
4951
private $expressionLanguage;
5052

51-
public function __construct(string $name, HubInterface $hub, ?IdFormatter $idFormatter = null)
53+
public function __construct(string $name, HubInterface $hub, ?IdFormatter $idFormatter = null, ?DoctrineClassResolver $doctrineClassResolver = null)
5254
{
5355
$this->name = $name;
5456
$this->hub = $hub;
5557
$this->idFormatter = $idFormatter ?? new IdFormatter();
58+
$this->doctrineClassResolver = $doctrineClassResolver ?? new DoctrineClassResolver();
5659

5760
if (class_exists(ExpressionLanguage::class)) {
5861
$this->expressionLanguage = new ExpressionLanguage();
@@ -65,7 +68,7 @@ public function broadcast(object $entity, string $action, array $options): void
6568
return;
6669
}
6770

68-
$entityClass = ClassUtil::getEntityClass($entity);
71+
$entityClass = $this->doctrineClassResolver->resolve($entity);
6972

7073
if (!isset($options['rendered_action'])) {
7174
throw new \InvalidArgumentException(sprintf('Cannot broadcast entity of class "%s" as option "rendered_action" is missing.', $entityClass));

src/Turbo/src/Bridge/Mercure/TurboStreamListenRenderer.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\UX\StimulusBundle\Helper\StimulusHelper;
1616
use Symfony\UX\Turbo\Broadcaster\IdAccessor;
1717
use Symfony\UX\Turbo\Broadcaster\IdFormatter;
18+
use Symfony\UX\Turbo\Doctrine\DoctrineClassResolver;
1819
use Symfony\UX\Turbo\Twig\TurboStreamListenRendererInterface;
1920
use Symfony\WebpackEncoreBundle\Twig\StimulusTwigExtension;
2021
use Twig\Environment;
@@ -30,15 +31,17 @@ final class TurboStreamListenRenderer implements TurboStreamListenRendererInterf
3031
private StimulusHelper $stimulusHelper;
3132
private IdAccessor $idAccessor;
3233
private IdFormatter $idFormatter;
34+
private DoctrineClassResolver $doctrineClassResolver;
3335

3436
/**
3537
* @param $stimulus StimulusHelper
3638
*/
37-
public function __construct(HubInterface $hub, StimulusHelper|StimulusTwigExtension $stimulus, IdAccessor $idAccessor, ?IdFormatter $idFormatter = null)
39+
public function __construct(HubInterface $hub, StimulusHelper|StimulusTwigExtension $stimulus, IdAccessor $idAccessor, ?IdFormatter $idFormatter = null, ?DoctrineClassResolver $doctrineClassResolver = null)
3840
{
3941
$this->hub = $hub;
4042
$this->idAccessor = $idAccessor;
4143
$this->idFormatter = $idFormatter ?? new IdFormatter();
44+
$this->doctrineClassResolver = $doctrineClassResolver ?? new DoctrineClassResolver();
4245

4346
if ($stimulus instanceof StimulusTwigExtension) {
4447
trigger_deprecation('symfony/ux-turbo', '2.9', 'Passing an instance of "%s" as second argument of "%s" is deprecated, pass an instance of "%s" instead.', StimulusTwigExtension::class, __CLASS__, StimulusHelper::class);
@@ -52,7 +55,7 @@ public function __construct(HubInterface $hub, StimulusHelper|StimulusTwigExtens
5255
public function renderTurboStreamListen(Environment $env, $topic): string
5356
{
5457
if (\is_object($topic)) {
55-
$class = $topic::class;
58+
$class = $this->doctrineClassResolver->resolve($topic);
5659

5760
if (!$id = $this->idAccessor->getEntityId($topic)) {
5861
throw new \LogicException(sprintf('Cannot listen to entity of class "%s" as the PropertyAccess component is not installed. Try running "composer require symfony/property-access".', $class));

src/Turbo/src/Broadcaster/IdAccessor.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\PropertyAccess\PropertyAccess;
1515
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
16+
use Symfony\UX\Turbo\Doctrine\DoctrineIdAccessor;
1617

1718
class IdAccessor
1819
{

src/Turbo/src/Broadcaster/TwigBroadcaster.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\UX\Turbo\Broadcaster;
1313

1414
use Symfony\UX\Turbo\Doctrine\ClassUtil;
15+
use Symfony\UX\Turbo\Doctrine\DoctrineClassResolver;
1516
use Twig\Environment;
1617

1718
/**
@@ -26,17 +27,19 @@ final class TwigBroadcaster implements BroadcasterInterface
2627
private $templatePrefixes;
2728
private $idAccessor;
2829
private $idFormatter;
30+
private $doctrineClassResolver;
2931

3032
/**
3133
* @param array<string, string> $templatePrefixes
3234
*/
33-
public function __construct(BroadcasterInterface $broadcaster, Environment $twig, array $templatePrefixes = [], ?IdAccessor $idAccessor = null, ?IdFormatter $idFormatter = null)
35+
public function __construct(BroadcasterInterface $broadcaster, Environment $twig, array $templatePrefixes = [], ?IdAccessor $idAccessor = null, ?IdFormatter $idFormatter = null, ?DoctrineClassResolver $doctrineClassResolver = null)
3436
{
3537
$this->broadcaster = $broadcaster;
3638
$this->twig = $twig;
3739
$this->templatePrefixes = $templatePrefixes;
3840
$this->idAccessor = $idAccessor ?? new IdAccessor();
3941
$this->idFormatter = $idFormatter ?? new IdFormatter();
42+
$this->doctrineClassResolver = $doctrineClassResolver ?? new DoctrineClassResolver();
4043
}
4144

4245
public function broadcast(object $entity, string $action, array $options): void
@@ -45,10 +48,9 @@ public function broadcast(object $entity, string $action, array $options): void
4548
$options['id'] = $id;
4649
}
4750

48-
$class = ClassUtil::getEntityClass($entity);
49-
5051
if (null === $template = $options['template'] ?? null) {
51-
$template = $class;
52+
$template = $this->doctrineClassResolver->resolve($entity);
53+
5254
foreach ($this->templatePrefixes as $namespace => $prefix) {
5355
if (str_starts_with($template, $namespace)) {
5456
$template = substr_replace($template, $prefix, 0, \strlen($namespace));

src/Turbo/src/Doctrine/BroadcastListener.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
use Symfony\Contracts\Service\ResetInterface;
2020
use Symfony\UX\Turbo\Attribute\Broadcast;
2121
use Symfony\UX\Turbo\Broadcaster\BroadcasterInterface;
22-
use Symfony\UX\Turbo\Broadcaster\DoctrineIdAccessor;
2322

2423
/**
2524
* Detects changes made from Doctrine entities and broadcasts updates to the broadcasters.
@@ -31,6 +30,7 @@ final class BroadcastListener implements ResetInterface
3130
private $broadcaster;
3231
private $annotationReader;
3332
private $doctrineIdAccessor;
33+
private $doctrineClassResolver;
3434

3535
/**
3636
* @var array<class-string, array<mixed>>
@@ -50,13 +50,14 @@ final class BroadcastListener implements ResetInterface
5050
*/
5151
private $removedEntities;
5252

53-
public function __construct(BroadcasterInterface $broadcaster, ?Reader $annotationReader = null, ?DoctrineIdAccessor $doctrineIdAccessor = null)
53+
public function __construct(BroadcasterInterface $broadcaster, ?Reader $annotationReader = null, ?DoctrineIdAccessor $doctrineIdAccessor = null, ?DoctrineClassResolver $doctrineClassResolver = null)
5454
{
5555
$this->reset();
5656

5757
$this->broadcaster = $broadcaster;
5858
$this->annotationReader = $annotationReader;
5959
$this->doctrineIdAccessor = $doctrineIdAccessor ?? new DoctrineIdAccessor();
60+
$this->doctrineClassResolver = $doctrineClassResolver ?? new DoctrineClassResolver();
6061
}
6162

6263
/**
@@ -97,7 +98,7 @@ public function postFlush(EventArgs $eventArgs): void
9798
try {
9899
foreach ($this->createdEntities as $entity) {
99100
$options = $this->createdEntities[$entity];
100-
$id = $this->doctrineIdAccessor->getEntityId($entity);
101+
$id = $this->doctrineIdAccessor->getEntityId($entity, $em);
101102
foreach ($options as $option) {
102103
$option['id'] = $id;
103104
$this->broadcaster->broadcast($entity, Broadcast::ACTION_CREATE, $option);
@@ -129,28 +130,28 @@ public function reset(): void
129130

130131
private function storeEntitiesToPublish(EntityManagerInterface $em, object $entity, string $property): void
131132
{
132-
$class = ClassUtil::getEntityClass($entity);
133+
$entityClass = $this->doctrineClassResolver->resolve($entity, $em);
133134

134-
if (!isset($this->broadcastedClasses[$class])) {
135-
$this->broadcastedClasses[$class] = [];
136-
$r = new \ReflectionClass($class);
135+
if (!isset($this->broadcastedClasses[$entityClass])) {
136+
$this->broadcastedClasses[$entityClass] = [];
137+
$r = new \ReflectionClass($entityClass);
137138

138139
if ($options = $r->getAttributes(Broadcast::class)) {
139140
foreach ($options as $option) {
140-
$this->broadcastedClasses[$class][] = $option->newInstance()->options;
141+
$this->broadcastedClasses[$entityClass][] = $option->newInstance()->options;
141142
}
142143
} elseif ($this->annotationReader && $options = $this->annotationReader->getClassAnnotations($r)) {
143144
foreach ($options as $option) {
144145
if ($option instanceof Broadcast) {
145-
$this->broadcastedClasses[$class][] = $option->options;
146+
$this->broadcastedClasses[$entityClass][] = $option->options;
146147
}
147148
}
148149
}
149150
}
150151

151-
if ($options = $this->broadcastedClasses[$class]) {
152+
if ($options = $this->broadcastedClasses[$entityClass]) {
152153
if ('createdEntities' !== $property) {
153-
$id = $this->doctrineIdAccessor->getEntityId($entity);
154+
$id = $this->doctrineIdAccessor->getEntityId($entity, $em);
154155
foreach ($options as $k => $option) {
155156
$options[$k]['id'] = $id;
156157
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Symfony\UX\Turbo\Doctrine;
4+
5+
use Doctrine\ORM\Mapping\ClassMetadata;
6+
use Doctrine\Persistence\ManagerRegistry;
7+
use Doctrine\Persistence\ObjectManager;
8+
9+
class DoctrineClassResolver
10+
{
11+
private $doctrine;
12+
13+
public function __construct(?ManagerRegistry $doctrine = null)
14+
{
15+
$this->doctrine = $doctrine;
16+
}
17+
18+
/**
19+
* @param object $entity
20+
* @return class-string
21+
*/
22+
public function resolve(object $entity, ?ObjectManager $em = null): string
23+
{
24+
$class = ClassUtil::getEntityClass($entity);
25+
26+
if (!$this->doctrine) {
27+
return $class;
28+
}
29+
30+
$em = $em ?? $this->doctrine->getManagerForClass($class);
31+
32+
if (!$em) {
33+
return $class;
34+
}
35+
36+
$classMetadata = $em->getClassMetadata($class);
37+
38+
if ($classMetadata instanceof ClassMetadata) {
39+
return $classMetadata->rootEntityName;
40+
}
41+
42+
return $class;
43+
}
44+
}

src/Turbo/src/Broadcaster/DoctrineIdAccessor.php renamed to src/Turbo/src/Doctrine/DoctrineIdAccessor.php

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\UX\Turbo\Broadcaster;
12+
namespace Symfony\UX\Turbo\Doctrine;
1313

1414
use Doctrine\Persistence\ManagerRegistry;
1515
use Doctrine\Persistence\ObjectManager;
16-
use Symfony\UX\Turbo\Doctrine\ClassUtil;
1716

1817
/**
1918
* @author Jason Schilling <[email protected]>
@@ -30,11 +29,11 @@ public function __construct(?ManagerRegistry $doctrine = null)
3029
/**
3130
* @return array<string, array<string, string>>|array<string, string>|null
3231
*/
33-
public function getEntityId(object $entity): ?array
32+
public function getEntityId(object $entity, ?ObjectManager $em = null): ?array
3433
{
35-
$entityClass = ClassUtil::getEntityClass($entity);
34+
$em = $em ?? $this->doctrine?->getManagerForClass($entity::class);
3635

37-
if ($this->doctrine && $em = $this->doctrine->getManagerForClass($entityClass)) {
36+
if ($em) {
3837
return $this->getIdentifierValues($em, $entity);
3938
}
4039

@@ -46,9 +45,7 @@ public function getEntityId(object $entity): ?array
4645
*/
4746
private function getIdentifierValues(ObjectManager $em, object $entity): array
4847
{
49-
$class = ClassUtil::getEntityClass($entity);
50-
51-
$values = $em->getClassMetadata($class)->getIdentifierValues($entity);
48+
$values = $em->getClassMetadata($entity::class)->getIdentifierValues($entity);
5249

5350
foreach ($values as $key => $value) {
5451
if (\is_object($value)) {

src/Turbo/src/TurboBundle.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1515
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
use Symfony\Component\DependencyInjection\Reference;
1718
use Symfony\Component\HttpFoundation\Request;
1819
use Symfony\Component\HttpKernel\Bundle\Bundle;
1920

@@ -34,7 +35,7 @@ public function build(ContainerBuilder $container): void
3435
{
3536
parent::build($container);
3637

37-
$container->addCompilerPass(new class() implements CompilerPassInterface {
38+
$container->addCompilerPass(new class () implements CompilerPassInterface {
3839
public function process(ContainerBuilder $container): void
3940
{
4041
if (!$container->hasDefinition('turbo.broadcaster.imux')) {
@@ -45,6 +46,24 @@ public function process(ContainerBuilder $container): void
4546
}
4647
}
4748
}, PassConfig::TYPE_BEFORE_REMOVING);
49+
50+
$container->addCompilerPass(new class () implements CompilerPassInterface {
51+
public function process(ContainerBuilder $container): void
52+
{
53+
$serviceIds = [
54+
...$container->findTaggedServiceIds('turbo.broadcaster'),
55+
...$container->findTaggedServiceIds('turbo.renderer.stream_listen'),
56+
];
57+
58+
foreach ($serviceIds as $serviceId => $tags) {
59+
$definition = $container->getDefinition($serviceId);
60+
61+
$definition
62+
->addArgument(new Reference('turbo.id_formatter'))
63+
->addArgument(new Reference('turbo.doctrine_class_resolver'));
64+
}
65+
}
66+
});
4867
}
4968

5069
public function getPath(): string

src/Turbo/tests/app/Entity/Song.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Song
2424
#[ORM\Id]
2525
#[ORM\GeneratedValue(strategy: 'AUTO')]
2626
#[ORM\Column(type: 'integer')]
27-
public ?string $id = null;
27+
public ?int $id = null;
2828

2929
#[ORM\Column]
3030
public string $title = '';

0 commit comments

Comments
 (0)