1414use Psr \EventDispatcher \EventDispatcherInterface ;
1515use Symfony \Component \DependencyInjection \ServiceLocator ;
1616use Symfony \Component \PropertyAccess \PropertyAccessorInterface ;
17+ use Symfony \Contracts \Service \ResetInterface ;
1718use Symfony \UX \TwigComponent \Attribute \AsTwigComponent ;
1819use Symfony \UX \TwigComponent \Event \PostMountEvent ;
1920use Symfony \UX \TwigComponent \Event \PreMountEvent ;
2324 *
2425 * @internal
2526 */
26- final class ComponentFactory
27+ final class ComponentFactory implements ResetInterface
2728{
29+ private static $ mountMethods = [];
30+ private static $ preMountMethods = [];
31+ private static $ postMountMethods = [];
32+
2833 /**
2934 * @param array<string, array> $config
3035 * @param array<class-string, string> $classMap
@@ -141,37 +146,40 @@ public function get(string $name): object
141146
142147 private function mount (object $ component , array &$ data ): void
143148 {
144- try {
145- $ method = (new \ReflectionClass ($ component ))->getMethod ('mount ' );
146- } catch (\ReflectionException ) {
147- // no hydrate method
148- return ;
149- }
150-
151149 if ($ component instanceof AnonymousComponent) {
152150 $ component ->mount ($ data );
153151
154152 return ;
155153 }
156154
157- $ parameters = [];
155+ if (null === (self ::$ mountMethods [$ component ::class] ?? null )) {
156+ try {
157+ $ mountMethod = self ::$ mountMethods [$ component ::class] = (new \ReflectionClass ($ component ))->getMethod ('mount ' );
158+ } catch (\ReflectionException ) {
159+ self ::$ mountMethods [$ component ::class] = false ;
158160
159- foreach ($ method ->getParameters () as $ refParameter ) {
160- $ name = $ refParameter ->getName ();
161+ return ;
162+ }
163+ }
161164
162- if (\array_key_exists ($ name , $ data )) {
163- $ parameters [] = $ data [$ name ];
165+ if (false === $ mountMethod ??= self ::$ mountMethods [$ component ::class]) {
166+ return ;
167+ }
164168
169+ $ parameters = [];
170+ foreach ($ mountMethod ->getParameters () as $ refParameter ) {
171+ if (\array_key_exists ($ name = $ refParameter ->getName (), $ data )) {
172+ $ parameters [] = $ data [$ name ];
165173 // remove the data element so it isn't used to set the property directly.
166174 unset($ data [$ name ]);
167175 } elseif ($ refParameter ->isDefaultValueAvailable ()) {
168176 $ parameters [] = $ refParameter ->getDefaultValue ();
169177 } else {
170- throw new \LogicException (\sprintf ('%s::mount() has a required $%s parameter. Make sure this is passed or make give a default value. ' , $ component ::class, $ refParameter -> getName () ));
178+ throw new \LogicException (\sprintf ('%s::mount() has a required $%s parameter. Make sure to pass it or give it a default value. ' , $ component ::class, $ name ));
171179 }
172180 }
173181
174- $ component -> mount ( ...$ parameters );
182+ $ mountMethod -> invoke ( $ component , ...$ parameters );
175183 }
176184
177185 private function preMount (object $ component , array $ data , ComponentMetadata $ componentMetadata ): array
@@ -180,10 +188,9 @@ private function preMount(object $component, array $data, ComponentMetadata $com
180188 $ this ->eventDispatcher ->dispatch ($ event );
181189 $ data = $ event ->getData ();
182190
183- foreach (AsTwigComponent::preMountMethods ($ component ) as $ method ) {
184- $ newData = $ component ->{$ method ->name }($ data );
185-
186- if (null !== $ newData ) {
191+ $ methods = self ::$ preMountMethods [$ component ::class] ??= AsTwigComponent::preMountMethods ($ component ::class);
192+ foreach ($ methods as $ method ) {
193+ if (null !== $ newData = $ method ->invoke ($ component , $ data )) {
187194 $ data = $ newData ;
188195 }
189196 }
@@ -199,19 +206,17 @@ private function postMount(object $component, array $data, ComponentMetadata $co
199206 $ event = new PostMountEvent ($ component , $ data , $ componentMetadata );
200207 $ this ->eventDispatcher ->dispatch ($ event );
201208 $ data = $ event ->getData ();
202- $ extraMetadata = $ event ->getExtraMetadata ();
203209
204- foreach (AsTwigComponent::postMountMethods ($ component ) as $ method ) {
205- $ newData = $ component ->{$ method ->name }($ data );
206-
207- if (null !== $ newData ) {
210+ $ methods = self ::$ postMountMethods [$ component ::class] ??= AsTwigComponent::postMountMethods ($ component ::class);
211+ foreach ($ methods as $ method ) {
212+ if (null !== $ newData = $ method ->invoke ($ component , $ data )) {
208213 $ data = $ newData ;
209214 }
210215 }
211216
212217 return [
213218 'data ' => $ data ,
214- 'extraMetadata ' => $ extraMetadata ,
219+ 'extraMetadata ' => $ event -> getExtraMetadata () ,
215220 ];
216221 }
217222
@@ -248,4 +253,11 @@ private function throwUnknownComponentException(string $name): void
248253
249254 throw new \InvalidArgumentException ($ message );
250255 }
256+
257+ public function reset (): void
258+ {
259+ self ::$ mountMethods = [];
260+ self ::$ preMountMethods = [];
261+ self ::$ postMountMethods = [];
262+ }
251263}
0 commit comments