Skip to content

Commit 3517dcb

Browse files
committed
Allow co living components with discriminator attribute
1 parent aff83f2 commit 3517dcb

File tree

6 files changed

+66
-15
lines changed

6 files changed

+66
-15
lines changed

src/LiveComponent/src/EventListener/QueryStringInitializeSubscriber.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpFoundation\RequestStack;
1616
use Symfony\UX\LiveComponent\Metadata\LiveComponentMetadata;
1717
use Symfony\UX\LiveComponent\Metadata\LiveComponentMetadataFactory;
18+
use Symfony\UX\LiveComponent\Util\LiveControllerAttributesCreator;
1819
use Symfony\UX\LiveComponent\Util\QueryStringPropsExtractor;
1920
use Symfony\UX\TwigComponent\Event\PreMountEvent;
2021

@@ -58,7 +59,11 @@ public function onPreMount(PreMountEvent $event): void
5859

5960
$request = $this->requestStack->getMainRequest();
6061

61-
$queryStringData = $this->queryStringPropsExtractor->extract($request, $metadata, $component);
62+
$prefix = $data[LiveControllerAttributesCreator::URL_PREFIX_PROP_NAME]
63+
?? $data[LiveControllerAttributesCreator::KEY_PROP_NAME]
64+
?? '';
65+
66+
$queryStringData = $this->queryStringPropsExtractor->extract($request, $metadata, $component, $prefix);
6267

6368
$event->setData(array_merge($data, $queryStringData));
6469
}

src/LiveComponent/src/Metadata/LivePropMetadata.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function allowsNull(): bool
5555
}
5656

5757
/**
58-
* @return array{'parameters': array<string,array{'property': string}>}
58+
* @return array{'name': string}
5959
*/
6060
public function getQueryStringMapping(): array
6161
{

src/LiveComponent/src/Util/LiveControllerAttributesCreator.php

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class LiveControllerAttributesCreator
3939
*/
4040
public const KEY_PROP_NAME = 'key';
4141

42+
public const URL_PREFIX_PROP_NAME = 'query-param-prefix';
43+
4244
public function __construct(
4345
private LiveComponentMetadataFactory $metadataFactory,
4446
private LiveComponentHydrator $hydrator,
@@ -108,6 +110,28 @@ public function attributesForRendering(MountedComponent $mounted, ComponentMetad
108110
}
109111
}
110112

113+
$liveMetadata = $this->metadataFactory->getMetadata($mounted->getName());
114+
115+
if ($liveMetadata->hasQueryStringBindings()) {
116+
$urlPrefix = $mountedAttributes->all()[self::URL_PREFIX_PROP_NAME]
117+
?? $mounted->getInputProps()[self::KEY_PROP_NAME]
118+
?? '';
119+
120+
$queryMapping = [];
121+
foreach ($liveMetadata->getAllLivePropsMetadata() as $livePropMetadata) {
122+
if ($mapping = $livePropMetadata->getQueryStringMapping()) {
123+
$mapping['name'] = $urlPrefix.$mapping['name'];
124+
$queryMapping[$livePropMetadata->getName()] = $mapping;
125+
}
126+
}
127+
$attributesCollection->setQueryUrlMapping($queryMapping);
128+
129+
if ('' !== $urlPrefix) {
130+
// So the prefix is also used when the component is re-rendered in live
131+
$mountedAttributes = $mountedAttributes->defaults([self::URL_PREFIX_PROP_NAME => $urlPrefix]);
132+
}
133+
}
134+
111135
$dehydratedProps = $this->dehydrateComponent(
112136
$mounted->getName(),
113137
$mounted->getComponent(),
@@ -121,17 +145,6 @@ public function attributesForRendering(MountedComponent $mounted, ComponentMetad
121145
);
122146
}
123147

124-
$liveMetadata = $this->metadataFactory->getMetadata($mounted->getName());
125-
if ($liveMetadata->hasQueryStringBindings()) {
126-
$queryMapping = [];
127-
foreach ($liveMetadata->getAllLivePropsMetadata() as $livePropMetadata) {
128-
if ($mapping = $livePropMetadata->getQueryStringMapping()) {
129-
$queryMapping[$livePropMetadata->getName()] = $mapping;
130-
}
131-
}
132-
$attributesCollection->setQueryUrlMapping($queryMapping);
133-
}
134-
135148
return $attributesCollection;
136149
}
137150

src/LiveComponent/src/Util/QueryStringPropsExtractor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function __construct(private readonly LiveComponentHydrator $hydrator)
2828
{
2929
}
3030

31-
public function extract(Request $request, LiveComponentMetadata $metadata, object $component): array
31+
public function extract(Request $request, LiveComponentMetadata $metadata, object $component, string $prefix = ''): array
3232
{
3333
$query = $request->query->all();
3434

@@ -39,7 +39,7 @@ public function extract(Request $request, LiveComponentMetadata $metadata, objec
3939

4040
foreach ($metadata->getAllLivePropsMetadata() as $livePropMetadata) {
4141
if ($queryStringMapping = $livePropMetadata->getQueryStringMapping()) {
42-
if (null !== ($value = $query[$queryStringMapping['name']] ?? null)) {
42+
if (null !== ($value = $query[$prefix.$queryStringMapping['name']] ?? null)) {
4343
if (\is_array($value) && $this->isNumericIndexedArray($value)) {
4444
ksort($value);
4545
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{{ component('component_with_url_bound_props', {'id': 'component1', 'query-param-prefix': 'c1_'}) }}
2+
{{ component('component_with_url_bound_props', {'id': 'component2', 'key': 'c2_'}) }}

src/LiveComponent/tests/Functional/EventListener/AddLiveAttributesSubscriberTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,35 @@ public function testQueryStringMappingAttribute()
153153

154154
$this->assertEquals($expected, $queryMapping);
155155
}
156+
157+
public function testQueryStringMappingAttributeWithMultipleComponents()
158+
{
159+
$crawler = $this->browser()
160+
->visit('/render-template/render_multiple_components_with_url_bound_props')
161+
->assertSuccessful()
162+
->crawler()
163+
;
164+
$component1 = $crawler->filter('div[id=component1]');
165+
$this->assertEquals('c1_', $component1->attr('query-param-prefix'));
166+
$queryMapping = json_decode($component1->attr('data-live-query-mapping-value'), true);
167+
$expected = [
168+
'prop1' => ['name' => 'c1_prop1'],
169+
'prop2' => ['name' => 'c1_prop2'],
170+
'prop3' => ['name' => 'c1_prop3'],
171+
'prop5' => ['name' => 'c1_prop5'],
172+
];
173+
174+
$this->assertEquals($expected, $queryMapping);
175+
176+
$component2 = $crawler->filter('div[id=component2]');
177+
$this->assertNull($component2->attr('query-param-prefix'));
178+
$queryMapping = json_decode($component2->attr('data-live-query-mapping-value'), true);
179+
$expected = [
180+
'prop1' => ['name' => 'c2_prop1'],
181+
'prop2' => ['name' => 'c2_prop2'],
182+
'prop3' => ['name' => 'c2_prop3'],
183+
'prop5' => ['name' => 'c2_prop5'],
184+
];
185+
$this->assertEquals($expected, $queryMapping);
186+
}
156187
}

0 commit comments

Comments
 (0)