@@ -463,16 +463,66 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache
463463
464464 $ routeFilters = $ this ->tryToRouteIt ($ routes );
465465
466- // $uri is URL-encoded.
466+ // Run "before" filters
467+ $ possibleResponse = $ this ->applyFilters ('before ' , $ routeFilters );
468+
469+ // If a ResponseInterface instance is returned then send it back to the client and stop
470+ if ($ possibleResponse instanceof ResponseInterface) {
471+ $ this ->outputBufferingEnd ();
472+
473+ return $ possibleResponse ;
474+ }
475+
476+ $ returned = $ this ->startController ();
477+
478+ $ this ->serveResponse ($ cacheConfig , $ returned );
479+
480+ // Run "after" filters
481+ $ this ->applyFilters ('after ' );
482+
483+ // Execute controller attributes' after() methods AFTER framework filters
484+ if ((config ('Routing ' )->useControllerAttributes ?? true ) === true ) { // @phpstan-ignore nullCoalesce.property
485+ $ this ->benchmark ->start ('route_attributes_after ' );
486+ $ this ->response = $ this ->router ->executeAfterAttributes ($ this ->request , $ this ->response );
487+ $ this ->benchmark ->stop ('route_attributes_after ' );
488+ }
489+
490+ // Skip unnecessary processing for special Responses.
491+ if (
492+ ! $ this ->response instanceof DownloadResponse
493+ && ! $ this ->response instanceof RedirectResponse
494+ ) {
495+ // Save our current URI as the previous URI in the session
496+ // for safer, more accurate use with `previous_url()` helper function.
497+ $ this ->storePreviousURL (current_url (true ));
498+ }
499+
500+ return $ this ->response ;
501+ }
502+
503+ /**
504+ * Runs filters.
505+ *
506+ * @param string $position 'before' or 'after'
507+ * @param list<string>|string|null $routeFilters
508+ */
509+ protected function applyFilters (string $ position , $ routeFilters = null ): ?ResponseInterface
510+ {
511+ if (! $ this ->enableFilters ) {
512+ return null ;
513+ }
514+
467515 $ uri = $ this ->request ->getPath ();
468516
469- if ($ this ->enableFilters ) {
470- /** @var Filters $filters */
471- $ filters = service ('filters ' );
517+ /** @var Filters $filters */
518+ $ filters = service ('filters ' );
472519
473- // If any filters were specified within the routes file,
474- // we need to ensure it's active for the current request
520+ if ($ position === 'before ' ) {
475521 if ($ routeFilters !== null ) {
522+ if (is_string ($ routeFilters )) {
523+ $ routeFilters = [$ routeFilters ];
524+ }
525+
476526 $ filters ->enableFilters ($ routeFilters , 'before ' );
477527
478528 $ oldFilterOrder = config (Feature::class)->oldFilterOrder ?? false ; // @phpstan-ignore nullCoalesce.property
@@ -483,31 +533,51 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache
483533 $ filters ->enableFilters ($ routeFilters , 'after ' );
484534 }
485535
486- // Run "before" filters
487536 $ this ->benchmark ->start ('before_filters ' );
488537 $ possibleResponse = $ filters ->run ($ uri , 'before ' );
489538 $ this ->benchmark ->stop ('before_filters ' );
490539
491- // If a ResponseInterface instance is returned then send it back to the client and stop
492540 if ($ possibleResponse instanceof ResponseInterface) {
493- $ this ->outputBufferingEnd ();
494-
495541 return $ possibleResponse ;
496542 }
497543
498544 if ($ possibleResponse instanceof IncomingRequest || $ possibleResponse instanceof CLIRequest) {
499545 $ this ->request = $ possibleResponse ;
500546 }
547+
548+ return null ;
501549 }
502550
503- $ returned = $ this ->startController ();
551+ // after position
552+ $ filters ->setResponse ($ this ->response );
553+
554+ $ this ->benchmark ->start ('after_filters ' );
555+ $ response = $ filters ->run ($ uri , 'after ' );
556+ $ this ->benchmark ->stop ('after_filters ' );
504557
558+ if ($ response instanceof ResponseInterface) {
559+ $ this ->response = $ response ;
560+ }
561+
562+ return null ;
563+ }
564+
565+ /**
566+ * Start the controller, run it, and gather output.
567+ *
568+ * @param mixed $returned
569+ */
570+ protected function serveResponse (Cache $ cacheConfig , $ returned ): void
571+ {
505572 // If startController returned a Response (from an attribute or Closure), use it
506573 if ($ returned instanceof ResponseInterface) {
507- $ this ->gatherOutput ($ cacheConfig , $ returned );
574+ $ this ->handleCache ($ cacheConfig , $ returned );
575+
576+ return ;
508577 }
578+
509579 // Closure controller has run in startController().
510- elseif (! is_callable ($ this ->controller )) {
580+ if (! is_callable ($ this ->controller )) {
511581 $ controller = $ this ->createController ();
512582
513583 if (! method_exists ($ controller , '_remap ' ) && ! is_callable ([$ controller , $ this ->method ], false )) {
@@ -526,43 +596,17 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache
526596 // If $returned is a string, then the controller output something,
527597 // probably a view, instead of echoing it directly. Send it along
528598 // so it can be used with the output.
529- $ this ->gatherOutput ($ cacheConfig , $ returned );
530-
531- if ($ this ->enableFilters ) {
532- /** @var Filters $filters */
533- $ filters = service ('filters ' );
534- $ filters ->setResponse ($ this ->response );
535-
536- // Run "after" filters
537- $ this ->benchmark ->start ('after_filters ' );
538- $ response = $ filters ->run ($ uri , 'after ' );
539- $ this ->benchmark ->stop ('after_filters ' );
540-
541- if ($ response instanceof ResponseInterface) {
542- $ this ->response = $ response ;
543- }
544- }
545-
546- // Execute controller attributes' after() methods AFTER framework filters
547- if ((config ('Routing ' )->useControllerAttributes ?? true ) === true ) { // @phpstan-ignore nullCoalesce.property
548- $ this ->benchmark ->start ('route_attributes_after ' );
549- $ this ->response = $ this ->router ->executeAfterAttributes ($ this ->request , $ this ->response );
550- $ this ->benchmark ->stop ('route_attributes_after ' );
551- }
552-
553- // Skip unnecessary processing for special Responses.
554- if (
555- ! $ this ->response instanceof DownloadResponse
556- && ! $ this ->response instanceof RedirectResponse
557- ) {
558- // Save our current URI as the previous URI in the session
559- // for safer, more accurate use with `previous_url()` helper function.
560- $ this ->storePreviousURL (current_url (true ));
561- }
562-
563- unset($ uri );
599+ $ this ->handleCache ($ cacheConfig , $ returned );
600+ }
564601
565- return $ this ->response ;
602+ /**
603+ * Gathers the script output and handles caching.
604+ *
605+ * @param mixed $returned
606+ */
607+ protected function handleCache (Cache $ cacheConfig , $ returned ): void
608+ {
609+ $ this ->gatherOutput ($ cacheConfig , $ returned );
566610 }
567611
568612 /**
0 commit comments