@@ -15,9 +15,10 @@ A real-time product search component might look like this:
15
15
// src/Components/ProductSearchComponent.php
16
16
namespace App\Components;
17
17
18
- use Symfony\UX\LiveComponent\LiveComponentInterface ;
18
+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent ;
19
19
20
- class ProductSearchComponent implements LiveComponentInterface
20
+ #[AsLiveComponent('product_search')]
21
+ class ProductSearchComponent
21
22
{
22
23
public string $query = '';
23
24
@@ -33,11 +34,6 @@ class ProductSearchComponent implements LiveComponentInterface
33
34
// example method that returns an array of Products
34
35
return $this->productRepository->search($this->query);
35
36
}
36
-
37
- public static function getComponentName(): string
38
- {
39
- return 'product_search';
40
- }
41
37
}
42
38
```
43
39
@@ -103,19 +99,15 @@ Suppose you've already built a basic Twig component:
103
99
// src/Components/RandomNumberComponent.php
104
100
namespace App\Components;
105
101
106
- use Symfony\UX\TwigComponent\ComponentInterface ;
102
+ use Symfony\UX\TwigComponent\Attribute\AsTwigComponent ;
107
103
108
- class RandomNumberComponent implements ComponentInterface
104
+ #[AsTwigComponent('random_number')]
105
+ class RandomNumberComponent
109
106
{
110
107
public function getRandomNumber(): string
111
108
{
112
109
return rand(0, 1000);
113
110
}
114
-
115
- public static function getComponentName(): string
116
- {
117
- return 'random_number';
118
- }
119
111
}
120
112
```
121
113
@@ -127,16 +119,18 @@ class RandomNumberComponent implements ComponentInterface
127
119
```
128
120
129
121
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 the
123
+ component's ` AsTwigComponent ` attribute with ` AsLiveComponent ` :
132
124
133
125
``` diff
134
126
// src/Components/RandomNumberComponent.php
135
127
136
- + use Symfony\UX\LiveComponent\LiveComponentInterface;
128
+ - use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
129
+ + use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
137
130
138
- - class RandomNumberComponent implements ComponentInterface
139
- + class RandomNumberComponent implements LiveComponentInterface
131
+ - #[AsTwigComponent('random_number')]
132
+ - #[AsLiveComponent('random_number')]
133
+ class RandomNumberComponent
140
134
{
141
135
}
142
136
```
@@ -183,11 +177,13 @@ namespace App\Components;
183
177
// ...
184
178
use Symfony\UX\LiveComponent\Attribute\LiveProp;
185
179
186
- class RandomNumberComponent implements LiveComponentInterface
180
+ #[AsLiveComponent('random_number')]
181
+ class RandomNumberComponent
187
182
{
188
- /** @ LiveProp */
183
+ #[ LiveProp]
189
184
public int $min = 0;
190
- /** @LiveProp */
185
+
186
+ #[LiveProp]
191
187
public int $max = 1000;
192
188
193
189
public function getRandomNumber(): string
@@ -206,14 +202,14 @@ when rendering the component:
206
202
{{ component('random_number', { min: 5, max: 500 }) }}
207
203
```
208
204
209
- But what's up with those ` @ LiveProp` annotations ? A property with
210
- the ` @ LiveProp` annotation (or ` LiveProp ` PHP 8 attribute) becomes
211
- a "stateful" property for this component. In other words, each time
212
- we click the "Generate a new number!" button, when the component
213
- re-renders, it will _ remember_ the original values for the ` $min ` and
214
- ` $max ` properties and generate a random number between 5 and 500.
215
- If you forgot to add ` @ LiveProp` , when the component re-rendered,
216
- those two values would _ not_ be set on the object.
205
+ But what's up with those ` LiveProp ` attributes ? A property with
206
+ the ` LiveProp ` attribute becomes a "stateful" property for this
207
+ component. In other words, each time we click the "Generate a
208
+ new number!" button, when the component re-renders, it will
209
+ _ remember_ the original values for the ` $min ` and ` $max ` properties
210
+ and generate a random number between 5 and 500. If you forgot to
211
+ add ` LiveProp ` , when the component re-rendered, those two values
212
+ would _ not_ be set on the object.
217
213
218
214
In short: LiveProps are "stateful properties": they will always
219
215
be set when rendering. Most properties will be LiveProps, with
@@ -267,13 +263,14 @@ the `writable=true` option:
267
263
// src/Components/RandomNumberComponent.php
268
264
// ...
269
265
270
- class RandomNumberComponent implements LiveComponentInterface
266
+ class RandomNumberComponent
271
267
{
272
- - /** @ LiveProp() */
273
- + /** @ LiveProp(writable= true) */
268
+ - #[ LiveProp]
269
+ + #[ LiveProp(writable: true)]
274
270
public int $min = 0;
275
- - /** @LiveProp() */
276
- + /** @LiveProp(writable=true) */
271
+
272
+ - #[LiveProp]
273
+ + #[LiveProp(writable: true)]
277
274
public int $max = 1000;
278
275
279
276
// ...
@@ -428,8 +425,8 @@ want to add a "Reset Min/Max" button to our "random number"
428
425
component that, when clicked, sets the min/max numbers back
429
426
to a default value.
430
427
431
- First, add a method with a ` LiveAction ` annotation (or PHP 8 attribute)
432
- above it that does the work:
428
+ First, add a method with a ` LiveAction ` attribute above it that
429
+ does the work:
433
430
434
431
``` php
435
432
// src/Components/RandomNumberComponent.php
@@ -438,13 +435,11 @@ namespace App\Components;
438
435
// ...
439
436
use Symfony\UX\LiveComponent\Attribute\LiveAction;
440
437
441
- class RandomNumberComponent implements LiveComponentInterface
438
+ class RandomNumberComponent
442
439
{
443
440
// ...
444
441
445
- /**
446
- * @LiveAction
447
- */
442
+ #[LiveAction]
448
443
public function resetMinMax()
449
444
{
450
445
$this->min = 0;
@@ -503,13 +498,11 @@ namespace App\Components;
503
498
// ...
504
499
use Psr\Log\LoggerInterface;
505
500
506
- class RandomNumberComponent implements LiveComponentInterface
501
+ class RandomNumberComponent
507
502
{
508
503
// ...
509
504
510
- /**
511
- * @LiveAction
512
- */
505
+ #[LiveAction]
513
506
public function resetMinMax(LoggerInterface $logger)
514
507
{
515
508
$this->min = 0;
@@ -548,13 +541,11 @@ namespace App\Components;
548
541
// ...
549
542
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
550
543
551
- class RandomNumberComponent extends AbstractController implements LiveComponentInterface
544
+ class RandomNumberComponent extends AbstractController
552
545
{
553
546
// ...
554
547
555
- /**
556
- * @LiveAction
557
- */
548
+ #[LiveAction]
558
549
public function resetMinMax()
559
550
{
560
551
// ...
@@ -684,11 +675,12 @@ use App\Entity\Post;
684
675
use App\Form\PostType;
685
676
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
686
677
use Symfony\Component\Form\FormInterface;
678
+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
687
679
use Symfony\UX\LiveComponent\Attribute\LiveProp;
688
- use Symfony\UX\LiveComponent\LiveComponentInterface;
689
680
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
690
681
691
- class PostFormComponent extends AbstractController implements LiveComponentInterface
682
+ #[AsLiveComponent('post_form')]
683
+ class PostFormComponent extends AbstractController
692
684
{
693
685
use ComponentWithFormTrait;
694
686
@@ -698,13 +690,12 @@ class PostFormComponent extends AbstractController implements LiveComponentInter
698
690
* Needed so the same form can be re-created
699
691
* when the component is re-rendered via Ajax.
700
692
*
701
- * The fieldName="" option is needed in this situation because
693
+ * The ` fieldName` option is needed in this situation because
702
694
* the form renders fields with names like `name="post[title]"`.
703
- * We set fieldName="" so that this live prop doesn't collide
695
+ * We set ` fieldName: ''` so that this live prop doesn't collide
704
696
* with that data. The value - initialFormData - could be anything.
705
- *
706
- * @LiveProp(fieldName="initialFormData")
707
697
*/
698
+ #[LiveProp(fieldName: 'initialFormData')]
708
699
public ?Post $post = null;
709
700
710
701
/**
@@ -715,11 +706,6 @@ class PostFormComponent extends AbstractController implements LiveComponentInter
715
706
// we can extend AbstractController to get the normal shortcuts
716
707
return $this->createForm(PostType::class, $this->post);
717
708
}
718
-
719
- public static function getComponentName(): string
720
- {
721
- return 'post_form';
722
- }
723
709
}
724
710
```
725
711
@@ -875,13 +861,11 @@ action to the component:
875
861
use Doctrine\ORM\EntityManagerInterface;
876
862
use Symfony\UX\LiveComponent\Attribute\LiveAction;
877
863
878
- class PostFormComponent extends AbstractController implements LiveComponentInterface
864
+ class PostFormComponent extends AbstractController
879
865
{
880
866
// ...
881
867
882
- /**
883
- * @LiveAction()
884
- */
868
+ #[LiveAction]
885
869
public function save(EntityManagerInterface $entityManager)
886
870
{
887
871
// shortcut to submit the form with form values
@@ -932,20 +916,14 @@ that is being edited:
932
916
namespace App\Twig\Components;
933
917
934
918
use App\Entity\Post;
919
+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
935
920
use Symfony\UX\LiveComponent\Attribute\LiveProp;
936
- use Symfony\UX\LiveComponent\LiveComponentInterface;
937
921
938
- class EditPostComponent implements LiveComponentInterface
922
+ #[AsLiveComponent('edit_post')]
923
+ class EditPostComponent
939
924
{
940
- /**
941
- * @LiveProp()
942
- */
925
+ #[LiveProp]
943
926
public Post $post;
944
-
945
- public static function getComponentName(): string
946
- {
947
- return 'edit_post';
948
- }
949
927
}
950
928
```
951
929
@@ -985,12 +963,10 @@ you can enable it via the `exposed` option:
985
963
``` diff
986
964
// ...
987
965
988
- class EditPostComponent implements LiveComponentInterface
966
+ class EditPostComponent
989
967
{
990
- /**
991
- - * @LiveProp(exposed={})
992
- + * @LiveProp(exposed={"title", "content"})
993
- */
968
+ - #[LiveProp]
969
+ + #[LiveProp(exposed: ['title', 'content'])]
994
970
public Post $post;
995
971
996
972
// ...
@@ -1020,36 +996,28 @@ First use the `ValidatableComponentTrait` and add any constraints you need:
1020
996
1021
997
``` php
1022
998
use App\Entity\User;
999
+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
1023
1000
use Symfony\UX\LiveComponent\Attribute\LiveProp;
1024
- use Symfony\UX\LiveComponent\LiveComponentInterface;
1025
1001
use Symfony\UX\LiveComponent\ValidatableComponentTrait;
1026
1002
use Symfony\Component\Validator\Constraints as Assert;
1027
1003
1028
- class EditUserComponent implements LiveComponentInterface
1004
+ #[AsLiveComponent('edit_user')]
1005
+ class EditUserComponent
1029
1006
{
1030
1007
use ValidatableComponentTrait;
1031
1008
1032
- /**
1033
- * @LiveProp(exposed={"email", "plainPassword"})
1034
- * @Assert\Valid()
1035
- */
1009
+ #[LiveProp(exposed: ['email', 'plainPassword'])]
1010
+ #[Assert\Valid]
1036
1011
public User $user;
1037
1012
1038
- /**
1039
- * @LiveProp()
1040
- * @Assert\IsTrue()
1041
- */
1013
+ #[LiveProp]
1014
+ #[Assert\IsTrue]
1042
1015
public bool $agreeToTerms = false;
1043
-
1044
- public static function getComponentName() : string
1045
- {
1046
- return 'edit_user';
1047
- }
1048
1016
}
1049
1017
```
1050
1018
1051
- Be sure to add the ` @Assert\ IsValid` to any property where you want
1052
- the object on that property to also be validated.
1019
+ Be sure to add the ` IsValid ` attribute/annotation to any property where
1020
+ you want the object on that property to also be validated.
1053
1021
1054
1022
Thanks to this setup, the component will now be automatically validated
1055
1023
on each render, but in a smart way: a property will only be validated
@@ -1063,13 +1031,12 @@ in an action:
1063
1031
``` php
1064
1032
use Symfony\UX\LiveComponent\Attribute\LiveAction;
1065
1033
1066
- class EditUserComponent implements LiveComponentInterface
1034
+ #[AsLiveComponent('edit_user')]
1035
+ class EditUserComponent
1067
1036
{
1068
1037
// ...
1069
1038
1070
- /**
1071
- * @LiveAction()
1072
- */
1039
+ #[LiveAction]
1073
1040
public function save()
1074
1041
{
1075
1042
// this will throw an exception if validation fails
0 commit comments