Skip to content

Commit cbb5369

Browse files
committed
Refactor App to load RouteHandler from Container
1 parent 82fb56c commit cbb5369

4 files changed

Lines changed: 143 additions & 35 deletions

File tree

src/App.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public function __construct(...$middleware)
108108
}
109109
}
110110

111-
$this->router = new RouteHandler($container);
111+
$this->router = $container->getObject(RouteHandler::class);
112112
$handlers[] = $this->router;
113113
$this->handler = new MiddlewareHandler($handlers);
114114
$this->sapi = \PHP_SAPI === 'cli' ? new ReactiveHandler($container->getEnv('X_LISTEN')) : new SapiHandler();

src/Container.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace FrameworkX;
44

5+
use FrameworkX\Io\RouteHandler;
56
use Psr\Container\ContainerInterface;
67
use Psr\Http\Message\ServerRequestInterface;
78

@@ -163,6 +164,8 @@ public function getObject(string $class) /*: object (PHP 7.2+) */
163164
// fallback for missing required internal classes from PSR-11 adapter
164165
if ($class === Container::class) {
165166
return $this; // @phpstan-ignore-line returns instanceof `T`
167+
} elseif ($class === RouteHandler::class) {
168+
return new RouteHandler($this); // @phpstan-ignore-line returns instanceof `T`
166169
}
167170
return new $class();
168171
}

tests/AppTest.php

Lines changed: 99 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,30 @@
3636

3737
class AppTest extends TestCase
3838
{
39+
public function testConstructAssignsDefaultMiddleware(): void
40+
{
41+
$app = new App();
42+
43+
$ref = new \ReflectionProperty($app, 'handler');
44+
if (PHP_VERSION_ID < 80100) {
45+
$ref->setAccessible(true);
46+
}
47+
$handler = $ref->getValue($app);
48+
assert($handler instanceof MiddlewareHandler);
49+
50+
$ref = new \ReflectionProperty($handler, 'handlers');
51+
if (PHP_VERSION_ID < 80100) {
52+
$ref->setAccessible(true);
53+
}
54+
$handlers = $ref->getValue($handler);
55+
assert(is_array($handlers));
56+
57+
$this->assertCount(3, $handlers);
58+
$this->assertInstanceOf(AccessLogHandler::class, $handlers[0]);
59+
$this->assertInstanceOf(ErrorHandler::class, $handlers[1]);
60+
$this->assertInstanceOf(RouteHandler::class, $handlers[2]);
61+
}
62+
3963
public function testConstructWithMiddlewareAssignsGivenMiddleware(): void
4064
{
4165
$middleware = function () { };
@@ -62,15 +86,17 @@ public function testConstructWithMiddlewareAssignsGivenMiddleware(): void
6286
$this->assertInstanceOf(RouteHandler::class, $handlers[3]);
6387
}
6488

65-
public function testConstructWithContainerAssignsDefaultHandlersAndContainerForRouteHandlerOnly(): void
89+
public function testConstructWithContainerMockAssignsDefaultHandlersFromContainer(): void
6690
{
6791
$accessLogHandler = new AccessLogHandler();
6892
$errorHandler = new ErrorHandler();
93+
$routeHandler = $this->createMock(RouteHandler::class);
6994

7095
$container = $this->createMock(Container::class);
71-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
96+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
7297
[AccessLogHandler::class, $accessLogHandler],
7398
[ErrorHandler::class, $errorHandler],
99+
[RouteHandler::class, $routeHandler],
74100
]);
75101

76102
assert($container instanceof Container);
@@ -93,6 +119,31 @@ public function testConstructWithContainerAssignsDefaultHandlersAndContainerForR
93119
$this->assertCount(3, $handlers);
94120
$this->assertSame($accessLogHandler, $handlers[0]);
95121
$this->assertSame($errorHandler, $handlers[1]);
122+
$this->assertSame($routeHandler, $handlers[2]);
123+
}
124+
125+
public function testConstructWithContainerInstanceAssignsDefaultHandlersAndContainerForRouteHandlerOnly(): void
126+
{
127+
$container = new Container([]);
128+
$app = new App($container);
129+
130+
$ref = new ReflectionProperty($app, 'handler');
131+
if (PHP_VERSION_ID < 80100) {
132+
$ref->setAccessible(true);
133+
}
134+
$handler = $ref->getValue($app);
135+
assert($handler instanceof MiddlewareHandler);
136+
137+
$ref = new ReflectionProperty($handler, 'handlers');
138+
if (PHP_VERSION_ID < 80100) {
139+
$ref->setAccessible(true);
140+
}
141+
$handlers = $ref->getValue($handler);
142+
assert(is_array($handlers));
143+
144+
$this->assertCount(3, $handlers);
145+
$this->assertInstanceOf(AccessLogHandler::class, $handlers[0]);
146+
$this->assertInstanceOf(ErrorHandler::class, $handlers[1]);
96147
$this->assertInstanceOf(RouteHandler::class, $handlers[2]);
97148

98149
$routeHandler = $handlers[2];
@@ -109,12 +160,14 @@ public function testConstructWithContainerAndMiddlewareClassNameAssignsCallableF
109160

110161
$accessLogHandler = new AccessLogHandler();
111162
$errorHandler = new ErrorHandler();
163+
$routeHandler = $this->createMock(RouteHandler::class);
112164

113165
$container = $this->createMock(Container::class);
114166
$container->expects($this->once())->method('callable')->with('stdClass')->willReturn($middleware);
115-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
167+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
116168
[AccessLogHandler::class, $accessLogHandler],
117169
[ErrorHandler::class, $errorHandler],
170+
[RouteHandler::class, $routeHandler],
118171
]);
119172

120173
assert($container instanceof Container);
@@ -138,14 +191,7 @@ public function testConstructWithContainerAndMiddlewareClassNameAssignsCallableF
138191
$this->assertSame($accessLogHandler, $handlers[0]);
139192
$this->assertSame($errorHandler, $handlers[1]);
140193
$this->assertSame($middleware, $handlers[2]);
141-
$this->assertInstanceOf(RouteHandler::class, $handlers[3]);
142-
143-
$routeHandler = $handlers[3];
144-
$ref = new ReflectionProperty($routeHandler, 'container');
145-
if (PHP_VERSION_ID < 80100) {
146-
$ref->setAccessible(true);
147-
}
148-
$this->assertSame($container, $ref->getValue($routeHandler));
194+
$this->assertSame($routeHandler, $handlers[3]);
149195
}
150196

151197
public function testConstructWithErrorHandlerOnlyAssignsErrorHandlerAfterDefaultAccessLogHandler(): void
@@ -228,11 +274,13 @@ public function testConstructWithContainerAndErrorHandlerClassAssignsErrorHandle
228274
{
229275
$accessLogHandler = new AccessLogHandler();
230276
$errorHandler = new ErrorHandler();
277+
$routeHandler = $this->createMock(RouteHandler::class);
231278

232279
$container = $this->createMock(Container::class);
233-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
280+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
234281
[AccessLogHandler::class, $accessLogHandler],
235282
[ErrorHandler::class, $errorHandler],
283+
[RouteHandler::class, $routeHandler],
236284
]);
237285

238286
assert($container instanceof Container);
@@ -255,26 +303,28 @@ public function testConstructWithContainerAndErrorHandlerClassAssignsErrorHandle
255303
$this->assertCount(3, $handlers);
256304
$this->assertSame($accessLogHandler, $handlers[0]);
257305
$this->assertSame($errorHandler, $handlers[1]);
258-
$this->assertInstanceOf(RouteHandler::class, $handlers[2]);
306+
$this->assertSame($routeHandler, $handlers[2]);
259307
}
260308

261309
public function testConstructWithMultipleContainersAndErrorHandlerClassAssignsErrorHandlerFromLastContainerBeforeErrorHandlerAfterDefaultAccessLogHandler(): void
262310
{
263311
$accessLogHandler = new AccessLogHandler();
264312
$errorHandler = new ErrorHandler();
313+
$routeHandler = $this->createMock(RouteHandler::class);
265314

266315
$unused = $this->createMock(Container::class);
267316
$unused->expects($this->never())->method('getObject');
268317

269318
$container = $this->createMock(Container::class);
270-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
319+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
271320
[AccessLogHandler::class, $accessLogHandler],
272321
[ErrorHandler::class, $errorHandler],
322+
[RouteHandler::class, $routeHandler],
273323
]);
274324

275325
assert($unused instanceof Container);
276326
assert($container instanceof Container);
277-
$app = new App($unused, $container, ErrorHandler::class, $unused);
327+
$app = new App($unused, $unused, $container, ErrorHandler::class);
278328

279329
$ref = new ReflectionProperty($app, 'handler');
280330
if (PHP_VERSION_ID < 80100) {
@@ -293,27 +343,29 @@ public function testConstructWithMultipleContainersAndErrorHandlerClassAssignsEr
293343
$this->assertCount(3, $handlers);
294344
$this->assertSame($accessLogHandler, $handlers[0]);
295345
$this->assertSame($errorHandler, $handlers[1]);
296-
$this->assertInstanceOf(RouteHandler::class, $handlers[2]);
346+
$this->assertSame($routeHandler, $handlers[2]);
297347
}
298348

299349
public function testConstructWithMultipleContainersAndMiddlewareAssignsErrorHandlerFromLastContainerBeforeMiddlewareAfterDefaultAccessLogHandler(): void
300350
{
301351
$middleware = function (ServerRequestInterface $request, callable $next) { };
302352
$accessLogHandler = new AccessLogHandler();
303353
$errorHandler = new ErrorHandler();
354+
$routeHandler = $this->createMock(RouteHandler::class);
304355

305356
$unused = $this->createMock(Container::class);
306357
$unused->expects($this->never())->method('getObject');
307358

308359
$container = $this->createMock(Container::class);
309-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
360+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
310361
[AccessLogHandler::class, $accessLogHandler],
311362
[ErrorHandler::class, $errorHandler],
363+
[RouteHandler::class, $routeHandler],
312364
]);
313365

314366
assert($unused instanceof Container);
315367
assert($container instanceof Container);
316-
$app = new App($unused, $container, $middleware, $unused);
368+
$app = new App($unused, $unused, $container, $middleware);
317369

318370
$ref = new ReflectionProperty($app, 'handler');
319371
if (PHP_VERSION_ID < 80100) {
@@ -333,7 +385,7 @@ public function testConstructWithMultipleContainersAndMiddlewareAssignsErrorHand
333385
$this->assertSame($accessLogHandler, $handlers[0]);
334386
$this->assertSame($errorHandler, $handlers[1]);
335387
$this->assertSame($middleware, $handlers[2]);
336-
$this->assertInstanceOf(RouteHandler::class, $handlers[3]);
388+
$this->assertSame($routeHandler, $handlers[3]);
337389
}
338390

339391
public function testConstructWithMiddlewareAndErrorHandlerAssignsGivenErrorHandlerAfterMiddlewareAndDefaultAccessLogHandlerAndErrorHandlerFirst(): void
@@ -372,6 +424,7 @@ public function testConstructWithMultipleContainersAndMiddlewareAndErrorHandlerC
372424

373425
$unused = $this->createMock(Container::class);
374426
$unused->expects($this->never())->method('getObject');
427+
assert($unused instanceof Container);
375428

376429
$accessLogHandler = new AccessLogHandler();
377430
$errorHandler1 = new ErrorHandler();
@@ -380,15 +433,19 @@ public function testConstructWithMultipleContainersAndMiddlewareAndErrorHandlerC
380433
[AccessLogHandler::class, $accessLogHandler],
381434
[ErrorHandler::class, $errorHandler1],
382435
]);
436+
assert($container1 instanceof Container);
383437

384438
$errorHandler2 = new ErrorHandler();
385439
$container2 = $this->createMock(Container::class);
386-
$container2->expects($this->exactly(1))->method('getObject')->with(ErrorHandler::class)->willReturn($errorHandler2);
387-
388-
assert($unused instanceof Container);
389-
assert($container1 instanceof Container);
440+
$container2->expects($this->once())->method('getObject')->with(ErrorHandler::class)->willReturn($errorHandler2);
390441
assert($container2 instanceof Container);
391-
$app = new App($unused, $container1, $middleware, $container2, ErrorHandler::class, $unused);
442+
443+
$routeHandler = $this->createMock(RouteHandler::class);
444+
$container3 = $this->createMock(Container::class);
445+
$container3->expects($this->once())->method('getObject')->with(RouteHandler::class)->willReturn($routeHandler);
446+
assert($container3 instanceof Container);
447+
448+
$app = new App($unused, $container1, $middleware, $container2, ErrorHandler::class, $unused, $container3);
392449

393450
$ref = new ReflectionProperty($app, 'handler');
394451
if (PHP_VERSION_ID < 80100) {
@@ -496,11 +553,13 @@ public function testConstructWithContainerAndAccessLogHandlerClassAndErrorHandle
496553
{
497554
$accessLogHandler = new AccessLogHandler();
498555
$errorHandler = new ErrorHandler();
556+
$routeHandler = $this->createMock(RouteHandler::class);
499557

500558
$container = $this->createMock(Container::class);
501-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
559+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
502560
[AccessLogHandler::class, $accessLogHandler],
503561
[ErrorHandler::class, $errorHandler],
562+
[RouteHandler::class, $routeHandler],
504563
]);
505564

506565
assert($container instanceof Container);
@@ -523,7 +582,7 @@ public function testConstructWithContainerAndAccessLogHandlerClassAndErrorHandle
523582
$this->assertCount(3, $handlers);
524583
$this->assertSame($accessLogHandler, $handlers[0]);
525584
$this->assertSame($errorHandler, $handlers[1]);
526-
$this->assertInstanceOf(RouteHandler::class, $handlers[2]);
585+
$this->assertSame($routeHandler, $handlers[2]);
527586
}
528587

529588
public function testConstructWithContainerAndAccessLogHandlerClassAndErrorHandlerClassWillUseContainerToGetAccessLogHandlerAndWillSkipAccessLogHandlerToDevNull(): void
@@ -532,11 +591,13 @@ public function testConstructWithContainerAndAccessLogHandlerClassAndErrorHandle
532591
$accessLogHandler->expects($this->once())->method('isDevNull')->willReturn(true);
533592

534593
$errorHandler = new ErrorHandler();
594+
$routeHandler = $this->createMock(RouteHandler::class);
535595

536596
$container = $this->createMock(Container::class);
537-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
597+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
538598
[AccessLogHandler::class, $accessLogHandler],
539599
[ErrorHandler::class, $errorHandler],
600+
[RouteHandler::class, $routeHandler],
540601
]);
541602

542603
assert($container instanceof Container);
@@ -558,7 +619,7 @@ public function testConstructWithContainerAndAccessLogHandlerClassAndErrorHandle
558619

559620
$this->assertCount(2, $handlers);
560621
$this->assertSame($errorHandler, $handlers[0]);
561-
$this->assertInstanceOf(RouteHandler::class, $handlers[1]);
622+
$this->assertSame($routeHandler, $handlers[1]);
562623
}
563624

564625
public function testConstructWithMiddlewareBeforeAccessLogHandlerAndErrorHandlerAssignsDefaultErrorHandlerAsFirstHandlerFollowedByGivenHandlers(): void
@@ -596,19 +657,21 @@ public function testConstructWithMultipleContainersAndAccessLogHandlerClassAndEr
596657
{
597658
$accessLogHandler = new AccessLogHandler();
598659
$errorHandler = new ErrorHandler();
660+
$routeHandler = $this->createMock(RouteHandler::class);
599661

600662
$unused = $this->createMock(Container::class);
601663
$unused->expects($this->never())->method('getObject');
602664

603665
$container = $this->createMock(Container::class);
604-
$container->expects($this->exactly(2))->method('getObject')->willReturnMap([
666+
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
605667
[AccessLogHandler::class, $accessLogHandler],
606668
[ErrorHandler::class, $errorHandler],
669+
[RouteHandler::class, $routeHandler],
607670
]);
608671

609672
assert($unused instanceof Container);
610673
assert($container instanceof Container);
611-
$app = new App($unused, $container, AccessLogHandler::class, ErrorHandler::class, $unused);
674+
$app = new App($unused, $unused, $container, AccessLogHandler::class, ErrorHandler::class);
612675

613676
$ref = new ReflectionProperty($app, 'handler');
614677
if (PHP_VERSION_ID < 80100) {
@@ -627,7 +690,7 @@ public function testConstructWithMultipleContainersAndAccessLogHandlerClassAndEr
627690
$this->assertCount(3, $handlers);
628691
$this->assertSame($accessLogHandler, $handlers[0]);
629692
$this->assertSame($errorHandler, $handlers[1]);
630-
$this->assertInstanceOf(RouteHandler::class, $handlers[2]);
693+
$this->assertSame($routeHandler, $handlers[2]);
631694
}
632695

633696

@@ -637,20 +700,22 @@ public function testConstructWithMultipleContainersAndMiddlewareAssignsDefaultHa
637700

638701
$accessLogHandler = new AccessLogHandler();
639702
$errorHandler = new ErrorHandler();
703+
$routeHandler = $this->createMock(RouteHandler::class);
640704

641705
$unused = $this->createMock(Container::class);
642706
$unused->expects($this->never())->method('getObject');
643707

644708
$container = $this->createMock(Container::class);
645-
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
709+
$container->expects($this->exactly(4))->method('getObject')->willReturnMap([
646710
[AccessLogHandler::class, $accessLogHandler],
647711
[ErrorHandler::class, $errorHandler],
648712
[Container::class, $container],
713+
[RouteHandler::class, $routeHandler],
649714
]);
650715

651716
assert($unused instanceof Container);
652717
assert($container instanceof Container);
653-
$app = new App($unused, $container, Container::class, $middleware, $unused);
718+
$app = new App($unused, $unused, $container, Container::class, $middleware);
654719

655720
$ref = new ReflectionProperty($app, 'handler');
656721
if (PHP_VERSION_ID < 80100) {
@@ -670,7 +735,7 @@ public function testConstructWithMultipleContainersAndMiddlewareAssignsDefaultHa
670735
$this->assertSame($accessLogHandler, $handlers[0]);
671736
$this->assertSame($errorHandler, $handlers[1]);
672737
$this->assertSame($middleware, $handlers[2]);
673-
$this->assertInstanceOf(RouteHandler::class, $handlers[3]);
738+
$this->assertSame($routeHandler, $handlers[3]);
674739
}
675740

676741
public function testConstructWithAccessLogHandlerOnlyThrows(): void

0 commit comments

Comments
 (0)