14
14
use Psr \EventDispatcher \EventDispatcherInterface ;
15
15
use Symfony \Component \DependencyInjection \ServiceLocator ;
16
16
use Symfony \Component \PropertyAccess \PropertyAccessorInterface ;
17
+ use Symfony \Contracts \Service \ResetInterface ;
17
18
use Symfony \UX \TwigComponent \Attribute \AsTwigComponent ;
18
19
use Symfony \UX \TwigComponent \Event \PostMountEvent ;
19
20
use Symfony \UX \TwigComponent \Event \PreMountEvent ;
23
24
*
24
25
* @internal
25
26
*/
26
- final class ComponentFactory
27
+ final class ComponentFactory implements ResetInterface
27
28
{
29
+ private static $ mountMethods = [];
30
+ private static $ preMountMethods = [];
31
+ private static $ postMountMethods = [];
32
+
28
33
/**
29
34
* @param array<string, array> $config
30
35
* @param array<class-string, string> $classMap
@@ -141,37 +146,40 @@ public function get(string $name): object
141
146
142
147
private function mount (object $ component , array &$ data ): void
143
148
{
144
- try {
145
- $ method = (new \ReflectionClass ($ component ))->getMethod ('mount ' );
146
- } catch (\ReflectionException ) {
147
- // no hydrate method
148
- return ;
149
- }
150
-
151
149
if ($ component instanceof AnonymousComponent) {
152
150
$ component ->mount ($ data );
153
151
154
152
return ;
155
153
}
156
154
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 ;
158
160
159
- foreach ($ method ->getParameters () as $ refParameter ) {
160
- $ name = $ refParameter ->getName ();
161
+ return ;
162
+ }
163
+ }
161
164
162
- if (\array_key_exists ($ name , $ data )) {
163
- $ parameters [] = $ data [$ name ];
165
+ if (false === $ mountMethod ??= self ::$ mountMethods [$ component ::class]) {
166
+ return ;
167
+ }
164
168
169
+ $ parameters = [];
170
+ foreach ($ mountMethod ->getParameters () as $ refParameter ) {
171
+ if (\array_key_exists ($ name = $ refParameter ->getName (), $ data )) {
172
+ $ parameters [] = $ data [$ name ];
165
173
// remove the data element so it isn't used to set the property directly.
166
174
unset($ data [$ name ]);
167
175
} elseif ($ refParameter ->isDefaultValueAvailable ()) {
168
176
$ parameters [] = $ refParameter ->getDefaultValue ();
169
177
} 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 ));
171
179
}
172
180
}
173
181
174
- $ component -> mount ( ...$ parameters );
182
+ $ mountMethod -> invoke ( $ component , ...$ parameters );
175
183
}
176
184
177
185
private function preMount (object $ component , array $ data , ComponentMetadata $ componentMetadata ): array
@@ -180,10 +188,9 @@ private function preMount(object $component, array $data, ComponentMetadata $com
180
188
$ this ->eventDispatcher ->dispatch ($ event );
181
189
$ data = $ event ->getData ();
182
190
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 )) {
187
194
$ data = $ newData ;
188
195
}
189
196
}
@@ -199,19 +206,17 @@ private function postMount(object $component, array $data, ComponentMetadata $co
199
206
$ event = new PostMountEvent ($ component , $ data , $ componentMetadata );
200
207
$ this ->eventDispatcher ->dispatch ($ event );
201
208
$ data = $ event ->getData ();
202
- $ extraMetadata = $ event ->getExtraMetadata ();
203
209
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 )) {
208
213
$ data = $ newData ;
209
214
}
210
215
}
211
216
212
217
return [
213
218
'data ' => $ data ,
214
- 'extraMetadata ' => $ extraMetadata ,
219
+ 'extraMetadata ' => $ event -> getExtraMetadata () ,
215
220
];
216
221
}
217
222
@@ -248,4 +253,11 @@ private function throwUnknownComponentException(string $name): void
248
253
249
254
throw new \InvalidArgumentException ($ message );
250
255
}
256
+
257
+ public function reset (): void
258
+ {
259
+ self ::$ mountMethods = [];
260
+ self ::$ preMountMethods = [];
261
+ self ::$ postMountMethods = [];
262
+ }
251
263
}
0 commit comments