Skip to content

Commit 1c401cd

Browse files
committed
remove LiveComponentInterface
1 parent 53bb8e2 commit 1c401cd

18 files changed

+197
-177
lines changed

src/LiveComponent/README.md

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ A real-time product search component might look like this:
1515
// src/Components/ProductSearchComponent.php
1616
namespace App\Components;
1717

18-
use Symfony\UX\LiveComponent\LiveComponentInterface;
18+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
1919

20-
class ProductSearchComponent implements LiveComponentInterface
20+
#[AsLiveComponent('product_search')]
21+
class ProductSearchComponent
2122
{
2223
public string $query = '';
2324

@@ -33,11 +34,6 @@ class ProductSearchComponent implements LiveComponentInterface
3334
// example method that returns an array of Products
3435
return $this->productRepository->search($this->query);
3536
}
36-
37-
public static function getComponentName(): string
38-
{
39-
return 'product_search';
40-
}
4137
}
4238
```
4339

@@ -103,19 +99,15 @@ Suppose you've already built a basic Twig component:
10399
// src/Components/RandomNumberComponent.php
104100
namespace App\Components;
105101

106-
use Symfony\UX\TwigComponent\ComponentInterface;
102+
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
107103

108-
class RandomNumberComponent implements ComponentInterface
104+
#[AsTwigComponent('random_number')]
105+
class RandomNumberComponent
109106
{
110107
public function getRandomNumber(): string
111108
{
112109
return rand(0, 1000);
113110
}
114-
115-
public static function getComponentName(): string
116-
{
117-
return 'random_number';
118-
}
119111
}
120112
```
121113

@@ -127,16 +119,18 @@ class RandomNumberComponent implements ComponentInterface
127119
```
128120

129121
To transform this into a "live" component (i.e. one that
130-
can be re-rendered live on the frontend), change your
131-
component's interface to `LiveComponentInterface`:
122+
can be re-rendered live on the frontend), replace
123+
component's `AsTwigComponent` attribute to `AsLiveComponent`:
132124

133125
```diff
134126
// src/Components/RandomNumberComponent.php
135127

136-
+use Symfony\UX\LiveComponent\LiveComponentInterface;
128+
-use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
129+
+use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
137130

138-
-class RandomNumberComponent implements ComponentInterface
139-
+class RandomNumberComponent implements LiveComponentInterface
131+
-#[AsTwigComponent('random_number')]
132+
-#[AsLiveComponent('random_number')]
133+
class RandomNumberComponent
140134
{
141135
}
142136
```
@@ -183,7 +177,8 @@ namespace App\Components;
183177
// ...
184178
use Symfony\UX\LiveComponent\Attribute\LiveProp;
185179

186-
class RandomNumberComponent implements LiveComponentInterface
180+
#[AsLiveComponent('random_number')]
181+
class RandomNumberComponent
187182
{
188183
/** @LiveProp */
189184
public int $min = 0;
@@ -267,7 +262,7 @@ the `writable=true` option:
267262
// src/Components/RandomNumberComponent.php
268263
// ...
269264

270-
class RandomNumberComponent implements LiveComponentInterface
265+
class RandomNumberComponent
271266
{
272267
- /** @LiveProp() */
273268
+ /** @LiveProp(writable=true) */
@@ -438,7 +433,7 @@ namespace App\Components;
438433
// ...
439434
use Symfony\UX\LiveComponent\Attribute\LiveAction;
440435

441-
class RandomNumberComponent implements LiveComponentInterface
436+
class RandomNumberComponent
442437
{
443438
// ...
444439

@@ -503,7 +498,7 @@ namespace App\Components;
503498
// ...
504499
use Psr\Log\LoggerInterface;
505500

506-
class RandomNumberComponent implements LiveComponentInterface
501+
class RandomNumberComponent
507502
{
508503
// ...
509504

@@ -548,7 +543,7 @@ namespace App\Components;
548543
// ...
549544
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
550545

551-
class RandomNumberComponent extends AbstractController implements LiveComponentInterface
546+
class RandomNumberComponent extends AbstractController
552547
{
553548
// ...
554549

@@ -684,11 +679,12 @@ use App\Entity\Post;
684679
use App\Form\PostType;
685680
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
686681
use Symfony\Component\Form\FormInterface;
682+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
687683
use Symfony\UX\LiveComponent\Attribute\LiveProp;
688-
use Symfony\UX\LiveComponent\LiveComponentInterface;
689684
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
690685

691-
class PostFormComponent extends AbstractController implements LiveComponentInterface
686+
#[AsLiveComponent('post_form')]
687+
class PostFormComponent extends AbstractController
692688
{
693689
use ComponentWithFormTrait;
694690

@@ -715,11 +711,6 @@ class PostFormComponent extends AbstractController implements LiveComponentInter
715711
// we can extend AbstractController to get the normal shortcuts
716712
return $this->createForm(PostType::class, $this->post);
717713
}
718-
719-
public static function getComponentName(): string
720-
{
721-
return 'post_form';
722-
}
723714
}
724715
```
725716

@@ -875,7 +866,7 @@ action to the component:
875866
use Doctrine\ORM\EntityManagerInterface;
876867
use Symfony\UX\LiveComponent\Attribute\LiveAction;
877868

878-
class PostFormComponent extends AbstractController implements LiveComponentInterface
869+
class PostFormComponent extends AbstractController
879870
{
880871
// ...
881872

@@ -932,20 +923,16 @@ that is being edited:
932923
namespace App\Twig\Components;
933924

934925
use App\Entity\Post;
926+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
935927
use Symfony\UX\LiveComponent\Attribute\LiveProp;
936-
use Symfony\UX\LiveComponent\LiveComponentInterface;
937928

938-
class EditPostComponent implements LiveComponentInterface
929+
#[AsLiveComponent('edit_post')]
930+
class EditPostComponent
939931
{
940932
/**
941933
* @LiveProp()
942934
*/
943935
public Post $post;
944-
945-
public static function getComponentName(): string
946-
{
947-
return 'edit_post';
948-
}
949936
}
950937
```
951938

@@ -985,7 +972,7 @@ you can enable it via the `exposed` option:
985972
```diff
986973
// ...
987974

988-
class EditPostComponent implements LiveComponentInterface
975+
class EditPostComponent
989976
{
990977
/**
991978
- * @LiveProp(exposed={})
@@ -1020,12 +1007,13 @@ First use the `ValidatableComponentTrait` and add any constraints you need:
10201007

10211008
```php
10221009
use App\Entity\User;
1010+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
10231011
use Symfony\UX\LiveComponent\Attribute\LiveProp;
1024-
use Symfony\UX\LiveComponent\LiveComponentInterface;
10251012
use Symfony\UX\LiveComponent\ValidatableComponentTrait;
10261013
use Symfony\Component\Validator\Constraints as Assert;
10271014

1028-
class EditUserComponent implements LiveComponentInterface
1015+
#[AsLiveComponent('edit_user')]
1016+
class EditUserComponent
10291017
{
10301018
use ValidatableComponentTrait;
10311019

@@ -1040,11 +1028,6 @@ class EditUserComponent implements LiveComponentInterface
10401028
* @Assert\IsTrue()
10411029
*/
10421030
public bool $agreeToTerms = false;
1043-
1044-
public static function getComponentName() : string
1045-
{
1046-
return 'edit_user';
1047-
}
10481031
}
10491032
```
10501033

@@ -1063,7 +1046,8 @@ in an action:
10631046
```php
10641047
use Symfony\UX\LiveComponent\Attribute\LiveAction;
10651048

1066-
class EditUserComponent implements LiveComponentInterface
1049+
#[AsLiveComponent('edit_user')]
1050+
class EditUserComponent
10671051
{
10681052
// ...
10691053

src/LiveComponent/composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
},
2828
"require": {
2929
"php": ">=8.0",
30-
"symfony/ux-twig-component": "^1.4"
30+
"symfony/ux-twig-component": "@dev"
3131
},
3232
"require-dev": {
3333
"symfony/framework-bundle": "^4.4|^5.0",
@@ -51,5 +51,11 @@
5151
"url": "https://github.com/symfony/ux"
5252
}
5353
},
54+
"repositories": [
55+
{
56+
"type": "path",
57+
"url": "../TwigComponent"
58+
}
59+
],
5460
"minimum-stability": "dev"
5561
}

src/LiveComponent/src/LiveComponentInterface.php renamed to src/LiveComponent/src/Attribute/AsLiveComponent.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\UX\LiveComponent;
12+
namespace Symfony\UX\LiveComponent\Attribute;
1313

14-
use Symfony\UX\TwigComponent\ComponentInterface;
14+
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
1515

1616
/**
1717
* @author Kevin Bond <[email protected]>
1818
*
1919
* @experimental
2020
*/
21-
interface LiveComponentInterface extends ComponentInterface
21+
#[\Attribute(\Attribute::TARGET_CLASS)]
22+
final class AsLiveComponent extends AsTwigComponent
2223
{
2324
}

src/LiveComponent/src/Attribute/LiveProp.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace Symfony\UX\LiveComponent\Attribute;
1313

14-
use Symfony\UX\LiveComponent\LiveComponentInterface;
15-
1614
/**
1715
* @Annotation
1816
* @Target("PROPERTY")
@@ -79,7 +77,7 @@ public function dehydrateMethod(): ?string
7977
return $this->dehydrateWith ? trim($this->dehydrateWith, '()') : null;
8078
}
8179

82-
public function calculateFieldName(LiveComponentInterface $component, string $fallback): string
80+
public function calculateFieldName(object $component, string $fallback): string
8381
{
8482
if (!$this->fieldName) {
8583
return $fallback;

src/LiveComponent/src/DefaultComponentController.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace Symfony\UX\LiveComponent;
1313

14-
use Symfony\UX\TwigComponent\ComponentInterface;
15-
1614
/**
1715
* @author Kevin Bond <[email protected]>
1816
*
@@ -22,23 +20,18 @@
2220
*/
2321
final class DefaultComponentController
2422
{
25-
/** @var LiveComponentInterface */
26-
private $component;
23+
private object $component;
2724

28-
public function __construct(ComponentInterface $component)
25+
public function __construct(object $component)
2926
{
30-
if (!$component instanceof LiveComponentInterface) {
31-
throw new \InvalidArgumentException('Not an instance of LiveComponentInterface.');
32-
}
33-
3427
$this->component = $component;
3528
}
3629

3730
public function __invoke(): void
3831
{
3932
}
4033

41-
public function getComponent(): LiveComponentInterface
34+
public function getComponent(): object
4235
{
4336
return $this->component;
4437
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
17+
use Symfony\UX\LiveComponent\EventListener\LiveComponentSubscriber;
18+
19+
/**
20+
* @author Kevin Bond <[email protected]>
21+
*
22+
* @experimental
23+
*/
24+
final class LiveComponentPass implements CompilerPassInterface
25+
{
26+
public function process(ContainerBuilder $container): void
27+
{
28+
$componentServiceMap = [];
29+
30+
foreach (array_keys($container->findTaggedServiceIds('twig.component')) as $id) {
31+
try {
32+
$attribute = AsLiveComponent::forClass($container->findDefinition($id)->getClass());
33+
} catch (\InvalidArgumentException $e) {
34+
continue;
35+
}
36+
37+
$componentServiceMap[$attribute->getName()] = $id;
38+
}
39+
40+
$container->findDefinition(LiveComponentSubscriber::class)->setArgument(0, $componentServiceMap);
41+
}
42+
}

0 commit comments

Comments
 (0)