Skip to content

Commit 40f6e5b

Browse files
committed
Reuse same DI container instance when loading global middleware classes
1 parent 5d63332 commit 40f6e5b

3 files changed

Lines changed: 121 additions & 4 deletions

File tree

src/App.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,18 @@ class App
3737
*/
3838
public function __construct(...$middleware)
3939
{
40+
$container = new Container();
4041
$errorHandler = new ErrorHandler();
41-
$this->router = new RouteHandler();
42+
$this->router = new RouteHandler($container);
43+
44+
if ($middleware) {
45+
$middleware = array_map(
46+
function ($handler) use ($container) {
47+
return is_callable($handler) ? $handler : $container->callable($handler);
48+
},
49+
$middleware
50+
);
51+
}
4252

4353
// new MiddlewareHandler([$accessLogHandler, $errorHandler, ...$middleware, $routeHandler])
4454
\array_unshift($middleware, $errorHandler);

src/RouteHandler.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ class RouteHandler
2727
/** @var Container */
2828
private $container;
2929

30-
public function __construct()
30+
public function __construct(Container $container = null)
3131
{
3232
$this->routeCollector = new RouteCollector(new RouteParser(), new RouteGenerator());
3333
$this->errorHandler = new ErrorHandler();
34-
$this->container = new Container();
34+
$this->container = $container ?? new Container();
3535
}
3636

3737
/**

tests/AppMiddlewareTest.php

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,112 @@ public function testGlobalMiddlewareCallsNextReturnsResponseFromController()
452452
$this->assertEquals("OK\n", (string) $response->getBody());
453453
}
454454

455+
public function testGlobalMiddlewareInstanceCallsNextReturnsResponseFromController()
456+
{
457+
$middleware = new class {
458+
public function __invoke(ServerRequestInterface $request, callable $next)
459+
{
460+
return $next($request);
461+
}
462+
};
463+
464+
$app = $this->createAppWithoutLogger($middleware);
465+
466+
$app->get('/', function () {
467+
return new Response(
468+
200,
469+
[
470+
'Content-Type' => 'text/html'
471+
],
472+
"OK\n"
473+
);
474+
});
475+
476+
$request = new ServerRequest('GET', 'http://localhost/');
477+
478+
// $response = $app->handleRequest($request);
479+
$ref = new \ReflectionMethod($app, 'handleRequest');
480+
$ref->setAccessible(true);
481+
$response = $ref->invoke($app, $request);
482+
483+
/** @var ResponseInterface $response */
484+
$this->assertInstanceOf(ResponseInterface::class, $response);
485+
$this->assertEquals(200, $response->getStatusCode());
486+
$this->assertEquals('text/html', $response->getHeaderLine('Content-Type'));
487+
$this->assertEquals("OK\n", (string) $response->getBody());
488+
}
489+
490+
public function testGlobalMiddlewareClassNameCallsNextReturnsResponseFromController()
491+
{
492+
$middleware = new class {
493+
public function __invoke(ServerRequestInterface $request, callable $next)
494+
{
495+
return $next($request);
496+
}
497+
};
498+
499+
$app = $this->createAppWithoutLogger(get_class($middleware));
500+
501+
$app->get('/', function () {
502+
return new Response(
503+
200,
504+
[
505+
'Content-Type' => 'text/html'
506+
],
507+
"OK\n"
508+
);
509+
});
510+
511+
$request = new ServerRequest('GET', 'http://localhost/');
512+
513+
// $response = $app->handleRequest($request);
514+
$ref = new \ReflectionMethod($app, 'handleRequest');
515+
$ref->setAccessible(true);
516+
$response = $ref->invoke($app, $request);
517+
518+
/** @var ResponseInterface $response */
519+
$this->assertInstanceOf(ResponseInterface::class, $response);
520+
$this->assertEquals(200, $response->getStatusCode());
521+
$this->assertEquals('text/html', $response->getHeaderLine('Content-Type'));
522+
$this->assertEquals("OK\n", (string) $response->getBody());
523+
}
524+
525+
public function testGlobalMiddlewareClassNameAndSameForRouterCallsSameMiddlewareInstanceTwiceAndNextReturnsResponseFromController()
526+
{
527+
$middleware = new class {
528+
private $called = 0;
529+
public function __invoke(ServerRequestInterface $request, callable $next)
530+
{
531+
return $next($request->withAttribute('called', ++$this->called));
532+
}
533+
};
534+
535+
$app = $this->createAppWithoutLogger(get_class($middleware));
536+
537+
$app->get('/', get_class($middleware), function (ServerRequestInterface $request) {
538+
return new Response(
539+
200,
540+
[
541+
'Content-Type' => 'text/html'
542+
],
543+
$request->getAttribute('called') . "\n"
544+
);
545+
});
546+
547+
$request = new ServerRequest('GET', 'http://localhost/');
548+
549+
// $response = $app->handleRequest($request);
550+
$ref = new \ReflectionMethod($app, 'handleRequest');
551+
$ref->setAccessible(true);
552+
$response = $ref->invoke($app, $request);
553+
554+
/** @var ResponseInterface $response */
555+
$this->assertInstanceOf(ResponseInterface::class, $response);
556+
$this->assertEquals(200, $response->getStatusCode());
557+
$this->assertEquals('text/html', $response->getHeaderLine('Content-Type'));
558+
$this->assertEquals("2\n", (string) $response->getBody());
559+
}
560+
455561
public function testGlobalMiddlewareCallsNextWithModifiedRequestWillBeUsedForRouting()
456562
{
457563
$app = $this->createAppWithoutLogger(function (ServerRequestInterface $request, callable $next) {
@@ -669,7 +775,8 @@ public function testGlobalMiddlewareCallsNextReturnsPromiseWhichResolvesWithModi
669775
$this->assertEquals("OK\n", (string) $response->getBody());
670776
}
671777

672-
private function createAppWithoutLogger(callable ...$middleware): App
778+
/** @param callable|class-string ...$middleware */
779+
private function createAppWithoutLogger(...$middleware): App
673780
{
674781
$app = new App(...$middleware);
675782

0 commit comments

Comments
 (0)