31
31
use Symfony \Component \HttpKernel \Event \FilterResponseEvent ;
32
32
use Symfony \Component \HttpKernel \Event \FinishRequestEvent ;
33
33
use Symfony \Component \HttpKernel \Event \GetResponseEvent ;
34
+ use Symfony \Component \HttpKernel \Event \GetResponseForControllerResultEvent ;
34
35
use Symfony \Component \HttpKernel \Event \GetResponseForExceptionEvent ;
35
36
use Symfony \Component \HttpKernel \Exception \AsyncEventDispatcherNeededException ;
36
37
use Symfony \Component \HttpKernel \Exception \BadRequestHttpException ;
38
+ use Symfony \Component \HttpKernel \Exception \ControllerDoesNotReturnResponseException ;
37
39
use Symfony \Component \HttpKernel \Exception \HttpExceptionInterface ;
38
40
use Symfony \Component \HttpKernel \Exception \NotFoundHttpException ;
41
+ use Throwable ;
39
42
40
43
/**
41
44
* Class AsyncHttpKernel.
@@ -113,7 +116,7 @@ public function handleAsync(
113
116
$ type
114
117
)
115
118
->then (null ,
116
- function (Exception $ exception ) use ($ request , $ type , $ catch ) {
119
+ function (Throwable $ exception ) use ($ request , $ type , $ catch ) {
117
120
if ($ exception instanceof RequestExceptionInterface) {
118
121
$ exception = new BadRequestHttpException ($ exception ->getMessage (), $ exception );
119
122
}
@@ -197,11 +200,53 @@ private function callAsyncController(Request $request, int $type): PromiseInterf
197
200
->then (function () use ($ controller , $ arguments ) {
198
201
return $ controller (...$ arguments );
199
202
})
203
+ ->then (function ($ response ) use ($ request , $ type , $ controller ) {
204
+ if (!$ response instanceof Response) {
205
+ return $ this ->callAsyncView ($ request , $ response , $ controller , $ type );
206
+ }
207
+
208
+ return $ response ;
209
+ })
200
210
->then (function ($ response ) use ($ request , $ type ) {
201
211
return $ this ->filterResponsePromise ($ response , $ request , $ type );
202
212
});
203
213
}
204
214
215
+ /**
216
+ * Call async view.
217
+ *
218
+ * @param Request $request
219
+ * @param mixed $response
220
+ * @param callable $controller
221
+ * @param int $type
222
+ *
223
+ * @return PromiseInterface
224
+ */
225
+ private function callAsyncView (
226
+ Request $ request ,
227
+ $ response ,
228
+ callable $ controller ,
229
+ int $ type
230
+ ): PromiseInterface {
231
+ return (new FulfilledPromise ())
232
+ ->then (function () use ($ request , $ response , $ controller , $ type ) {
233
+ $ event = new GetResponseForControllerResultEvent ($ this , $ request , $ type , $ response );
234
+ $ this ->dispatcher ->dispatch (KernelEvents::VIEW , $ event );
235
+
236
+ if ($ event ->hasResponse ()) {
237
+ return $ event ->getResponse ();
238
+ } else {
239
+ $ msg = sprintf ('The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned %s. ' , $ this ->varToString ($ response ));
240
+ // the user may have forgotten to return something
241
+ if (null === $ response ) {
242
+ $ msg .= ' Did you forget to add a return statement somewhere in your controller? ' ;
243
+ }
244
+
245
+ throw new ControllerDoesNotReturnResponseException ($ msg , $ controller , __FILE__ , __LINE__ - 17 );
246
+ }
247
+ });
248
+ }
249
+
205
250
/**
206
251
* Filters a response object.
207
252
*
@@ -247,7 +292,7 @@ private function finishRequestPromise(Request $request, int $type)
247
292
/**
248
293
* Handles an exception by trying to convert it to a Response.
249
294
*
250
- * @param Exception $exception
295
+ * @param Throwable $exception
251
296
* @param Request $request
252
297
* @param int $type
253
298
*
@@ -256,10 +301,17 @@ private function finishRequestPromise(Request $request, int $type)
256
301
* @throws Exception
257
302
*/
258
303
private function handleExceptionPromise (
259
- Exception $ exception ,
304
+ Throwable $ exception ,
260
305
Request $ request ,
261
306
int $ type
262
307
): PromiseInterface {
308
+ if (!$ exception instanceof Exception) {
309
+ $ exception = new Exception (
310
+ $ exception ->getMessage (),
311
+ $ exception ->getCode ()
312
+ );
313
+ }
314
+
263
315
$ event = new GetResponseForExceptionEvent ($ this , $ request , $ type , $ exception );
264
316
265
317
return $ this
@@ -291,4 +343,42 @@ private function handleExceptionPromise(
291
343
return $ this ->filterResponsePromise ($ response , $ request , $ type );
292
344
});
293
345
}
346
+
347
+ /**
348
+ * Returns a human-readable string for the specified variable.
349
+ */
350
+ private function varToString ($ var ): string
351
+ {
352
+ if (\is_object ($ var )) {
353
+ return sprintf ('an object of type %s ' , \get_class ($ var ));
354
+ }
355
+ if (\is_array ($ var )) {
356
+ $ a = [];
357
+ foreach ($ var as $ k => $ v ) {
358
+ $ a [] = sprintf ('%s => ... ' , $ k );
359
+ }
360
+
361
+ return sprintf ('an array ([%s]) ' , mb_substr (implode (', ' , $ a ), 0 , 255 ));
362
+ }
363
+ if (\is_resource ($ var )) {
364
+ return sprintf ('a resource (%s) ' , get_resource_type ($ var ));
365
+ }
366
+ if (null === $ var ) {
367
+ return 'null ' ;
368
+ }
369
+ if (false === $ var ) {
370
+ return 'a boolean value (false) ' ;
371
+ }
372
+ if (true === $ var ) {
373
+ return 'a boolean value (true) ' ;
374
+ }
375
+ if (\is_string ($ var )) {
376
+ return sprintf ('a string ("%s%s") ' , mb_substr ($ var , 0 , 255 ), mb_strlen ($ var ) > 255 ? '... ' : '' );
377
+ }
378
+ if (is_numeric ($ var )) {
379
+ return sprintf ('a number (%s) ' , (string ) $ var );
380
+ }
381
+
382
+ return (string ) $ var ;
383
+ }
294
384
}
0 commit comments