From b72ac9e8900356fa01c7c3a71cecad380a682ca0 Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Tue, 3 Jul 2012 14:27:03 -0700 Subject: [PATCH 1/9] Add static init() to Zend\Mvc\Application Also no need to md5() the service manager keys in ServiceListener. --- src/Listener/ServiceListener.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Listener/ServiceListener.php b/src/Listener/ServiceListener.php index d5850a3..4889e40 100644 --- a/src/Listener/ServiceListener.php +++ b/src/Listener/ServiceListener.php @@ -71,13 +71,13 @@ public function __construct(ServiceManager $serviceManager) /** * @param string $key - * @param ServiceManager $serviceManager + * @param ServiceManager|string $serviceManager * @return ServiceListener */ public function addServiceManager($serviceManager, $key, $moduleInterface, $method) { if (is_string($serviceManager)) { - $smKey = md5($serviceManager); + $smKey = $serviceManager; } elseif ($serviceManager instanceof ServiceManager) { $smKey = spl_object_hash($serviceManager); } else { From cc6fa3f717aff995254a1664508485773917d9c4 Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Tue, 3 Jul 2012 15:52:45 -0700 Subject: [PATCH 2/9] Fix exception message in ServiceListener --- src/Listener/ServiceListener.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Listener/ServiceListener.php b/src/Listener/ServiceListener.php index 4889e40..413e17b 100644 --- a/src/Listener/ServiceListener.php +++ b/src/Listener/ServiceListener.php @@ -237,9 +237,8 @@ protected function serviceConfigurationToArray($config) if (!$config instanceof ServiceConfiguration) { throw new Exception\RuntimeException(sprintf( - 'Invalid service manager configuration class provided; received "%s", expected class implementing %s', - $class, - 'Zend\ServiceManager\ConfigurationInterface' + 'Invalid service manager configuration class provided; received "%s", expected an instance of Zend\ServiceManager\Configuration', + $class )); } From 658ba5dcfb4cad12c62320833d6bf16b1f3c4920 Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Wed, 4 Jul 2012 06:13:41 -0700 Subject: [PATCH 3/9] Refactor ConfigListener to track value sources This will enable us to provide useful debugging tools in regards to config merging. --- src/Listener/ConfigListener.php | 178 ++++++++++++++++---------------- 1 file changed, 87 insertions(+), 91 deletions(-) diff --git a/src/Listener/ConfigListener.php b/src/Listener/ConfigListener.php index 23c906c..dfb1e98 100644 --- a/src/Listener/ConfigListener.php +++ b/src/Listener/ConfigListener.php @@ -22,23 +22,28 @@ /** * Config listener - * + * * @category Zend * @package Zend_ModuleManager * @subpackage Listener */ -class ConfigListener extends AbstractListener implements - ConfigMergerInterface, +class ConfigListener extends AbstractListener implements + ConfigMergerInterface, ListenerAggregateInterface { - const STATIC_PATH = 'static_path'; - const GLOB_PATH = 'glob_path'; + const STATIC_PATH = 'static_path'; + const GLOB_PATH = 'glob_path'; /** * @var array */ protected $listeners = array(); + /** + * @var array + */ + protected $configs = array(); + /** * @var array */ @@ -95,9 +100,15 @@ public function __invoke(ModuleEvent $e) */ public function attach(EventManagerInterface $events) { - $this->listeners[] = $events->attach('loadModule', array($this, 'loadModule'), 1000); $this->listeners[] = $events->attach('loadModules.pre', array($this, 'loadModulesPre'), 9000); + + if ($this->skipConfig) { + return $this; + } + + $this->listeners[] = $events->attach('loadModule', array($this, 'loadModule'), 1000); $this->listeners[] = $events->attach('loadModules.post', array($this, 'loadModulesPost'), 9000); + return $this; } @@ -110,6 +121,7 @@ public function attach(EventManagerInterface $events) public function loadModulesPre(ModuleEvent $e) { $e->setConfigListener($this); + return $this; } @@ -121,32 +133,46 @@ public function loadModulesPre(ModuleEvent $e) */ public function loadModule(ModuleEvent $e) { - if (true === $this->skipConfig) { - return; - } $module = $e->getParam('module'); - if (is_callable(array($module, 'getConfig'))) { - $this->mergeModuleConfig($module); + + if (!$module instanceof ConfigProviderInterface + && !is_callable(array($module, 'getConfig')) + ) { + return $this; } + + $config = $module->getConfig(); + $this->addConfig($e->getModuleName(), $config); + return $this; } /** * Merge all config files matched by the given glob()s * - * This should really only be called by the module manager. + * This is only attached if config is not cached. * * @param ModuleEvent $e * @return ConfigListener */ public function loadModulesPost(ModuleEvent $e) { - if (true === $this->skipConfig) { - return $this; - } + // Load the config files foreach ($this->paths as $path) { - $this->mergePath($path); + $this->addConfigByPath($path['path'], $path['type']); } + + // Merge all of the collected configs + $this->mergedConfig = array(); + foreach ($this->configs as $key => $config) { + $this->mergedConfig = ArrayUtils::merge($this->mergedConfig, $config); + } + + // If enabled, update the config cache + if ($this->getOptions()->getConfigCacheEnabled()) { + $this->updateCache(); + } + return $this; } @@ -197,28 +223,10 @@ public function setMergedConfig(array $config) return $this; } - /** - * Add a path of config files to merge after loading modules - * - * @param string $path - * @return ConfigListener - */ - protected function addConfigPath($path, $type) - { - if (!is_string($path)) { - throw new Exception\InvalidArgumentException( - sprintf('Parameter to %s::%s() must be a string; %s given.', - __CLASS__, __METHOD__, gettype($path)) - ); - } - $this->paths[] = array('type' => $type, 'path' => $path); - return $this; - } - /** * Add an array of glob paths of config files to merge after loading modules * - * @param mixed $globPaths + * @param array|Traversable $globPaths * @return ConfigListener */ public function addConfigGlobPaths($globPaths) @@ -242,12 +250,12 @@ public function addConfigGlobPath($globPath) /** * Add an array of static paths of config files to merge after loading modules * - * @param mixed $staticPaths + * @param array|Traversable $staticPaths * @return ConfigListener */ public function addConfigStaticPaths($staticPaths) { - $this->addConfigPaths($staticPaths, self::STATIC_PATH); + $this->addConfigPaths($staticPaths, self::STATIC_PATH); return $this; } @@ -259,7 +267,7 @@ public function addConfigStaticPaths($staticPaths) */ public function addConfigStaticPath($staticPath) { - $this->addConfigPath($staticPath, self::STATIC_PATH); + $this->addConfigPath($staticPath, self::STATIC_PATH); return $this; } @@ -271,7 +279,7 @@ public function addConfigStaticPath($staticPath) */ protected function addConfigPaths($paths, $type) { - if ($paths instanceof Traversable) { + if ($paths instanceof Traversable) { $paths = ArrayUtils::iteratorToArray($paths); } @@ -290,82 +298,70 @@ protected function addConfigPaths($paths, $type) } /** - * Merge all config files matching a glob + * Add a path of config files to load and merge after loading modules * - * @param mixed $path + * @param string $path + * @param string $type * @return ConfigListener */ - protected function mergePath($path) + protected function addConfigPath($path, $type) { - switch ($path['type']) { - case self::STATIC_PATH: - $config = ConfigFactory::fromFile($path['path']); - break; - - case self::GLOB_PATH: - $config = ConfigFactory::fromFiles(Glob::glob($path['path'], Glob::GLOB_BRACE)); - break; - } - $this->mergeTraversableConfig($config); - if ($this->getOptions()->getConfigCacheEnabled()) { - $this->updateCache(); + if (!is_string($path)) { + throw new Exception\InvalidArgumentException( + sprintf('Parameter to %s::%s() must be a string; %s given.', + __CLASS__, __METHOD__, gettype($path)) + ); } + $this->paths[] = array('type' => $type, 'path' => $path); return $this; } - /** - * mergeModuleConfig - * - * @param mixed $module - * @return ConfigListener - */ - protected function mergeModuleConfig($module) + + + protected function addConfig($key, $config) { - if (false !== $this->skipConfig - || (!$module instanceof ConfigProviderInterface - && !is_callable(array($module, 'getConfig'))) - ) { - return $this; + if ($config instanceof Traversable) { + $config = ArrayUtils::iteratorToArray($config); } - $config = $module->getConfig(); - try { - $this->mergeTraversableConfig($config); - } catch (Exception\InvalidArgumentException $e) { - // Throw a more descriptive exception + if (!is_array($config)) { throw new Exception\InvalidArgumentException( - sprintf('getConfig() method of %s must be an array, ' + sprintf('Config being merged must be an array, ' . 'implement the \Traversable interface, or be an ' - . 'instance of Zend\Config\Config. %s given.', - get_class($module), gettype($config)) + . 'instance of Zend\Config\Config. %s given.', gettype($config)) ); } - if ($this->getOptions()->getConfigCacheEnabled()) { - $this->updateCache(); - } + $this->configs[$key] = $config; return $this; } /** - * @param $config - * @throws Exception\InvalidArgumentException - * @return void + * Given a path (glob or static), fetch the config and add it to the array + * of configs to merge. + * + * @param string $path + * @param string $type + * @return ConfigListener */ - protected function mergeTraversableConfig($config) + protected function addConfigByPath($path, $type) { - if ($config instanceof Traversable) { - $config = ArrayUtils::iteratorToArray($config); - } - if (!is_array($config)) { - throw new Exception\InvalidArgumentException( - sprintf('Config being merged must be an array, ' - . 'implement the \Traversable interface, or be an ' - . 'instance of Zend\Config\Config. %s given.', gettype($config)) - ); + switch ($type) { + case self::STATIC_PATH: + $this->addConfig($path, ConfigFactory::fromFile($path)); + break; + + case self::GLOB_PATH: + // We want to keep track of where each value came from so we don't + // use ConfigFactory::fromFiles() since it does merging internally. + foreach(Glob::glob($path, Glob::GLOB_BRACE) as $file) { + $this->addConfig($file, ConfigFactory::fromFile($file)); + } + break; } - $this->setMergedConfig(ArrayUtils::merge($this->mergedConfig, $config)); + + return $this; } /** From 604d80b97f8f4ad331dc010e605854b44476bd62 Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Wed, 4 Jul 2012 07:01:53 -0700 Subject: [PATCH 4/9] Update ConfigListener tests --- test/Listener/ConfigListenerTest.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/Listener/ConfigListenerTest.php b/test/Listener/ConfigListenerTest.php index 7140027..d9fce98 100644 --- a/test/Listener/ConfigListenerTest.php +++ b/test/Listener/ConfigListenerTest.php @@ -61,7 +61,7 @@ public function setUp() public function tearDown() { $file = glob($this->tmpdir . DIRECTORY_SEPARATOR . '*'); - @unlink($file[0]); // change this if there's ever > 1 file + @unlink($file[0]); // change this if there's ever > 1 file @rmdir($this->tmpdir); // Restore original autoloaders AutoloaderFactory::unregisterAutoloaders(); @@ -85,7 +85,7 @@ public function testMultipleConfigsAreMerged() $configListener = new ConfigListener; $moduleManager = $this->moduleManager; - $moduleManager->getEventManager()->attach('loadModule', $configListener); + $configListener->attach($moduleManager->getEventManager()); $moduleManager->setModules(array('SomeModule', 'ListenerTestModule')); $moduleManager->loadModules(); @@ -107,18 +107,18 @@ public function testCanCacheMergedConfig() $moduleManager = $this->moduleManager; $moduleManager->setModules(array('SomeModule', 'ListenerTestModule')); - $moduleManager->getEventManager()->attach('loadModule', $configListener); + $configListener->attach($moduleManager->getEventManager()); $moduleManager->loadModules(); // This should cache the config $modules = $moduleManager->getLoadedModules(); $this->assertTrue($modules['ListenerTestModule']->getConfigCalled); - // Now we check to make sure it uses the config and doesn't hit + // Now we check to make sure it uses the config and doesn't hit // the module objects getConfig() method(s) $moduleManager = new ModuleManager(array('SomeModule', 'ListenerTestModule')); $moduleManager->getEventManager()->attach('loadModule.resolve', new ModuleResolverListener, 1000); $configListener = new ConfigListener($options); - $moduleManager->getEventManager()->attach('loadModule', $configListener); + $configListener->attach($moduleManager->getEventManager()); $moduleManager->loadModules(); $modules = $moduleManager->getLoadedModules(); $this->assertFalse($modules['ListenerTestModule']->getConfigCalled); @@ -132,24 +132,24 @@ public function testBadConfigValueThrowsInvalidArgumentException() $moduleManager = $this->moduleManager; $moduleManager->setModules(array('BadConfigModule', 'SomeModule')); - $moduleManager->getEventManager()->attach('loadModule', $configListener); + $configListener->attach($moduleManager->getEventManager()); $moduleManager->loadModules(); } - + public function testBadGlobPathTrowsInvalidArgumentException() { $this->setExpectedException('InvalidArgumentException'); $configListener = new ConfigListener; $configListener->addConfigGlobPath(array('asd')); } - + public function testBadGlobPathArrayTrowsInvalidArgumentException() { $this->setExpectedException('InvalidArgumentException'); $configListener = new ConfigListener; $configListener->addConfigGlobPaths('asd'); } - + public function testBadStaticPathArrayTrowsInvalidArgumentException() { $this->setExpectedException('InvalidArgumentException'); @@ -165,7 +165,7 @@ public function testCanMergeConfigFromGlob() $moduleManager = $this->moduleManager; $moduleManager->setModules(array('SomeModule')); - $moduleManager->getEventManager()->attachAggregate($configListener); + $configListener->attach($moduleManager->getEventManager()); $moduleManager->loadModules(); $configObjectCheck = $configListener->getMergedConfig(); @@ -182,7 +182,7 @@ public function testCanMergeConfigFromGlob() $this->assertSame('loaded', $config['php']); $this->assertSame('loaded', $config['xml']); } - + public function testCanMergeConfigFromStaticPath() { $configListener = new ConfigListener; @@ -210,7 +210,7 @@ public function testCanMergeConfigFromStaticPath() $this->assertSame('loaded', $config['php']); $this->assertSame('loaded', $config['xml']); } - + public function testCanMergeConfigFromStaticPaths() { $configListener = new ConfigListener; @@ -276,7 +276,7 @@ public function testCanCacheMergedConfigFromGlob() $this->assertNotNull($configObjectFromGlob->xml); $this->assertSame($configObjectFromGlob->xml, $configObjectFromCache->xml); } - + public function testCanCacheMergedConfigFromStatic() { $options = new ListenerOptions(array( @@ -338,7 +338,7 @@ public function testCanMergeConfigFromArrayOfGlobs() $this->assertSame('loaded', $configObject->php); $this->assertSame('loaded', $configObject->xml); } - + public function testCanMergeConfigFromArrayOfStatic() { $configListener = new ConfigListener; From c446a96814175ac920a3f382989945111d713791 Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Wed, 4 Jul 2012 07:02:01 -0700 Subject: [PATCH 5/9] Update ServiceListener tests --- test/Listener/ServiceListenerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Listener/ServiceListenerTest.php b/test/Listener/ServiceListenerTest.php index 4482f01..502ee4f 100644 --- a/test/Listener/ServiceListenerTest.php +++ b/test/Listener/ServiceListenerTest.php @@ -46,7 +46,7 @@ class ServiceListenerTest extends TestCase public function setUp() { $this->services = new ServiceManager(); - $this->listener = new ServiceListener(); + $this->listener = new ServiceListener($this->services); $this->listener->addServiceManager($this->services, 'service_manager', 'Zend\ModuleManager\Feature\ServiceProviderInterface', 'getServiceConfiguration'); $this->event = new ModuleEvent(); $this->configListener = new ConfigListener(); @@ -97,7 +97,7 @@ public function getServiceConfiguration() public function assertServiceManagerIsConfigured() { - $this->listener->onLoadModulesPost($this->event); + $this->listener->onLoadModulesFinish($this->event); foreach ($this->getServiceConfiguration() as $prop => $expected) { if ($prop == 'invokables') { $prop = 'invokableClasses'; From 78cd91d3d8f228a371f017878723aa5fc8a4fd0c Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Wed, 4 Jul 2012 10:22:18 -0700 Subject: [PATCH 6/9] Allow modules to override service configuration --- src/Listener/ServiceListener.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Listener/ServiceListener.php b/src/Listener/ServiceListener.php index 413e17b..9071e3d 100644 --- a/src/Listener/ServiceListener.php +++ b/src/Listener/ServiceListener.php @@ -56,6 +56,11 @@ class ServiceListener implements ListenerAggregateInterface */ protected $defaultServiceManager; + /** + * @var array + */ + protected $defaultServiceConfiguration; + /** * @var array */ @@ -64,9 +69,10 @@ class ServiceListener implements ListenerAggregateInterface /** * @param ServiceManager $serviceManager */ - public function __construct(ServiceManager $serviceManager) + public function __construct(ServiceManager $serviceManager, $configuration = null) { $this->defaultServiceManager = $serviceManager; + $this->defaultServiceConfiguration = $configuration; } /** @@ -181,6 +187,10 @@ public function onLoadModulesFinish(ModuleEvent $e) $configListener = $e->getConfigListener(); $config = $configListener->getMergedConfig(false); + if ($this->defaultServiceConfiguration) { + $config = ArrayUtils::merge(array('service_manager' => $this->defaultServiceConfiguration), $config); + } + foreach ($this->serviceManagers as $key => $sm) { if (isset($config[$sm['config_key']]) From 43640055d7b20f8cac4ca4ea3862e7bfb38bc0c2 Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Wed, 4 Jul 2012 12:38:47 -0700 Subject: [PATCH 7/9] Add extra_config module listener option This is useful for unit testing. Edited Zend\View\Helper\Navigation\AbstractTest to use this. --- src/Listener/ConfigListener.php | 2 +- src/Listener/ListenerOptions.php | 62 +++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/Listener/ConfigListener.php b/src/Listener/ConfigListener.php index dfb1e98..bfc325a 100644 --- a/src/Listener/ConfigListener.php +++ b/src/Listener/ConfigListener.php @@ -163,7 +163,7 @@ public function loadModulesPost(ModuleEvent $e) } // Merge all of the collected configs - $this->mergedConfig = array(); + $this->mergedConfig = $this->getOptions()->getExtraConfig() ?: array(); foreach ($this->configs as $key => $config) { $this->mergedConfig = ArrayUtils::merge($this->mergedConfig, $config); } diff --git a/src/Listener/ListenerOptions.php b/src/Listener/ListenerOptions.php index b573644..761fbb8 100644 --- a/src/Listener/ListenerOptions.php +++ b/src/Listener/ListenerOptions.php @@ -15,7 +15,7 @@ /** * Listener options - * + * * @category Zend * @package Zend_ModuleManager * @subpackage Listener @@ -31,12 +31,17 @@ class ListenerOptions extends AbstractOptions * @var array */ protected $configGlobPaths = array(); - + /** * @var array */ protected $configStaticPaths = array(); + /** + * @var array + */ + protected $extraConfig = array(); + /** * @var bool */ @@ -83,18 +88,18 @@ public function setModulePaths($modulePaths) } /** - * Get the glob patterns to load additional config files - * + * Get the glob patterns to load additional config files + * * @return array */ public function getConfigGlobPaths() { return $this->configGlobPaths; } - + /** - * Get the static paths to load additional config files - * + * Get the static paths to load additional config files + * * @return array */ public function getConfigStaticPaths() @@ -104,8 +109,8 @@ public function getConfigStaticPaths() /** * Set the glob patterns to use for loading additional config files - * - * @param array $configGlobPaths + * + * @param array|Traversable $configGlobPaths * @return ListenerOptions */ public function setConfigGlobPaths($configGlobPaths) @@ -119,12 +124,13 @@ public function setConfigGlobPaths($configGlobPaths) ); } $this->configGlobPaths = $configGlobPaths; + return $this; } - + /** * Set the static paths to use for loading additional config files - * - * @param array $configStaticPaths + * + * @param array|Traversable $configStaticPaths * @return ListenerOptions */ public function setConfigStaticPaths($configStaticPaths) @@ -138,6 +144,38 @@ public function setConfigStaticPaths($configStaticPaths) ); } $this->configStaticPaths = $configStaticPaths; + return $this; + } + + /** + * Get any extra config to merge in. + * + * @return array|Traversable + */ + public function getExtraConfig() + { + return $this->extraConfig; + } + + /** + * Add some extra config array to the main config. This is mainly useful + * for unit testing purposes. + * + * @param array|Traversable $extraConfig + * @return ListenerOptions + */ + public function setExtraConfig($extraConfig) + { + if (!is_array($extraConfig) && !$extraConfig instanceof Traversable) { + throw new Exception\InvalidArgumentException( + sprintf('Argument passed to %s::%s() must be an array, ' + . 'implement the \Traversable interface, or be an ' + . 'instance of Zend\Config\Config. %s given.', + __CLASS__, __METHOD__, gettype($extraConfig)) + ); + } + $this->extraConfig = $extraConfig; + return $this; } /** From 8a17226874e52f538ddcf7e3560d15f1ef06359c Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Thu, 5 Jul 2012 02:42:13 -0700 Subject: [PATCH 8/9] Refactor ModuleManager events - Removes the loadModules.pre event - Adds a loadModules event - Use constants for event names to match Zend\Mvc - All work contained within listeners now Listeners that need to do things after modules are loaded, but do some work that modules should be able to assume is complete in loadModules.post should attach to the loadModules event with a negative priority. --- src/Listener/ConfigListener.php | 13 ++--- src/Listener/DefaultListenerAggregate.php | 17 +++--- src/Listener/LocatorRegistrationListener.php | 36 ++++++------- src/Listener/OnBootstrapListener.php | 2 +- src/Listener/ServiceListener.php | 6 +-- src/ModuleEvent.php | 8 +++ src/ModuleManager.php | 55 ++++++++++++++------ 7 files changed, 86 insertions(+), 51 deletions(-) diff --git a/src/Listener/ConfigListener.php b/src/Listener/ConfigListener.php index bfc325a..e18785e 100644 --- a/src/Listener/ConfigListener.php +++ b/src/Listener/ConfigListener.php @@ -100,14 +100,15 @@ public function __invoke(ModuleEvent $e) */ public function attach(EventManagerInterface $events) { - $this->listeners[] = $events->attach('loadModules.pre', array($this, 'loadModulesPre'), 9000); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onloadModulesPre'), 1000); if ($this->skipConfig) { + // We already have the config from cache, no need to collect or merge. return $this; } - $this->listeners[] = $events->attach('loadModule', array($this, 'loadModule'), 1000); - $this->listeners[] = $events->attach('loadModules.post', array($this, 'loadModulesPost'), 9000); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, array($this, 'onLoadModule')); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onLoadModulesPost'), -1000); return $this; } @@ -118,7 +119,7 @@ public function attach(EventManagerInterface $events) * @param ModuleEvent $e * @return ConfigListener */ - public function loadModulesPre(ModuleEvent $e) + public function onloadModulesPre(ModuleEvent $e) { $e->setConfigListener($this); @@ -131,7 +132,7 @@ public function loadModulesPre(ModuleEvent $e) * @param ModuleEvent $e * @return ConfigListener */ - public function loadModule(ModuleEvent $e) + public function onLoadModule(ModuleEvent $e) { $module = $e->getParam('module'); @@ -155,7 +156,7 @@ public function loadModule(ModuleEvent $e) * @param ModuleEvent $e * @return ConfigListener */ - public function loadModulesPost(ModuleEvent $e) + public function onLoadModulesPost(ModuleEvent $e) { // Load the config files foreach ($this->paths as $path) { diff --git a/src/Listener/DefaultListenerAggregate.php b/src/Listener/DefaultListenerAggregate.php index dd5459a..0404c3e 100644 --- a/src/Listener/DefaultListenerAggregate.php +++ b/src/Listener/DefaultListenerAggregate.php @@ -13,16 +13,17 @@ use Zend\EventManager\EventManagerInterface; use Zend\EventManager\ListenerAggregateInterface; use Zend\Loader\ModuleAutoloader; +use Zend\ModuleManager\ModuleEvent; use Zend\Stdlib\CallbackHandler; /** * Default listener aggregate - * + * * @category Zend * @package Zend_ModuleManager * @subpackage Listener */ -class DefaultListenerAggregate extends AbstractListener implements +class DefaultListenerAggregate extends AbstractListener implements ListenerAggregateInterface { /** @@ -48,11 +49,13 @@ public function attach(EventManagerInterface $events) $locatorRegistrationListener = new LocatorRegistrationListener($options); $moduleAutoloader = new ModuleAutoloader($options->getModulePaths()); - $this->listeners[] = $events->attach('loadModules.pre', array($moduleAutoloader, 'register'), 1000); - $this->listeners[] = $events->attach('loadModule.resolve', new ModuleResolverListener, 1000); - $this->listeners[] = $events->attach('loadModule', new AutoloaderListener($options), 2000); - $this->listeners[] = $events->attach('loadModule', new InitTrigger($options), 1000); - $this->listeners[] = $events->attach('loadModule', new OnBootstrapListener($options), 1000); + // High priority, we assume module autoloading (for FooNamespace\Module classes) should be available before anything else + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($moduleAutoloader, 'register'), 9000); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE_RESOLVE, new ModuleResolverListener); + // High priority, because most other loadModule listeners will assume the module's classes are available via autoloading + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new AutoloaderListener($options), 9000); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new InitTrigger($options)); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new OnBootstrapListener($options)); $this->listeners[] = $events->attach($locatorRegistrationListener); $this->listeners[] = $events->attach($configListener); return $this; diff --git a/src/Listener/LocatorRegistrationListener.php b/src/Listener/LocatorRegistrationListener.php index cd8f0d2..e57337c 100644 --- a/src/Listener/LocatorRegistrationListener.php +++ b/src/Listener/LocatorRegistrationListener.php @@ -18,12 +18,12 @@ /** * Locator registration listener - * + * * @category Zend * @package Zend_ModuleManager * @subpackage Listener */ -class LocatorRegistrationListener extends AbstractListener implements +class LocatorRegistrationListener extends AbstractListener implements ListenerAggregateInterface { /** @@ -37,15 +37,15 @@ class LocatorRegistrationListener extends AbstractListener implements protected $listeners = array(); /** - * loadModule + * loadModule * - * Check each loaded module to see if it implements LocatorRegistered. If it + * Check each loaded module to see if it implements LocatorRegistered. If it * does, we add it to an internal array for later. - * - * @param ModuleEvent $e + * + * @param ModuleEvent $e * @return void */ - public function loadModule(ModuleEvent $e) + public function onLoadModule(ModuleEvent $e) { if (!$e->getModule() instanceof LocatorRegisteredInterface) { return; @@ -54,14 +54,14 @@ public function loadModule(ModuleEvent $e) } /** - * loadModulesPost + * loadModulesPost + * + * Once all the modules are loaded, loop * - * Once all the modules are loaded, loop - * - * @param Event $e + * @param Event $e * @return void */ - public function loadModulesPost(Event $e) + public function onLoadModulesPost(Event $e) { $moduleManager = $e->getTarget(); $events = $moduleManager->getEventManager()->getSharedManager(); @@ -85,14 +85,14 @@ public function loadModulesPost(Event $e) } /** - * Bootstrap listener + * Bootstrap listener * - * This is ran during the MVC bootstrap event because it requires access to + * This is ran during the MVC bootstrap event because it requires access to * the DI container. * - * @TODO: Check the application / locator / etc a bit better to make sure + * @TODO: Check the application / locator / etc a bit better to make sure * the env looks how we're expecting it to? - * @param Event $e + * @param Event $e * @return void */ public function onBootstrap(Event $e) @@ -116,8 +116,8 @@ public function onBootstrap(Event $e) */ public function attach(EventManagerInterface $events) { - $this->listeners[] = $events->attach('loadModule', array($this, 'loadModule'), 1000); - $this->listeners[] = $events->attach('loadModules.post', array($this, 'loadModulesPost'), 9000); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, array($this, 'onLoadModule')); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onLoadModulesPost'), -1000); return $this; } diff --git a/src/Listener/OnBootstrapListener.php b/src/Listener/OnBootstrapListener.php index 1ff2dc1..48e7dd8 100644 --- a/src/Listener/OnBootstrapListener.php +++ b/src/Listener/OnBootstrapListener.php @@ -15,7 +15,7 @@ /** * Autoloader listener - * + * * @category Zend * @package Zend_ModuleManager * @subpackage Listener diff --git a/src/Listener/ServiceListener.php b/src/Listener/ServiceListener.php index 9071e3d..6edaac5 100644 --- a/src/Listener/ServiceListener.php +++ b/src/Listener/ServiceListener.php @@ -108,8 +108,8 @@ public function addServiceManager($serviceManager, $key, $moduleInterface, $meth */ public function attach(EventManagerInterface $events) { - $this->listeners[] = $events->attach('loadModule', array($this, 'onLoadModule'), 1500); - $this->listeners[] = $events->attach('loadModules.finish', array($this, 'onLoadModulesFinish'), 8500); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, array($this, 'onLoadModule')); + $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES_POST, array($this, 'onLoadModulesPost')); return $this; } @@ -182,7 +182,7 @@ public function onLoadModule(ModuleEvent $e) * @param ModuleEvent $e * @return void */ - public function onLoadModulesFinish(ModuleEvent $e) + public function onLoadModulesPost(ModuleEvent $e) { $configListener = $e->getConfigListener(); $config = $configListener->getMergedConfig(false); diff --git a/src/ModuleEvent.php b/src/ModuleEvent.php index deb1c0e..b4eceec 100644 --- a/src/ModuleEvent.php +++ b/src/ModuleEvent.php @@ -21,6 +21,14 @@ */ class ModuleEvent extends Event { + /** + * Module events triggered by eventmanager + */ + CONST EVENT_LOAD_MODULES = 'loadModules'; + CONST EVENT_LOAD_MODULE_RESOLVE = 'loadModule.resolve'; + CONST EVENT_LOAD_MODULE = 'loadModule'; + CONST EVENT_LOAD_MODULES_POST = 'loadModules.post'; + /** * Get the name of a given module * diff --git a/src/ModuleManager.php b/src/ModuleManager.php index d650db4..df20876 100644 --- a/src/ModuleManager.php +++ b/src/ModuleManager.php @@ -16,7 +16,7 @@ /** * Module manager - * + * * @category Zend * @package Zend_ModuleManager */ @@ -66,6 +66,19 @@ public function __construct($modules, EventManagerInterface $eventManager = null } } + public function onLoadModules() + { + if (true === $this->modulesAreLoaded) { + return $this; + } + + foreach ($this->getModules() as $moduleName) { + $this->loadModule($moduleName); + } + + $this->modulesAreLoaded = true; + } + /** * Load the provided modules. * @@ -79,17 +92,15 @@ public function loadModules() return $this; } - $this->getEventManager()->trigger(__FUNCTION__ . '.pre', $this, $this->getEvent()); - - foreach ($this->getModules() as $moduleName) { - $this->loadModule($moduleName); - } - - $this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, $this->getEvent()); + $this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULES, $this, $this->getEvent()); - $this->modulesAreLoaded = true; - - $this->getEventManager()->trigger(__FUNCTION__ . '.finish', $this, $this->getEvent()); + /** + * Having a dedicated .post event abstracts the complexity of priorities from the user. + * Users can attach to the .post event and be sure that important + * things like config merging are complete without having to worry if + * they set a low enough priority. + */ + $this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULES_POST, $this, $this->getEvent()); return $this; } @@ -111,7 +122,7 @@ public function loadModule($moduleName) $event = $this->getEvent(); $event->setModuleName($moduleName); - $result = $this->getEventManager()->trigger(__FUNCTION__ . '.resolve', $this, $event, function ($r) { + $result = $this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULE_RESOLVE, $this, $event, function ($r) { return (is_object($r)); }); @@ -125,7 +136,7 @@ public function loadModule($moduleName) } $event->setModule($module); - $this->getEventManager()->trigger(__FUNCTION__, $this, $event); + $this->getEventManager()->trigger(ModuleEvent::EVENT_LOAD_MODULE, $this, $event); $this->loadedModules[$moduleName] = $module; return $module; } @@ -145,9 +156,9 @@ public function getLoadedModules($loadModules = false) } /** - * Get an instance of a module class by the module name - * - * @param string $moduleName + * Get an instance of a module class by the module name + * + * @param string $moduleName * @return mixed */ public function getModule($moduleName) @@ -226,6 +237,7 @@ public function setEventManager(EventManagerInterface $events) 'module_manager', )); $this->events = $events; + $this->attachDefaultListeners(); return $this; } @@ -243,4 +255,15 @@ public function getEventManager() } return $this->events; } + + /** + * Register the default event listeners + * + * @return ModuleManager + */ + protected function attachDefaultListeners() + { + $events = $this->getEventManager(); + $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onLoadModules')); + } } From 0f738f8aa9896524fe74b4e993ae87c02eceb4c0 Mon Sep 17 00:00:00 2001 From: Evan Coury Date: Thu, 5 Jul 2012 03:25:07 -0700 Subject: [PATCH 9/9] Update ModuleManager tests for event changes --- test/Listener/ConfigListenerTest.php | 6 +++--- .../Listener/DefaultListenerAggregateTest.php | 19 ++++++++++--------- test/Listener/ServiceListenerTest.php | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/test/Listener/ConfigListenerTest.php b/test/Listener/ConfigListenerTest.php index d9fce98..1212534 100644 --- a/test/Listener/ConfigListenerTest.php +++ b/test/Listener/ConfigListenerTest.php @@ -386,12 +386,12 @@ public function testConfigListenerFunctionsAsAggregateListener() $configListener = new ConfigListener; $moduleManager = $this->moduleManager; - $this->assertEquals(1, count($moduleManager->getEventManager()->getEvents())); + $this->assertEquals(2, count($moduleManager->getEventManager()->getEvents())); $configListener->attach($moduleManager->getEventManager()); - $this->assertEquals(4, count($moduleManager->getEventManager()->getEvents())); + $this->assertEquals(3, count($moduleManager->getEventManager()->getEvents())); $configListener->detach($moduleManager->getEventManager()); - $this->assertEquals(1, count($moduleManager->getEventManager()->getEvents())); + $this->assertEquals(2, count($moduleManager->getEventManager()->getEvents())); } } diff --git a/test/Listener/DefaultListenerAggregateTest.php b/test/Listener/DefaultListenerAggregateTest.php index 9a759ed..b4f87d2 100644 --- a/test/Listener/DefaultListenerAggregateTest.php +++ b/test/Listener/DefaultListenerAggregateTest.php @@ -46,7 +46,7 @@ public function setUp() $this->includePath = get_include_path(); $this->defaultListeners = new DefaultListenerAggregate( - new ListenerOptions(array( + new ListenerOptions(array( 'module_paths' => array( realpath(__DIR__ . '/TestAsset'), ), @@ -80,9 +80,12 @@ public function testDefaultListenerAggregateCanAttachItself() $events = $moduleManager->getEventManager()->getEvents(); $expectedEvents = array( - 'loadModules.pre' => array( + 'loadModules' => array( 'Zend\Loader\ModuleAutoloader', - 'Zend\ModuleManager\Listener\ConfigListener', + 'config-pre' => 'Zend\ModuleManager\Listener\ConfigListener', + 'config-post' => 'Zend\ModuleManager\Listener\ConfigListener', + 'Zend\ModuleManager\Listener\LocatorRegistrationListener', + 'Zend\ModuleManager\ModuleManager', ), 'loadModule.resolve' => array( 'Zend\ModuleManager\Listener\ModuleResolverListener', @@ -94,10 +97,6 @@ public function testDefaultListenerAggregateCanAttachItself() 'Zend\ModuleManager\Listener\ConfigListener', 'Zend\ModuleManager\Listener\LocatorRegistrationListener', ), - 'loadModules.post' => array( - 'Zend\ModuleManager\Listener\ConfigListener', - 'Zend\ModuleManager\Listener\LocatorRegistrationListener', - ), ); foreach ($expectedEvents as $event => $expectedListeners) { $this->assertContains($event, $events); @@ -119,10 +118,12 @@ public function testDefaultListenerAggregateCanDetachItself() $listenerAggregate = new DefaultListenerAggregate; $moduleManager = new ModuleManager(array('ListenerTestModule')); + $this->assertEquals(1, count($moduleManager->getEventManager()->getEvents())); + $listenerAggregate->attach($moduleManager->getEventManager()); - $this->assertEquals(4, count($moduleManager->getEventManager()->getEvents())); + $this->assertEquals(3, count($moduleManager->getEventManager()->getEvents())); $listenerAggregate->detach($moduleManager->getEventManager()); - $this->assertEquals(0, count($moduleManager->getEventManager()->getEvents())); + $this->assertEquals(1, count($moduleManager->getEventManager()->getEvents())); } } diff --git a/test/Listener/ServiceListenerTest.php b/test/Listener/ServiceListenerTest.php index 502ee4f..3111731 100644 --- a/test/Listener/ServiceListenerTest.php +++ b/test/Listener/ServiceListenerTest.php @@ -97,7 +97,7 @@ public function getServiceConfiguration() public function assertServiceManagerIsConfigured() { - $this->listener->onLoadModulesFinish($this->event); + $this->listener->onLoadModulesPost($this->event); foreach ($this->getServiceConfiguration() as $prop => $expected) { if ($prop == 'invokables') { $prop = 'invokableClasses';