11<?php
22
3+ /**
4+ * Slim Framework (https://slimframework.com)
5+ *
6+ * @license https://github.com/slimphp/Slim/blob/5.x/LICENSE.md (MIT License)
7+ */
8+
39namespace Slim \Middleware ;
410
511use Psr \Http \Message \ResponseInterface ;
915use RuntimeException ;
1016use Slim \Exception \HttpMethodNotAllowedException ;
1117use Slim \Exception \HttpNotFoundException ;
18+ use Slim \Interfaces \RouteInterface ;
1219use Slim \Routing \PipelineRunner ;
13- use Slim \Routing \Route ;
14- use Slim \Routing \RouteContext ;
1520use Slim \Routing \RouteInvoker ;
16- use Slim \Routing \RoutingResults ;
21+ use Slim \Routing \RouteMatch ;
1722
1823/**
19- * This middleware processes the routing results to determine if a route was found,
20- * if the HTTP method is allowed, or if the route was not found. Based on these results,
21- * it either executes the found route's handler with its associated middleware stack or
22- * throws appropriate exceptions for 404 Not Found or 405 Method Not Allowed.
24+ * Interprets the RouteMatch produced by RoutingMiddleware and either:
25+ * - executes the matched route together with its middleware stack, or
26+ * - throws the appropriate HTTP exception for 404 / 405 cases.
27+ *
28+ * This middleware is intended to be terminal within the routing pipeline.
2329 */
2430final class EndpointMiddleware implements MiddlewareInterface
2531{
@@ -37,73 +43,88 @@ public function __construct(
3743
3844 public function process (ServerRequestInterface $ request , RequestHandlerInterface $ handler ): ResponseInterface
3945 {
40- /* @var RoutingResults $routingResults */
41- $ routingResults = $ request ->getAttribute (RouteContext::ROUTING_RESULTS );
46+ $ routeMatch = $ request ->getAttribute (RouteMatch::class);
4247
43- if (!$ routingResults instanceof RoutingResults ) {
48+ if (!$ routeMatch instanceof RouteMatch ) {
4449 throw new RuntimeException (
45- 'An unexpected error occurred while handling routing results. Routing results are not available . ' ,
50+ 'RouteMatch is missing from the request. Add RoutingMiddleware before EndpointMiddleware . ' ,
4651 );
4752 }
4853
49- $ routeStatus = $ routingResults ->getRouteStatus ();
50- if ($ routeStatus === RoutingResults::FOUND ) {
51- return $ this ->handleFound ($ request , $ routingResults );
54+ if ($ routeMatch ->isFound ()) {
55+ $ route = $ routeMatch ->getRoute ();
56+
57+ if (!$ route instanceof RouteInterface) {
58+ throw new RuntimeException ('RouteMatch is in FOUND state but does not contain a valid route. ' );
59+ }
60+
61+ return $ this ->handleFound ($ request , $ route , $ routeMatch ->getArguments ());
5262 }
5363
54- if ($ routeStatus === RoutingResults::NOT_FOUND ) {
55- // 404 Not Found
64+ if ($ routeMatch ->isNotFound ()) {
5665 throw new HttpNotFoundException ($ request );
5766 }
5867
59- if ($ routeStatus === RoutingResults::METHOD_NOT_ALLOWED ) {
60- // 405 Method Not Allowed
68+ if ($ routeMatch ->isMethodNotAllowed ()) {
6169 $ exception = new HttpMethodNotAllowedException ($ request );
62- $ exception ->setAllowedMethods ($ routingResults ->getAllowedMethods ());
70+ $ exception ->setAllowedMethods ($ routeMatch ->getAllowedMethods ());
6371
6472 throw $ exception ;
6573 }
6674
67- throw new RuntimeException ('An unexpected error occurred while endpoint handling . ' );
75+ throw new RuntimeException ('An unexpected routing state was encountered . ' );
6876 }
6977
78+ /**
79+ * @param array<string, mixed> $arguments
80+ */
7081 private function handleFound (
7182 ServerRequestInterface $ request ,
72- RoutingResults $ routingResults ,
83+ RouteInterface $ route ,
84+ array $ arguments ,
7385 ): ResponseInterface {
74- $ route = $ routingResults ->getRoute () ?? throw new RuntimeException ('Route not found. ' );
75-
76- // Collect route specific middleware
7786 $ pipeline = $ this ->collectRouteMiddleware ($ route );
7887
79- // Invoke the route/group specific middleware stack
8088 $ pipeline [] = $ this ->routeInvoker ->withHandler (
8189 $ route ->getHandler (),
82- $ routingResults -> getRouteArguments () ,
90+ $ arguments ,
8391 );
8492
85- return $ this ->pipelineRunner ->withPipeline ($ pipeline )->handle ($ request );
93+ return $ this ->pipelineRunner
94+ ->withPipeline ($ pipeline )
95+ ->handle ($ request );
8696 }
8797
8898 /**
89- * @param Route $route
90- * @return array<MiddlewareInterface|callable|string> List of middleware
99+ * Collects middleware in execution order:
100+ * - outermost parent group middleware first
101+ * - nested group middleware next
102+ * - route-specific middleware last
103+ *
104+ * @return array<MiddlewareInterface|callable|string>
91105 */
92- private function collectRouteMiddleware (Route $ route ): array
106+ private function collectRouteMiddleware (RouteInterface $ route ): array
93107 {
94- $ middlewares = [];
95-
96- // Append group specific middleware from all parent route groups
108+ $ groupMiddlewareStack = [];
97109 $ group = $ route ->getRouteGroup ();
98110
99- while ($ group ) {
100- // Prepend group middleware so outer groups come first
101- $ middlewares = array_merge ($ group ->getMiddleware (), $ middlewares );
111+ while ($ group !== null ) {
112+ array_unshift ($ groupMiddlewareStack , $ group ->getMiddleware ());
102113 $ group = $ group ->getRouteGroup ();
103114 }
104115
105- // Append endpoint-specific middleware
106- return array_merge ($ middlewares , $ route ->getMiddleware ());
107- }
116+ $ pipeline = [];
117+
118+ foreach ($ groupMiddlewareStack as $ middlewareList ) {
119+ foreach ($ middlewareList as $ middleware ) {
120+ $ pipeline [] = $ middleware ;
121+ }
122+ }
108123
124+ foreach ($ route ->getMiddleware () as $ middleware ) {
125+ $ pipeline [] = $ middleware ;
126+ }
127+
128+ return $ pipeline ;
129+ }
109130}
0 commit comments