Skip to content

Commit 953721e

Browse files
committed
[LiveComponent] Only consider Live components in InterceptChildComponentRenderSubscriber
1 parent 19feb79 commit 953721e

File tree

4 files changed

+69
-26
lines changed

4 files changed

+69
-26
lines changed

src/LiveComponent/src/DependencyInjection/LiveComponentExtension.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
use Symfony\UX\LiveComponent\Twig\TemplateMap;
4242
use Symfony\UX\LiveComponent\Util\ChildComponentPartialRenderer;
4343
use Symfony\UX\LiveComponent\Util\FingerprintCalculator;
44+
use Symfony\UX\LiveComponent\Util\LiveComponentStack;
4445
use Symfony\UX\LiveComponent\Util\LiveControllerAttributesCreator;
4546
use Symfony\UX\LiveComponent\Util\TwigAttributeHelperFactory;
4647
use Symfony\UX\TwigComponent\ComponentFactory;
@@ -113,7 +114,7 @@ function (ChildDefinition $definition, AsLiveComponent $attribute) {
113114
$container->register('ux.live_component.event_listener.data_model_props_subscriber', DataModelPropsSubscriber::class)
114115
->addTag('kernel.event_subscriber')
115116
->setArguments([
116-
new Reference('ux.twig_component.component_stack'),
117+
new Reference('ux.twig_component.live_component_stack'),
117118
new Reference('property_accessor'),
118119
])
119120
;
@@ -130,10 +131,16 @@ function (ChildDefinition $definition, AsLiveComponent $attribute) {
130131
$container->register('ux.live_component.live_responder', LiveResponder::class);
131132
$container->setAlias(LiveResponder::class, 'ux.live_component.live_responder');
132133

133-
$container->register('ux.live_component.intercept_child_component_render_subscriber', InterceptChildComponentRenderSubscriber::class)
134+
$container->register('ux.twig_component.live_component_stack', LiveComponentStack::class)
134135
->setArguments([
135136
new Reference('ux.twig_component.component_stack'),
136137
])
138+
;
139+
140+
$container->register('ux.live_component.intercept_child_component_render_subscriber', InterceptChildComponentRenderSubscriber::class)
141+
->setArguments([
142+
new Reference('ux.twig_component.live_component_stack'),
143+
])
137144
->addTag('container.service_subscriber', ['key' => DeterministicTwigIdCalculator::class, 'id' => 'ux.live_component.deterministic_id_calculator'])
138145
->addTag('container.service_subscriber', ['key' => ChildComponentPartialRenderer::class, 'id' => 'ux.live_component.child_component_partial_renderer'])
139146
->addTag('kernel.event_subscriber');

src/LiveComponent/src/EventListener/DataModelPropsSubscriber.php

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313

1414
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1515
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
16-
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
16+
use Symfony\UX\LiveComponent\Util\LiveComponentStack;
1717
use Symfony\UX\LiveComponent\Util\ModelBindingParser;
18-
use Symfony\UX\TwigComponent\ComponentStack;
1918
use Symfony\UX\TwigComponent\Event\PreMountEvent;
20-
use Symfony\UX\TwigComponent\MountedComponent;
2119

2220
/**
2321
* Parses the "data-model" key, which triggers extra props to be passed in.
@@ -33,7 +31,7 @@ final class DataModelPropsSubscriber implements EventSubscriberInterface
3331
{
3432
private ModelBindingParser $modelBindingParser;
3533

36-
public function __construct(private ComponentStack $componentStack, private PropertyAccessorInterface $propertyAccessor)
34+
public function __construct(private LiveComponentStack $componentStack, private PropertyAccessorInterface $propertyAccessor)
3735
{
3836
$this->modelBindingParser = new ModelBindingParser();
3937
}
@@ -58,7 +56,7 @@ public function onPreMount(PreMountEvent $event): void
5856

5957
// find the first parent of the component about to be rendered that is a Live Component
6058
// only those can have properties controlled via the data-model attribute
61-
$parentMountedComponent = $this->getCurrentLiveComponent($this->componentStack);
59+
$parentMountedComponent = $this->componentStack->getCurrentLiveComponent();
6260
if (null === $parentMountedComponent) {
6361
throw new \LogicException('You can only pass "data-model" when rendering a component when you\'re rendering inside of a parent component.');
6462
}
@@ -79,20 +77,4 @@ public static function getSubscribedEvents(): array
7977
PreMountEvent::class => 'onPreMount',
8078
];
8179
}
82-
83-
private function getCurrentLiveComponent(ComponentStack $componentStack): ?MountedComponent
84-
{
85-
foreach ($componentStack as $mountedComponent) {
86-
if ($this->isLiveComponent($mountedComponent->getComponent()::class)) {
87-
return $mountedComponent;
88-
}
89-
}
90-
91-
return null;
92-
}
93-
94-
private function isLiveComponent(string $classname): bool
95-
{
96-
return [] !== (new \ReflectionClass($classname))->getAttributes(AsLiveComponent::class);
97-
}
9880
}

src/LiveComponent/src/EventListener/InterceptChildComponentRenderSubscriber.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
use Symfony\Contracts\Service\ServiceSubscriberInterface;
1717
use Symfony\UX\LiveComponent\Twig\DeterministicTwigIdCalculator;
1818
use Symfony\UX\LiveComponent\Util\ChildComponentPartialRenderer;
19+
use Symfony\UX\LiveComponent\Util\LiveComponentStack;
1920
use Symfony\UX\LiveComponent\Util\LiveControllerAttributesCreator;
20-
use Symfony\UX\TwigComponent\ComponentStack;
2121
use Symfony\UX\TwigComponent\Event\PreCreateForRenderEvent;
2222

2323
/**
@@ -34,15 +34,15 @@ class InterceptChildComponentRenderSubscriber implements EventSubscriberInterfac
3434
public const CHILDREN_FINGERPRINTS_METADATA_KEY = 'children_fingerprints';
3535

3636
public function __construct(
37-
private ComponentStack $componentStack,
37+
private LiveComponentStack $componentStack,
3838
private ContainerInterface $container,
3939
) {
4040
}
4141

4242
public function preComponentCreated(PreCreateForRenderEvent $event): void
4343
{
4444
// if there is already a component, that's a parent. Else, this is not a child.
45-
if (null === $parentComponent = $this->componentStack->getCurrentComponent()) {
45+
if (null === $parentComponent = $this->componentStack->getCurrentLiveComponent()) {
4646
return;
4747
}
4848

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symfony\UX\LiveComponent\Util;
6+
7+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
8+
use Symfony\UX\TwigComponent\ComponentStack;
9+
use Symfony\UX\TwigComponent\MountedComponent;
10+
11+
/**
12+
* This class decorates the TwigComponent\ComponentStack adding specific Live component functionalities.
13+
*
14+
* @author Bart Vanderstukken <bart.vanderstukken@gmail.com>
15+
*
16+
* @internal
17+
*/
18+
final class LiveComponentStack extends ComponentStack
19+
{
20+
public function __construct(private readonly ComponentStack $componentStack)
21+
{
22+
}
23+
24+
public function getCurrentLiveComponent(): ?MountedComponent
25+
{
26+
foreach ($this->componentStack as $mountedComponent) {
27+
if ($this->isLiveComponent($mountedComponent->getComponent()::class)) {
28+
return $mountedComponent;
29+
}
30+
}
31+
32+
return null;
33+
}
34+
35+
private function isLiveComponent(string $classname): bool
36+
{
37+
return [] !== (new \ReflectionClass($classname))->getAttributes(AsLiveComponent::class);
38+
}
39+
40+
public function getCurrentComponent(): ?MountedComponent
41+
{
42+
return $this->componentStack->getCurrentComponent();
43+
}
44+
45+
public function getParentComponent(): ?MountedComponent
46+
{
47+
return $this->componentStack->getParentComponent();
48+
}
49+
50+
public function hasParentComponent(): bool
51+
{
52+
return $this->componentStack->hasParentComponent();
53+
}
54+
}

0 commit comments

Comments
 (0)