From 3d20d5f63ea5edcb509683c0dea7e2fa3f54ec2e Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 10 Aug 2019 21:30:47 +0200 Subject: [PATCH 1/7] #2778 Configure the application via a container --- Slim/Factory/AppFactory.php | 22 +++++++++++++++++++ tests/Factory/AppFactoryTest.php | 37 ++++++++++++++++++++++++++++++++ tests/Mocks/MockContainer.php | 26 ++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 tests/Mocks/MockContainer.php diff --git a/Slim/Factory/AppFactory.php b/Slim/Factory/AppFactory.php index 54b0864d9..9d3c10979 100644 --- a/Slim/Factory/AppFactory.php +++ b/Slim/Factory/AppFactory.php @@ -89,6 +89,28 @@ public static function create( ); } + /** + * @param ContainerInterface $container + * @return App + */ + public static function createFromContainer(ContainerInterface $container): App + { + $responseFactory = $container->has(ResponseFactoryInterface::class) + ? $container->get(ResponseFactoryInterface::class) + : self::determineResponseFactory(); + $callableResolver = $container->has(CallableResolverInterface::class) + ? $container->get(CallableResolverInterface::class) + : null; + $routeCollector = $container->has(RouteCollectorInterface::class) + ? $container->get(RouteCollectorInterface::class) + : null; + $routeResolver = $container->has(RouteResolverInterface::class) + ? $container->get(RouteResolverInterface::class) + : null; + + return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver); + } + /** * @return ResponseFactoryInterface * @throws RuntimeException diff --git a/tests/Factory/AppFactoryTest.php b/tests/Factory/AppFactoryTest.php index 83ed1ebb2..423f373ba 100644 --- a/tests/Factory/AppFactoryTest.php +++ b/tests/Factory/AppFactoryTest.php @@ -31,6 +31,7 @@ use Slim\Interfaces\RouteResolverInterface; use Slim\Psr7\Factory\ResponseFactory as SlimResponseFactory; use Slim\Routing\RouteCollector; +use Slim\Tests\Mocks\MockContainer; use Slim\Tests\Mocks\MockPsr17FactoryWithoutStreamFactory; use Slim\Tests\TestCase; use Zend\Diactoros\ResponseFactory as ZendDiactorosResponseFactory; @@ -228,4 +229,40 @@ public function testResponseAndStreamFactoryIsBeingInjectedInDecoratedResponseFa $this->assertSame($streamFactoryProphecy->reveal(), $streamFactoryProperty->getValue($response)); } + + public function testCreateAppWithEmptyContainer() + { + $container = new MockContainer([]); + + $app = AppFactory::createFromContainer($container); + + $this->assertSame($container, $app->getContainer()); + } + + public function testCreateAppWithContainerThatProvidesAllImplementations() + { + $responseFactory = $this->createMock(ResponseFactoryInterface::class); + $callableResolver = $this->createMock(CallableResolverInterface::class); + $routeParser = $this->createMock(RouteParserInterface::class); + $routeCollector = $this->createConfiguredMock(RouteCollectorInterface::class, [ + 'getRouteParser' => $routeParser + ]); + $routeResolver = $this->createMock(RouteResolverInterface::class); + + $container = new MockContainer([ + ResponseFactoryInterface::class => $responseFactory, + CallableResolverInterface::class => $callableResolver, + RouteCollectorInterface::class => $routeCollector, + RouteParserInterface::class => $routeParser, + RouteResolverInterface::class => $routeResolver, + ]); + + $app = AppFactory::createFromContainer($container); + + $this->assertSame($responseFactory, $app->getResponseFactory()); + $this->assertSame($container, $app->getContainer()); + $this->assertSame($callableResolver, $app->getCallableResolver()); + $this->assertSame($routeCollector, $app->getRouteCollector()); + $this->assertSame($routeResolver, $app->getRouteResolver()); + } } diff --git a/tests/Mocks/MockContainer.php b/tests/Mocks/MockContainer.php new file mode 100644 index 000000000..459378818 --- /dev/null +++ b/tests/Mocks/MockContainer.php @@ -0,0 +1,26 @@ +entries = $entries; + } + + public function get($id) + { + return $this->entries[$id]; + } + + public function has($id) + { + return array_key_exists($id, $this->entries); + } +} From 5cd23e0d456c61876155244afefaf855958458a2 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Sat, 10 Aug 2019 22:42:53 +0200 Subject: [PATCH 2/7] Remove PHPUnit mocks --- tests/Factory/AppFactoryTest.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/Factory/AppFactoryTest.php b/tests/Factory/AppFactoryTest.php index 423f373ba..09b53dbe6 100644 --- a/tests/Factory/AppFactoryTest.php +++ b/tests/Factory/AppFactoryTest.php @@ -241,13 +241,14 @@ public function testCreateAppWithEmptyContainer() public function testCreateAppWithContainerThatProvidesAllImplementations() { - $responseFactory = $this->createMock(ResponseFactoryInterface::class); - $callableResolver = $this->createMock(CallableResolverInterface::class); - $routeParser = $this->createMock(RouteParserInterface::class); - $routeCollector = $this->createConfiguredMock(RouteCollectorInterface::class, [ - 'getRouteParser' => $routeParser - ]); - $routeResolver = $this->createMock(RouteResolverInterface::class); + $responseFactory = $this->prophesize(ResponseFactoryInterface::class)->reveal(); + $callableResolver = $this->prophesize(CallableResolverInterface::class)->reveal(); + $routeParser = $this->prophesize(RouteParserInterface::class)->reveal(); + $routeCollectorProphecy = $this->prophesize(RouteCollectorInterface::class); + $routeCollectorProphecy->getRouteParser() + ->willReturn($routeParser); + $routeCollector = $routeCollectorProphecy->reveal(); + $routeResolver = $this->prophesize(RouteResolverInterface::class)->reveal(); $container = new MockContainer([ ResponseFactoryInterface::class => $responseFactory, From ed72502e7c7060ed91ac121d06d67153ba21faa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20B=C3=A9rub=C3=A9?= Date: Sat, 10 Aug 2019 16:24:16 -0600 Subject: [PATCH 3/7] make createFromContainer uses create --- Slim/Factory/AppFactory.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Slim/Factory/AppFactory.php b/Slim/Factory/AppFactory.php index 9d3c10979..c3c797727 100644 --- a/Slim/Factory/AppFactory.php +++ b/Slim/Factory/AppFactory.php @@ -97,18 +97,21 @@ public static function createFromContainer(ContainerInterface $container): App { $responseFactory = $container->has(ResponseFactoryInterface::class) ? $container->get(ResponseFactoryInterface::class) - : self::determineResponseFactory(); + : null; + $callableResolver = $container->has(CallableResolverInterface::class) ? $container->get(CallableResolverInterface::class) : null; + $routeCollector = $container->has(RouteCollectorInterface::class) ? $container->get(RouteCollectorInterface::class) : null; + $routeResolver = $container->has(RouteResolverInterface::class) ? $container->get(RouteResolverInterface::class) : null; - return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver); + return self::create($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver); } /** From 4e8b2c13dc51dde68517dd0222c7ccc17ce4b9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20B=C3=83=C2=A9rub=C3=83=C2=A9?= Date: Sat, 10 Aug 2019 16:24:32 -0600 Subject: [PATCH 4/7] add prophesized tests for createFromContainer method --- tests/Factory/AppFactoryTest.php | 135 ++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 29 deletions(-) diff --git a/tests/Factory/AppFactoryTest.php b/tests/Factory/AppFactoryTest.php index 09b53dbe6..d3d13cfab 100644 --- a/tests/Factory/AppFactoryTest.php +++ b/tests/Factory/AppFactoryTest.php @@ -31,7 +31,6 @@ use Slim\Interfaces\RouteResolverInterface; use Slim\Psr7\Factory\ResponseFactory as SlimResponseFactory; use Slim\Routing\RouteCollector; -use Slim\Tests\Mocks\MockContainer; use Slim\Tests\Mocks\MockPsr17FactoryWithoutStreamFactory; use Slim\Tests\TestCase; use Zend\Diactoros\ResponseFactory as ZendDiactorosResponseFactory; @@ -230,40 +229,118 @@ public function testResponseAndStreamFactoryIsBeingInjectedInDecoratedResponseFa $this->assertSame($streamFactoryProphecy->reveal(), $streamFactoryProperty->getValue($response)); } - public function testCreateAppWithEmptyContainer() + public function testCreateAppWithContainerUsesContainerDependenciesWhenPresent() { - $container = new MockContainer([]); + $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); + $callableResolverProphecy = $this->prophesize(CallableResolverInterface::class); + $routeResolverProphecy = $this->prophesize(RouteResolverInterface::class); + $routeParserProphecy = $this->prophesize(RouteParserInterface::class); + + $routeCollectorProphecy = $this->prophesize(RouteCollectorInterface::class); + $routeCollectorProphecy + ->getRouteParser() + ->willReturn($routeParserProphecy->reveal()) + ->shouldBeCalledOnce(); + + $containerProphecy = $this->prophesize(ContainerInterface::class); + + $containerProphecy + ->has(ResponseFactoryInterface::class) + ->willReturn(true) + ->shouldBeCalledOnce(); + + $containerProphecy + ->get(ResponseFactoryInterface::class) + ->willReturn($responseFactoryProphecy->reveal()) + ->shouldBeCalledOnce(); + + $containerProphecy + ->has(CallableResolverInterface::class) + ->willReturn(true) + ->shouldBeCalledOnce(); + + $containerProphecy + ->get(CallableResolverInterface::class) + ->willReturn($callableResolverProphecy->reveal()) + ->shouldBeCalledOnce(); + + $containerProphecy + ->has(RouteCollectorInterface::class) + ->willReturn(true) + ->shouldBeCalledOnce(); + + $containerProphecy + ->get(RouteCollectorInterface::class) + ->willReturn($routeCollectorProphecy->reveal()) + ->shouldBeCalledOnce(); + + $containerProphecy + ->has(RouteResolverInterface::class) + ->willReturn(true) + ->shouldBeCalledOnce(); + + $containerProphecy + ->get(RouteResolverInterface::class) + ->willReturn($routeResolverProphecy->reveal()) + ->shouldBeCalledOnce(); - $app = AppFactory::createFromContainer($container); + AppFactory::setSlimHttpDecoratorsAutomaticDetection(false); + $app = AppFactory::createFromContainer($containerProphecy->reveal()); - $this->assertSame($container, $app->getContainer()); + $this->assertSame($app->getResponseFactory(), $responseFactoryProphecy->reveal()); + $this->assertSame($app->getContainer(), $containerProphecy->reveal()); + $this->assertSame($app->getCallableResolver(), $callableResolverProphecy->reveal()); + $this->assertSame($app->getRouteCollector(), $routeCollectorProphecy->reveal()); + $this->assertSame($app->getRouteResolver(), $routeResolverProphecy->reveal()); } - public function testCreateAppWithContainerThatProvidesAllImplementations() + public function testCreateAppWithContainerFallsBackOntoInternalLogic() { - $responseFactory = $this->prophesize(ResponseFactoryInterface::class)->reveal(); - $callableResolver = $this->prophesize(CallableResolverInterface::class)->reveal(); - $routeParser = $this->prophesize(RouteParserInterface::class)->reveal(); + $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); + $callableResolverProphecy = $this->prophesize(CallableResolverInterface::class); + $routeResolverProphecy = $this->prophesize(RouteResolverInterface::class); + $routeParserProphecy = $this->prophesize(RouteParserInterface::class); + $routeCollectorProphecy = $this->prophesize(RouteCollectorInterface::class); - $routeCollectorProphecy->getRouteParser() - ->willReturn($routeParser); - $routeCollector = $routeCollectorProphecy->reveal(); - $routeResolver = $this->prophesize(RouteResolverInterface::class)->reveal(); - - $container = new MockContainer([ - ResponseFactoryInterface::class => $responseFactory, - CallableResolverInterface::class => $callableResolver, - RouteCollectorInterface::class => $routeCollector, - RouteParserInterface::class => $routeParser, - RouteResolverInterface::class => $routeResolver, - ]); - - $app = AppFactory::createFromContainer($container); - - $this->assertSame($responseFactory, $app->getResponseFactory()); - $this->assertSame($container, $app->getContainer()); - $this->assertSame($callableResolver, $app->getCallableResolver()); - $this->assertSame($routeCollector, $app->getRouteCollector()); - $this->assertSame($routeResolver, $app->getRouteResolver()); + $routeCollectorProphecy + ->getRouteParser() + ->willReturn($routeParserProphecy->reveal()) + ->shouldBeCalledOnce(); + + $containerProphecy = $this->prophesize(ContainerInterface::class); + + $containerProphecy + ->has(ResponseFactoryInterface::class) + ->willReturn(false) + ->shouldBeCalledOnce(); + + $containerProphecy + ->has(CallableResolverInterface::class) + ->willReturn(false) + ->shouldBeCalledOnce(); + + $containerProphecy + ->has(RouteCollectorInterface::class) + ->willReturn(false) + ->shouldBeCalledOnce(); + + $containerProphecy + ->has(RouteResolverInterface::class) + ->willReturn(false) + ->shouldBeCalledOnce(); + + AppFactory::setSlimHttpDecoratorsAutomaticDetection(false); + AppFactory::setResponseFactory($responseFactoryProphecy->reveal()); + AppFactory::setCallableResolver($callableResolverProphecy->reveal()); + AppFactory::setRouteCollector($routeCollectorProphecy->reveal()); + AppFactory::setRouteResolver($routeResolverProphecy->reveal()); + + $app = AppFactory::createFromContainer($containerProphecy->reveal()); + + $this->assertSame($app->getResponseFactory(), $responseFactoryProphecy->reveal()); + $this->assertSame($app->getContainer(), $containerProphecy->reveal()); + $this->assertSame($app->getCallableResolver(), $callableResolverProphecy->reveal()); + $this->assertSame($app->getRouteCollector(), $routeCollectorProphecy->reveal()); + $this->assertSame($app->getRouteResolver(), $routeResolverProphecy->reveal()); } } From e58b5a43eb5cf3fffb4e20f5e20ad81b4b0bed5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20B=C3=83=C2=A9rub=C3=83=C2=A9?= Date: Sat, 10 Aug 2019 16:24:32 -0600 Subject: [PATCH 5/7] remove MockContainer --- tests/Mocks/MockContainer.php | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 tests/Mocks/MockContainer.php diff --git a/tests/Mocks/MockContainer.php b/tests/Mocks/MockContainer.php deleted file mode 100644 index 459378818..000000000 --- a/tests/Mocks/MockContainer.php +++ /dev/null @@ -1,26 +0,0 @@ -entries = $entries; - } - - public function get($id) - { - return $this->entries[$id]; - } - - public function has($id) - { - return array_key_exists($id, $this->entries); - } -} From fab65b4de34d14667069747b620c6e8994e91402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20B=C3=A9rub=C3=A9?= Date: Sun, 11 Aug 2019 09:39:32 -0600 Subject: [PATCH 6/7] revert back to instantiating App manually instead of using create method --- Slim/Factory/AppFactory.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Slim/Factory/AppFactory.php b/Slim/Factory/AppFactory.php index c3c797727..331c6933e 100644 --- a/Slim/Factory/AppFactory.php +++ b/Slim/Factory/AppFactory.php @@ -97,7 +97,7 @@ public static function createFromContainer(ContainerInterface $container): App { $responseFactory = $container->has(ResponseFactoryInterface::class) ? $container->get(ResponseFactoryInterface::class) - : null; + : self::determineResponseFactory(); $callableResolver = $container->has(CallableResolverInterface::class) ? $container->get(CallableResolverInterface::class) @@ -111,7 +111,7 @@ public static function createFromContainer(ContainerInterface $container): App ? $container->get(RouteResolverInterface::class) : null; - return self::create($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver); + return new App($responseFactory, $container, $callableResolver, $routeCollector, $routeResolver); } /** From 2f1b23936c2ea7a406b46b6b5cd88f8584d6e7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20B=C3=A9rub=C3=A9?= Date: Sun, 11 Aug 2019 09:39:41 -0600 Subject: [PATCH 7/7] remove extraneous test --- tests/Factory/AppFactoryTest.php | 50 -------------------------------- 1 file changed, 50 deletions(-) diff --git a/tests/Factory/AppFactoryTest.php b/tests/Factory/AppFactoryTest.php index d3d13cfab..d490ff720 100644 --- a/tests/Factory/AppFactoryTest.php +++ b/tests/Factory/AppFactoryTest.php @@ -293,54 +293,4 @@ public function testCreateAppWithContainerUsesContainerDependenciesWhenPresent() $this->assertSame($app->getRouteCollector(), $routeCollectorProphecy->reveal()); $this->assertSame($app->getRouteResolver(), $routeResolverProphecy->reveal()); } - - public function testCreateAppWithContainerFallsBackOntoInternalLogic() - { - $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); - $callableResolverProphecy = $this->prophesize(CallableResolverInterface::class); - $routeResolverProphecy = $this->prophesize(RouteResolverInterface::class); - $routeParserProphecy = $this->prophesize(RouteParserInterface::class); - - $routeCollectorProphecy = $this->prophesize(RouteCollectorInterface::class); - $routeCollectorProphecy - ->getRouteParser() - ->willReturn($routeParserProphecy->reveal()) - ->shouldBeCalledOnce(); - - $containerProphecy = $this->prophesize(ContainerInterface::class); - - $containerProphecy - ->has(ResponseFactoryInterface::class) - ->willReturn(false) - ->shouldBeCalledOnce(); - - $containerProphecy - ->has(CallableResolverInterface::class) - ->willReturn(false) - ->shouldBeCalledOnce(); - - $containerProphecy - ->has(RouteCollectorInterface::class) - ->willReturn(false) - ->shouldBeCalledOnce(); - - $containerProphecy - ->has(RouteResolverInterface::class) - ->willReturn(false) - ->shouldBeCalledOnce(); - - AppFactory::setSlimHttpDecoratorsAutomaticDetection(false); - AppFactory::setResponseFactory($responseFactoryProphecy->reveal()); - AppFactory::setCallableResolver($callableResolverProphecy->reveal()); - AppFactory::setRouteCollector($routeCollectorProphecy->reveal()); - AppFactory::setRouteResolver($routeResolverProphecy->reveal()); - - $app = AppFactory::createFromContainer($containerProphecy->reveal()); - - $this->assertSame($app->getResponseFactory(), $responseFactoryProphecy->reveal()); - $this->assertSame($app->getContainer(), $containerProphecy->reveal()); - $this->assertSame($app->getCallableResolver(), $callableResolverProphecy->reveal()); - $this->assertSame($app->getRouteCollector(), $routeCollectorProphecy->reveal()); - $this->assertSame($app->getRouteResolver(), $routeResolverProphecy->reveal()); - } }