diff --git a/src/ApplicationListenersProvider.php b/src/ApplicationListenersProvider.php index 6564c5c3..ec2973c8 100644 --- a/src/ApplicationListenersProvider.php +++ b/src/ApplicationListenersProvider.php @@ -17,7 +17,10 @@ use const SORT_REGULAR; /** - * Provides lazy container + * Double-dispatch listener provider for Application to ensure default listeners and to ensure listeners attached + * once on Application instantiation. + * + * Delays fetching listener aggregates from container until attempt to attach them is made. */ final class ApplicationListenersProvider { diff --git a/test/Application/BadControllerTrait.php b/test/Application/BadControllerTrait.php index b80e4059..6f28de13 100644 --- a/test/Application/BadControllerTrait.php +++ b/test/Application/BadControllerTrait.php @@ -7,8 +7,9 @@ use Laminas\Http\PhpEnvironment\Request; use Laminas\Http\PhpEnvironment\Response; use Laminas\Mvc\Application; +use Laminas\Mvc\ConfigProvider; use Laminas\Mvc\Controller\ControllerManager; -use Laminas\Router\ConfigProvider; +use Laminas\Router; use Laminas\Router\Http\Literal; use Laminas\ServiceManager\ServiceManager; use Laminas\Stdlib\ArrayUtils; @@ -21,8 +22,8 @@ trait BadControllerTrait { public function prepareApplication(): Application { - $config = [ - 'router' => [ + $testConfig = [ + 'router' => [ 'routes' => [ 'path' => [ 'type' => Literal::class, @@ -36,14 +37,7 @@ public function prepareApplication(): Application ], ], ], - ]; - - $serviceConfig = ArrayUtils::merge( - ArrayUtils::merge( - (new \Laminas\Mvc\ConfigProvider())->getDependencies(), - (new ConfigProvider())->getDependencyConfig(), - ), - [ + 'dependencies' => [ 'aliases' => [ 'ControllerLoader' => ControllerManager::class, ], @@ -62,13 +56,19 @@ public function prepareApplication(): Application 'SendResponseListener' => MockSendResponseListener::class, 'BootstrapListener' => StubBootstrapListener::class, ], - 'services' => [ - 'config' => $config, - ], - ] + ], + ]; + + $config = ArrayUtils::merge( + ArrayUtils::merge( + (new ConfigProvider())(), + (new Router\ConfigProvider())(), + ), + $testConfig ); - $services = new ServiceManager($serviceConfig); - $application = $services->get('Application'); + $config['dependencies']['services']['config'] = $config; + $services = new ServiceManager($config['dependencies']); + $application = $services->get('Application'); $request = $services->get('Request'); $request->setUri('http://example.local/bad'); diff --git a/test/Application/InvalidControllerTypeTrait.php b/test/Application/InvalidControllerTypeTrait.php index bbf0d240..fb050fee 100644 --- a/test/Application/InvalidControllerTypeTrait.php +++ b/test/Application/InvalidControllerTypeTrait.php @@ -7,8 +7,9 @@ use Laminas\Http\PhpEnvironment\Request; use Laminas\Http\PhpEnvironment\Response; use Laminas\Mvc\Application; +use Laminas\Mvc\ConfigProvider; use Laminas\Mvc\Controller\ControllerManager; -use Laminas\Router\ConfigProvider; +use Laminas\Router; use Laminas\Router\Http\Literal; use Laminas\ServiceManager\ServiceManager; use Laminas\Stdlib\ArrayUtils; @@ -21,8 +22,8 @@ trait InvalidControllerTypeTrait { public function prepareApplication(): Application { - $config = [ - 'router' => [ + $testConfig = [ + 'router' => [ 'routes' => [ 'path' => [ 'type' => Literal::class, @@ -36,14 +37,7 @@ public function prepareApplication(): Application ], ], ], - ]; - - $serviceConfig = ArrayUtils::merge( - ArrayUtils::merge( - (new \Laminas\Mvc\ConfigProvider())->getDependencies(), - (new ConfigProvider())->getDependencyConfig(), - ), - [ + 'dependencies' => [ 'aliases' => [ 'ControllerLoader' => 'ControllerManager', ], @@ -53,7 +47,6 @@ public function prepareApplication(): Application 'bad' => static fn(): stdClass => new stdClass(), ], ]), - 'Router' => static fn($services) => $services->get('HttpRouter'), ], 'invokables' => [ 'Request' => Request::class, @@ -62,13 +55,20 @@ public function prepareApplication(): Application 'SendResponseListener' => MockSendResponseListener::class, 'BootstrapListener' => StubBootstrapListener::class, ], - 'services' => [ - 'config' => $config, - ], - ] + ], + ]; + + $config = ArrayUtils::merge( + ArrayUtils::merge( + (new ConfigProvider())(), + (new Router\ConfigProvider())(), + ), + $testConfig ); - $services = new ServiceManager($serviceConfig); - $application = $services->get('Application'); + $config['dependencies']['services']['config'] = $config; + + $services = new ServiceManager($config['dependencies']); + $application = $services->get('Application'); $request = $services->get('Request'); $request->setUri('http://example.local/bad'); diff --git a/test/Application/MissingControllerTrait.php b/test/Application/MissingControllerTrait.php index 7340e2da..bd093a13 100644 --- a/test/Application/MissingControllerTrait.php +++ b/test/Application/MissingControllerTrait.php @@ -7,7 +7,8 @@ use Laminas\Http\PhpEnvironment\Request; use Laminas\Http\PhpEnvironment\Response; use Laminas\Mvc\Application; -use Laminas\Router\ConfigProvider; +use Laminas\Mvc\ConfigProvider; +use Laminas\Router; use Laminas\Router\Http\Literal; use Laminas\ServiceManager\ServiceManager; use Laminas\Stdlib\ArrayUtils; @@ -19,8 +20,8 @@ trait MissingControllerTrait { public function prepareApplication(): Application { - $config = [ - 'router' => [ + $testConfig = [ + 'router' => [ 'routes' => [ 'path' => [ 'type' => Literal::class, @@ -34,17 +35,7 @@ public function prepareApplication(): Application ], ], ], - ]; - - $serviceConfig = ArrayUtils::merge( - ArrayUtils::merge( - (new \Laminas\Mvc\ConfigProvider())->getDependencies(), - (new ConfigProvider())->getDependencyConfig(), - ), - [ - 'factories' => [ - 'Router' => static fn($services) => $services->get('HttpRouter'), - ], + 'dependencies' => [ 'invokables' => [ 'Request' => Request::class, 'Response' => Response::class, @@ -52,13 +43,21 @@ public function prepareApplication(): Application 'SendResponseListener' => MockSendResponseListener::class, 'BootstrapListener' => StubBootstrapListener::class, ], - 'services' => [ - 'config' => $config, - ], - ] + ], + ]; + + $config = ArrayUtils::merge( + ArrayUtils::merge( + (new ConfigProvider())(), + (new Router\ConfigProvider())(), + ), + $testConfig ); - $services = new ServiceManager($serviceConfig); - $application = $services->get('Application'); + + $config['dependencies']['services']['config'] = $config; + + $services = new ServiceManager($config['dependencies']); + $application = $services->get('Application'); $request = $services->get('Request'); $request->setUri('http://example.local/bad'); diff --git a/test/Application/PathControllerTrait.php b/test/Application/PathControllerTrait.php index 9d2d0eaf..625e2a7d 100644 --- a/test/Application/PathControllerTrait.php +++ b/test/Application/PathControllerTrait.php @@ -22,8 +22,8 @@ trait PathControllerTrait { public function prepareApplication(): Application { - $config = [ - 'router' => [ + $testConfig = [ + 'router' => [ 'routes' => [ 'path' => [ 'type' => Literal::class, @@ -36,14 +36,7 @@ public function prepareApplication(): Application ], ], ], - ]; - - $serviceConfig = ArrayUtils::merge( - ArrayUtils::merge( - (new ConfigProvider())->getDependencies(), - (new Router\ConfigProvider())->getDependencyConfig(), - ), - [ + 'dependencies' => [ 'aliases' => [ 'ControllerLoader' => ControllerManager::class, ], @@ -53,7 +46,6 @@ public function prepareApplication(): Application 'path' => static fn() => new TestAsset\PathController(), ], ]), - 'Router' => static fn($services) => $services->get('HttpRouter'), ], 'invokables' => [ 'Request' => Request::class, @@ -62,13 +54,20 @@ public function prepareApplication(): Application 'SendResponseListener' => MockSendResponseListener::class, 'BootstrapListener' => StubBootstrapListener::class, ], - 'services' => [ - 'config' => $config, - ], - ] + ], + ]; + + $config = ArrayUtils::merge( + ArrayUtils::merge( + (new ConfigProvider())(), + (new Router\ConfigProvider())(), + ), + $testConfig ); - $services = new ServiceManager($serviceConfig); - $application = $services->get('Application'); + $config['dependencies']['services']['config'] = $config; + + $services = new ServiceManager($config['dependencies']); + $application = $services->get('Application'); $request = $services->get('Request'); $request->setUri('http://example.local/path'); diff --git a/test/ApplicationTest.php b/test/ApplicationTest.php index 5123f444..3d3f7fed 100644 --- a/test/ApplicationTest.php +++ b/test/ApplicationTest.php @@ -10,12 +10,12 @@ use Laminas\Http\PhpEnvironment\Request; use Laminas\Http\PhpEnvironment\Response; use Laminas\Mvc\Application; +use Laminas\Mvc\ConfigProvider; use Laminas\Mvc\Controller\ControllerManager; use Laminas\Mvc\MvcEvent; -use Laminas\Router\ConfigProvider; +use Laminas\Router; use Laminas\Router\Http\Literal; use Laminas\Router\RouteMatch; -use Laminas\Router\RouterFactory; use Laminas\Router\SimpleRouteStack; use Laminas\ServiceManager\ServiceManager; use Laminas\Stdlib\ArrayUtils; @@ -32,9 +32,7 @@ use ReflectionProperty; use stdClass; -use function array_shift; use function array_values; -use function is_array; use function sprintf; use function var_export; @@ -50,12 +48,8 @@ class ApplicationTest extends TestCase public function setUp(): void { - $serviceConfig = ArrayUtils::merge( - ArrayUtils::merge( - (new \Laminas\Mvc\ConfigProvider())->getDependencies(), - (new ConfigProvider())->getDependencyConfig(), - ), - [ + $testConfig = [ + 'dependencies' => [ 'invokables' => [ 'Request' => Request::class, 'Response' => Response::class, @@ -63,15 +57,22 @@ public function setUp(): void 'SendResponseListener' => MockSendResponseListener::class, 'BootstrapListener' => StubBootstrapListener::class, ], - 'factories' => [ - 'Router' => RouterFactory::class, - ], 'services' => [ 'config' => [], ], - ] + ], + ]; + + $config = ArrayUtils::merge( + ArrayUtils::merge( + (new ConfigProvider())(), + (new Router\ConfigProvider())(), + ), + $testConfig ); - $this->serviceManager = new ServiceManager($serviceConfig); + $config['dependencies']['services']['config'] = $config; + + $this->serviceManager = new ServiceManager($config['dependencies']); $this->serviceManager->setAllowOverride(true); $this->application = $this->serviceManager->get('Application'); } @@ -130,9 +131,9 @@ private function getIdentifiersFromSharedEventManager(SharedEventManager $events } /** - * @dataProvider bootstrapRegistersListenersProvider + * @dataProvider defaultApplicationListenersProvider */ - public function testBootstrapRegistersListeners(string $listenerServiceName, string $event, string $method): void + public function testHasRegisteredDefaultListeners(string $listenerServiceName, string $event, string $method): void { $listenerService = $this->serviceManager->get($listenerServiceName); $this->application->bootstrap(); @@ -142,7 +143,7 @@ public function testBootstrapRegistersListeners(string $listenerServiceName, str $this->assertContains([$listenerService, $method], $listeners); } - public function bootstrapRegistersListenersProvider(): array + public function defaultApplicationListenersProvider(): array { // @codingStandardsIgnoreStart // [ Service Name, Event, Method, isCustom ] @@ -156,34 +157,6 @@ public function bootstrapRegistersListenersProvider(): array // @codingStandardsIgnoreEnd } - public function testBootstrapAlwaysRegistersDefaultListeners(): void - { - $r = new ReflectionProperty($this->application, 'defaultListeners'); - $r->setAccessible(true); - $defaultListenersNames = $r->getValue($this->application); - $defaultListeners = []; - foreach ($defaultListenersNames as $defaultListenerName) { - $defaultListeners[] = $this->serviceManager->get($defaultListenerName); - } - - $this->application->bootstrap(); - $eventManager = $this->application->getEventManager(); - - $registeredListeners = []; - foreach ($this->getEventsFromEventManager($eventManager) as $event) { - foreach ($this->getListenersForEvent($event, $eventManager) as $listener) { - if (is_array($listener)) { - $listener = array_shift($listener); - } - $registeredListeners[] = $listener; - } - } - - foreach ($defaultListeners as $defaultListener) { - $this->assertContains($defaultListener, $registeredListeners); - } - } - public function testBootstrapRegistersConfiguredMvcEvent(): void { $this->assertNull($this->application->getMvcEvent());