@@ -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
@@ -113,19 +109,15 @@ Suppose you've already built a basic Twig component:
113
109
// src/Components/RandomNumberComponent.php
114
110
namespace App\Components;
115
111
116
- use Symfony\UX\TwigComponent\ComponentInterface ;
112
+ use Symfony\UX\TwigComponent\Attribute\AsTwigComponent ;
117
113
118
- class RandomNumberComponent implements ComponentInterface
114
+ # [AsTwigComponent('random_number')]
115
+ class RandomNumberComponent
119
116
{
120
117
public function getRandomNumber() : string
121
118
{
122
119
return rand(0, 1000);
123
120
}
124
-
125
- public static function getComponentName() : string
126
- {
127
- return 'random_number';
128
- }
129
121
}
130
122
```
131
123
@@ -137,16 +129,18 @@ class RandomNumberComponent implements ComponentInterface
137
129
```
138
130
139
131
To transform this into a "live" component (i.e. one that
140
- can be re-rendered live on the frontend), change your
141
- component's interface to ` LiveComponentInterface ` :
132
+ can be re-rendered live on the frontend), replace the
133
+ component's ` AsTwigComponent ` attribute with ` AsLiveComponent ` :
142
134
143
135
``` diff
144
136
// src/Components/RandomNumberComponent.php
145
137
146
- + use Symfony\UX\LiveComponent\LiveComponentInterface;
138
+ - use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
139
+ + use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
147
140
148
- - class RandomNumberComponent implements ComponentInterface
149
- + class RandomNumberComponent implements LiveComponentInterface
141
+ - #[AsTwigComponent('random_number')]
142
+ - #[AsLiveComponent('random_number')]
143
+ class RandomNumberComponent
150
144
{
151
145
}
152
146
```
@@ -193,11 +187,13 @@ namespace App\Components;
193
187
// ...
194
188
use Symfony\UX\LiveComponent\Attribute\LiveProp;
195
189
196
- class RandomNumberComponent implements LiveComponentInterface
190
+ #[AsLiveComponent('random_number')]
191
+ class RandomNumberComponent
197
192
{
198
- /** @ LiveProp */
193
+ #[ LiveProp]
199
194
public int $min = 0;
200
- /** @LiveProp */
195
+
196
+ #[LiveProp]
201
197
public int $max = 1000;
202
198
203
199
public function getRandomNumber(): string
@@ -216,14 +212,14 @@ when rendering the component:
216
212
{{ component('random_number', { min: 5, max: 500 }) }}
217
213
```
218
214
219
- But what's up with those ` @ LiveProp` annotations ? A property with
220
- the ` @ LiveProp` annotation (or ` LiveProp ` PHP 8 attribute) becomes
221
- a "stateful" property for this component. In other words, each time
222
- we click the "Generate a new number!" button, when the component
223
- re-renders, it will _ remember_ the original values for the ` $min ` and
224
- ` $max ` properties and generate a random number between 5 and 500.
225
- If you forgot to add ` @ LiveProp` , when the component re-rendered,
226
- those two values would _ not_ be set on the object.
215
+ But what's up with those ` LiveProp ` attributes ? A property with
216
+ the ` LiveProp ` attribute becomes a "stateful" property for this
217
+ component. In other words, each time we click the "Generate a
218
+ new number!" button, when the component re-renders, it will
219
+ _ remember_ the original values for the ` $min ` and ` $max ` properties
220
+ and generate a random number between 5 and 500. If you forgot to
221
+ add ` LiveProp ` , when the component re-rendered, those two values
222
+ would _ not_ be set on the object.
227
223
228
224
In short: LiveProps are "stateful properties": they will always
229
225
be set when rendering. Most properties will be LiveProps, with
@@ -277,13 +273,14 @@ the `writable=true` option:
277
273
// src/Components/RandomNumberComponent.php
278
274
// ...
279
275
280
- class RandomNumberComponent implements LiveComponentInterface
276
+ class RandomNumberComponent
281
277
{
282
- - /** @ LiveProp() */
283
- + /** @ LiveProp(writable= true) */
278
+ - #[ LiveProp]
279
+ + #[ LiveProp(writable: true)]
284
280
public int $min = 0;
285
- - /** @LiveProp() */
286
- + /** @LiveProp(writable=true) */
281
+
282
+ - #[LiveProp]
283
+ + #[LiveProp(writable: true)]
287
284
public int $max = 1000;
288
285
289
286
// ...
@@ -438,8 +435,8 @@ want to add a "Reset Min/Max" button to our "random number"
438
435
component that, when clicked, sets the min/max numbers back
439
436
to a default value.
440
437
441
- First, add a method with a ` LiveAction ` annotation (or PHP 8 attribute)
442
- above it that does the work:
438
+ First, add a method with a ` LiveAction ` attribute above it that
439
+ does the work:
443
440
444
441
``` php
445
442
// src/Components/RandomNumberComponent.php
@@ -448,13 +445,11 @@ namespace App\Components;
448
445
// ...
449
446
use Symfony\UX\LiveComponent\Attribute\LiveAction;
450
447
451
- class RandomNumberComponent implements LiveComponentInterface
448
+ class RandomNumberComponent
452
449
{
453
450
// ...
454
451
455
- /**
456
- * @LiveAction
457
- */
452
+ #[LiveAction]
458
453
public function resetMinMax()
459
454
{
460
455
$this->min = 0;
@@ -513,13 +508,11 @@ namespace App\Components;
513
508
// ...
514
509
use Psr\Log\LoggerInterface;
515
510
516
- class RandomNumberComponent implements LiveComponentInterface
511
+ class RandomNumberComponent
517
512
{
518
513
// ...
519
514
520
- /**
521
- * @LiveAction
522
- */
515
+ #[LiveAction]
523
516
public function resetMinMax(LoggerInterface $logger)
524
517
{
525
518
$this->min = 0;
@@ -558,13 +551,11 @@ namespace App\Components;
558
551
// ...
559
552
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
560
553
561
- class RandomNumberComponent extends AbstractController implements LiveComponentInterface
554
+ class RandomNumberComponent extends AbstractController
562
555
{
563
556
// ...
564
557
565
- /**
566
- * @LiveAction
567
- */
558
+ #[LiveAction]
568
559
public function resetMinMax()
569
560
{
570
561
// ...
@@ -694,11 +685,12 @@ use App\Entity\Post;
694
685
use App\Form\PostType;
695
686
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
696
687
use Symfony\Component\Form\FormInterface;
688
+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
697
689
use Symfony\UX\LiveComponent\Attribute\LiveProp;
698
- use Symfony\UX\LiveComponent\LiveComponentInterface;
699
690
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
700
691
701
- class PostFormComponent extends AbstractController implements LiveComponentInterface
692
+ #[AsLiveComponent('post_form')]
693
+ class PostFormComponent extends AbstractController
702
694
{
703
695
use ComponentWithFormTrait;
704
696
@@ -708,13 +700,12 @@ class PostFormComponent extends AbstractController implements LiveComponentInter
708
700
* Needed so the same form can be re-created
709
701
* when the component is re-rendered via Ajax.
710
702
*
711
- * The fieldName="" option is needed in this situation because
703
+ * The ` fieldName` option is needed in this situation because
712
704
* the form renders fields with names like `name="post[title]"`.
713
- * We set fieldName="" so that this live prop doesn't collide
705
+ * We set ` fieldName: ''` so that this live prop doesn't collide
714
706
* with that data. The value - initialFormData - could be anything.
715
- *
716
- * @LiveProp(fieldName="initialFormData")
717
707
*/
708
+ #[LiveProp(fieldName: 'initialFormData')]
718
709
public ?Post $post = null;
719
710
720
711
/**
@@ -725,11 +716,6 @@ class PostFormComponent extends AbstractController implements LiveComponentInter
725
716
// we can extend AbstractController to get the normal shortcuts
726
717
return $this->createForm(PostType::class, $this->post);
727
718
}
728
-
729
- public static function getComponentName(): string
730
- {
731
- return 'post_form';
732
- }
733
719
}
734
720
```
735
721
@@ -885,13 +871,11 @@ action to the component:
885
871
use Doctrine\ORM\EntityManagerInterface;
886
872
use Symfony\UX\LiveComponent\Attribute\LiveAction;
887
873
888
- class PostFormComponent extends AbstractController implements LiveComponentInterface
874
+ class PostFormComponent extends AbstractController
889
875
{
890
876
// ...
891
877
892
- /**
893
- * @LiveAction()
894
- */
878
+ #[LiveAction]
895
879
public function save(EntityManagerInterface $entityManager)
896
880
{
897
881
// shortcut to submit the form with form values
@@ -942,20 +926,14 @@ that is being edited:
942
926
namespace App\Twig\Components;
943
927
944
928
use App\Entity\Post;
929
+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
945
930
use Symfony\UX\LiveComponent\Attribute\LiveProp;
946
- use Symfony\UX\LiveComponent\LiveComponentInterface;
947
931
948
- class EditPostComponent implements LiveComponentInterface
932
+ #[AsLiveComponent('edit_post')]
933
+ class EditPostComponent
949
934
{
950
- /**
951
- * @LiveProp()
952
- */
935
+ #[LiveProp]
953
936
public Post $post;
954
-
955
- public static function getComponentName(): string
956
- {
957
- return 'edit_post';
958
- }
959
937
}
960
938
```
961
939
@@ -995,12 +973,10 @@ you can enable it via the `exposed` option:
995
973
``` diff
996
974
// ...
997
975
998
- class EditPostComponent implements LiveComponentInterface
976
+ class EditPostComponent
999
977
{
1000
- /**
1001
- - * @LiveProp(exposed={})
1002
- + * @LiveProp(exposed={"title", "content"})
1003
- */
978
+ - #[LiveProp]
979
+ + #[LiveProp(exposed: ['title', 'content'])]
1004
980
public Post $post;
1005
981
1006
982
// ...
@@ -1030,36 +1006,28 @@ First use the `ValidatableComponentTrait` and add any constraints you need:
1030
1006
1031
1007
``` php
1032
1008
use App\Entity\User;
1009
+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
1033
1010
use Symfony\UX\LiveComponent\Attribute\LiveProp;
1034
- use Symfony\UX\LiveComponent\LiveComponentInterface;
1035
1011
use Symfony\UX\LiveComponent\ValidatableComponentTrait;
1036
1012
use Symfony\Component\Validator\Constraints as Assert;
1037
1013
1038
- class EditUserComponent implements LiveComponentInterface
1014
+ #[AsLiveComponent('edit_user')]
1015
+ class EditUserComponent
1039
1016
{
1040
1017
use ValidatableComponentTrait;
1041
1018
1042
- /**
1043
- * @LiveProp(exposed={"email", "plainPassword"})
1044
- * @Assert\Valid()
1045
- */
1019
+ #[LiveProp(exposed: ['email', 'plainPassword'])]
1020
+ #[Assert\Valid]
1046
1021
public User $user;
1047
1022
1048
- /**
1049
- * @LiveProp()
1050
- * @Assert\IsTrue()
1051
- */
1023
+ #[LiveProp]
1024
+ #[Assert\IsTrue]
1052
1025
public bool $agreeToTerms = false;
1053
-
1054
- public static function getComponentName() : string
1055
- {
1056
- return 'edit_user';
1057
- }
1058
1026
}
1059
1027
```
1060
1028
1061
- Be sure to add the ` @Assert\ IsValid` to any property where you want
1062
- the object on that property to also be validated.
1029
+ Be sure to add the ` IsValid ` attribute/annotation to any property where
1030
+ you want the object on that property to also be validated.
1063
1031
1064
1032
Thanks to this setup, the component will now be automatically validated
1065
1033
on each render, but in a smart way: a property will only be validated
@@ -1073,13 +1041,12 @@ in an action:
1073
1041
``` php
1074
1042
use Symfony\UX\LiveComponent\Attribute\LiveAction;
1075
1043
1076
- class EditUserComponent implements LiveComponentInterface
1044
+ #[AsLiveComponent('edit_user')]
1045
+ class EditUserComponent
1077
1046
{
1078
1047
// ...
1079
1048
1080
- /**
1081
- * @LiveAction()
1082
- */
1049
+ #[LiveAction]
1083
1050
public function save()
1084
1051
{
1085
1052
// this will throw an exception if validation fails
0 commit comments