1111
1212namespace Symfony \UX \TwigComponent ;
1313
14+ use Symfony \Component \PropertyAccess \PropertyAccessorInterface ;
1415use Symfony \Contracts \EventDispatcher \EventDispatcherInterface ;
16+ use Symfony \UX \TwigComponent \Attribute \ExposeInTemplate ;
1517use Symfony \UX \TwigComponent \EventListener \PreRenderEvent ;
1618use Twig \Environment ;
1719use Twig \Extension \EscaperExtension ;
@@ -28,7 +30,8 @@ final class ComponentRenderer
2830 public function __construct (
2931 private Environment $ twig ,
3032 private EventDispatcherInterface $ dispatcher ,
31- private ComponentFactory $ factory
33+ private ComponentFactory $ factory ,
34+ private PropertyAccessorInterface $ propertyAccessor
3235 ) {
3336 }
3437
@@ -40,10 +43,42 @@ public function render(MountedComponent $mounted): string
4043 $ this ->safeClassesRegistered = true ;
4144 }
4245
43- $ event = new PreRenderEvent ($ mounted , $ this ->factory ->metadataFor ($ mounted ->getName ()));
46+ $ component = $ mounted ->getComponent ();
47+ $ variables = array_merge (
48+ // add the component as "this"
49+ ['this ' => $ component ],
50+
51+ // add attributes
52+ ['attributes ' => $ mounted ->getAttributes ()],
53+
54+ // expose all public properties
55+ get_object_vars ($ component ),
56+
57+ // expose non-public properties marked with ExposeInTemplate attribute
58+ iterator_to_array ($ this ->exposedVariables ($ component )),
59+ );
60+ $ event = new PreRenderEvent ($ mounted , $ this ->factory ->metadataFor ($ mounted ->getName ()), $ variables );
4461
4562 $ this ->dispatcher ->dispatch ($ event );
4663
4764 return $ this ->twig ->render ($ event ->getTemplate (), $ event ->getVariables ());
4865 }
66+
67+ private function exposedVariables (object $ component ): \Iterator
68+ {
69+ $ class = new \ReflectionClass ($ component );
70+
71+ foreach ($ class ->getProperties () as $ property ) {
72+ if (!$ attribute = $ property ->getAttributes (ExposeInTemplate::class)[0 ] ?? null ) {
73+ continue ;
74+ }
75+
76+ $ attribute = $ attribute ->newInstance ();
77+
78+ /** @var ExposeInTemplate $attribute */
79+ $ value = $ attribute ->getter ? $ component ->{rtrim ($ attribute ->getter , '() ' )}() : $ this ->propertyAccessor ->getValue ($ component , $ property ->name );
80+
81+ yield $ attribute ->name ?? $ property ->name => $ value ;
82+ }
83+ }
4984}
0 commit comments