1414use Psr \Http \Server \RequestHandlerInterface ;
1515use RuntimeException ;
1616use Slim \Factory \AppFactory ;
17+ use Slim \Routing \PipelineOrder ;
1718use Slim \Routing \PipelineRunner ;
1819use stdClass ;
1920
2021final class RunnerTest extends TestCase
2122{
22- public function testHandleWithMiddlewareInterface ()
23+ public function testHandleWithMiddlewareInterface (): void
2324 {
2425 $ app = AppFactory::create ();
2526
@@ -61,7 +62,7 @@ function () use ($response) {
6162 $ this ->assertSame ('Success ' , $ result ->getHeaderLine ('X-Result ' ));
6263 }
6364
64- public function testHandleWithRequestHandlerInterface ()
65+ public function testHandleWithRequestHandlerInterface (): void
6566 {
6667 $ app = AppFactory::create ();
6768
@@ -99,7 +100,7 @@ public function handle(ServerRequestInterface $request): ResponseInterface
99100 $ this ->assertSame ('Handled ' , $ result ->getHeaderLine ('X-Handler ' ));
100101 }
101102
102- public function testHandleWithCallableMiddleware ()
103+ public function testHandleWithCallableMiddleware (): void
103104 {
104105 $ app = AppFactory::create ();
105106
@@ -127,10 +128,10 @@ function (ServerRequestInterface $req, RequestHandlerInterface $handler) use ($r
127128 $ this ->assertSame ('Called ' , $ result ->getHeaderLine ('X-Callable ' ));
128129 }
129130
130- public function testHandleWithEmptyQueueThrowsException ()
131+ public function testHandleWithEmptyQueueThrowsException (): void
131132 {
132133 $ this ->expectException (RuntimeException::class);
133- $ this ->expectExceptionMessage ('No middleware found. Add a response factory middleware . ' );
134+ $ this ->expectExceptionMessage ('The middleware pipeline is empty . ' );
134135
135136 $ app = AppFactory::create ();
136137
@@ -149,10 +150,12 @@ public function testHandleWithEmptyQueueThrowsException()
149150 $ runner ->handle ($ request );
150151 }
151152
152- public function testHandleWithInvalidObjectMiddlewareThrowsException ()
153+ public function testHandleWithInvalidObjectMiddlewareThrowsException (): void
153154 {
154155 $ this ->expectException (RuntimeException::class);
155- $ this ->expectExceptionMessage ('Invalid middleware queue entry "object" ' );
156+ $ this ->expectExceptionMessage (
157+ 'Invalid pipeline entry of type "stdClass". Expected one of: callable, Psr\Http\Server\MiddlewareInterface, or Psr\Http\Server\RequestHandlerInterface. ' ,
158+ );
156159
157160 $ app = AppFactory::create ();
158161
@@ -169,7 +172,7 @@ public function testHandleWithInvalidObjectMiddlewareThrowsException()
169172 $ runner ->handle ($ request );
170173 }
171174
172- public function testHandleWithInvalidMiddlewareStringThrowsException ()
175+ public function testHandleWithInvalidMiddlewareStringThrowsException (): void
173176 {
174177 $ this ->expectException (NotFoundException::class);
175178 $ this ->expectExceptionMessage ("No entry or class found for 'foo' " );
@@ -188,4 +191,58 @@ public function testHandleWithInvalidMiddlewareStringThrowsException()
188191
189192 $ runner ->handle ($ request );
190193 }
194+
195+ public function testHandleExecutesPipelineInLifoOrder (): void
196+ {
197+ $ app = AppFactory::create ();
198+ $ container = $ app ->getContainer ();
199+
200+ $ request = $ container
201+ ->get (ServerRequestFactoryInterface::class)
202+ ->createServerRequest ('GET ' , '/ ' );
203+
204+ $ responseFactory = $ container ->get (ResponseFactoryInterface::class);
205+
206+ // This middleware will be executed LAST in LIFO mode (because it was added first).
207+ $ first = new class implements MiddlewareInterface {
208+ public function process (
209+ ServerRequestInterface $ request ,
210+ RequestHandlerInterface $ handler ,
211+ ): ResponseInterface {
212+ $ response = $ handler ->handle ($ request );
213+ return $ response ->withHeader ('X-Order ' , 'First ' );
214+ }
215+ };
216+
217+ // This middleware will be executed FIRST in LIFO mode.
218+ $ second = new class implements MiddlewareInterface {
219+ public function process (
220+ ServerRequestInterface $ request ,
221+ RequestHandlerInterface $ handler ,
222+ ): ResponseInterface {
223+ $ response = $ handler ->handle ($ request );
224+ return $ response ->withHeader ('X-Order ' , 'Second ' );
225+ }
226+ };
227+
228+ // Final handler that produces a basic response
229+ $ finalHandler = fn () => $ responseFactory ->createResponse ();
230+
231+ $ runner = $ container
232+ ->get (PipelineRunner::class)
233+ ->withOrder (PipelineOrder::LIFO )
234+ ->withPipeline (
235+ [
236+ $ finalHandler , // end
237+ $ second , // ^ second
238+ $ first , // ^ start
239+ ],
240+ );
241+
242+ $ response = $ runner ->handle ($ request );
243+
244+ $ this ->assertSame ('First ' , $ response ->getHeaderLine ('X-Order ' ));
245+ }
246+
247+
191248}
0 commit comments