@@ -69,6 +69,10 @@ public function onKernelRequest(RequestEvent $event): void
6969 return ;
7070 }
7171
72+ if ($ request ->attributes ->has ('_controller ' )) {
73+ return ;
74+ }
75+
7276 // the default "action" is get, which does nothing
7377 $ action = $ request ->get ('action ' , 'get ' );
7478 $ componentName = (string ) $ request ->get ('component ' );
@@ -107,6 +111,23 @@ public function onKernelRequest(RequestEvent $event): void
107111 throw new BadRequestHttpException ('Invalid CSRF token. ' );
108112 }
109113
114+ if ('_batch ' === $ action ) {
115+ // use batch controller
116+ $ data = $ this ->parseDataFor ($ request );
117+
118+ $ request ->attributes ->set ('_controller ' , 'ux.live_component.batch_action_controller ' );
119+ $ request ->attributes ->set ('serviceId ' , $ metadata ->getServiceId ());
120+ $ request ->attributes ->set ('actions ' , $ data ['actions ' ]);
121+ $ request ->attributes ->set ('_mounted_component ' , $ this ->container ->get (LiveComponentHydrator::class)->hydrate (
122+ $ this ->container ->get (ComponentFactory::class)->get ($ componentName ),
123+ $ data ['data ' ],
124+ $ componentName ,
125+ ));
126+ $ request ->attributes ->set ('_is_live_batch_action ' , true );
127+
128+ return ;
129+ }
130+
110131 $ request ->attributes ->set ('_controller ' , sprintf ('%s::%s ' , $ metadata ->getServiceId (), $ action ));
111132 }
112133
@@ -118,18 +139,13 @@ public function onKernelController(ControllerEvent $event): void
118139 return ;
119140 }
120141
121- $ actionArguments = [];
122- if ($ request ->query ->has ('data ' )) {
123- // ?data=
124- $ data = json_decode ($ request ->query ->get ('data ' ), true , 512 , \JSON_THROW_ON_ERROR );
125- } else {
126- // OR body of the request is JSON
127- $ requestData = json_decode ($ request ->getContent (), true , 512 , \JSON_THROW_ON_ERROR );
128- $ data = $ requestData ['data ' ] ?? [];
129- $ actionArguments = $ requestData ['args ' ] ?? [];
142+ if ($ request ->attributes ->get ('_is_live_batch_action ' )) {
143+ return ;
130144 }
131145
132- if (!\is_array ($ controller = $ event ->getController ()) || 2 !== \count ($ controller )) {
146+ $ controller = $ event ->getController ();
147+
148+ if (!\is_array ($ controller ) || 2 !== \count ($ controller )) {
133149 throw new \RuntimeException ('Not a valid live component. ' );
134150 }
135151
@@ -143,14 +159,29 @@ public function onKernelController(ControllerEvent $event): void
143159 throw new NotFoundHttpException (sprintf ('The action "%s" either doesn \'t exist or is not allowed in "%s". Make sure it exist and has the LiveAction attribute above it. ' , $ action , \get_class ($ component )));
144160 }
145161
146- $ mounted = $ this ->container ->get (LiveComponentHydrator::class)->hydrate (
147- $ component ,
148- $ data ,
149- $ request ->attributes ->get ('_component_name ' )
150- );
151-
152- $ request ->attributes ->set ('_mounted_component ' , $ mounted );
162+ /*
163+ * Either we:
164+ * A) To not have a _mounted_component, so hydrate $component
165+ * B) We DO have a _mounted_component, so no need to hydrate,
166+ * but we DO need to make sure it's set as the controller.
167+ */
168+ if (!$ request ->attributes ->has ('_mounted_component ' )) {
169+ $ request ->attributes ->set ('_mounted_component ' , $ this ->container ->get (LiveComponentHydrator::class)->hydrate (
170+ $ component ,
171+ $ this ->parseDataFor ($ request )['data ' ],
172+ $ request ->attributes ->get ('_component_name ' )
173+ ));
174+ } else {
175+ // override the component with our already-mounted version
176+ $ component = $ request ->attributes ->get ('_mounted_component ' )->getComponent ();
177+ $ event ->setController ([
178+ $ component ,
179+ $ action ,
180+ ]);
181+ }
153182
183+ // read the action arguments from the request, unless they're already set (batch sub-requests)
184+ $ actionArguments = $ request ->attributes ->get ('_component_action_args ' , $ this ->parseDataFor ($ request )['args ' ]);
154185 // extra variables to be made available to the controller
155186 // (for "actions" only)
156187 foreach (LiveArg::liveArgs ($ component , $ action ) as $ parameter => $ arg ) {
@@ -160,12 +191,49 @@ public function onKernelController(ControllerEvent $event): void
160191 }
161192 }
162193
194+ /**
195+ * @return array{
196+ * data: array,
197+ * args: array,
198+ * actions: array
199+ * }
200+ */
201+ private function parseDataFor (Request $ request ): array
202+ {
203+ if (!$ request ->attributes ->has ('_live_request_data ' )) {
204+ if ($ request ->query ->has ('data ' )) {
205+ return [
206+ 'data ' => json_decode ($ request ->query ->get ('data ' ), true , 512 , \JSON_THROW_ON_ERROR ),
207+ 'args ' => [],
208+ 'actions ' => [],
209+ ];
210+ }
211+
212+ $ requestData = $ request ->toArray ();
213+
214+ $ request ->attributes ->set ('_live_request_data ' , [
215+ 'data ' => $ requestData ['data ' ] ?? [],
216+ 'args ' => $ requestData ['args ' ] ?? [],
217+ 'actions ' => $ requestData ['actions ' ] ?? [],
218+ ]);
219+ }
220+
221+ return $ request ->attributes ->get ('_live_request_data ' );
222+ }
223+
163224 public function onKernelView (ViewEvent $ event ): void
164225 {
165226 if (!$ this ->isLiveComponentRequest ($ request = $ event ->getRequest ())) {
166227 return ;
167228 }
168229
230+ if (!$ event ->isMainRequest ()) {
231+ // sub-request, so skip rendering
232+ $ event ->setResponse (new Response ());
233+
234+ return ;
235+ }
236+
169237 $ event ->setResponse ($ this ->createResponse ($ request ->attributes ->get ('_mounted_component ' )));
170238 }
171239
0 commit comments