Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[2.1] Module class map cache #2086

Merged
merged 6 commits into from

5 participants

@coss

Adds the ablity to cache the module class map.

'module_map_cache_enabled' => true,
'module_map_cache_key'     => 'some key',

The ModuleAutoloader now longer throws a build-in exception but Exception\InvalidArgumentException.

coss added some commits
@coss coss Added module class map cache ability.
- ModuleAutoloader uses now Exception\InvalidArgumentException instead of the built-in InvalidArgumentException
c7c5591
@coss coss Renamed callback method and fixed API docblock 530017a
@travisbot

This pull request passes (merged 530017a into f30ec3f).

@travisbot

This pull request passes (merged 983101d into f30ec3f).

@weierophinney

Assigned to 2.1. Also, you'll need to rebase, as the top-level test directory was finally renamed to "ZendTest".

@coss

Should I PR the ModuleAutoloader exception fix separately so it can be fixed before 2.1?

@Maks3w
Collaborator

Hi,

We have renamed the folder for tests from Zend to ZendTest.

Can you rebase your PR to catch this change?

Thanks in advance.

@prolic prolic commented on the diff
...d/ModuleManager/Listener/DefaultListenerAggregate.php
((5 lines not shown))
// 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(new ModuleLoaderListener($options));
@prolic
prolic added a note

You forgot the first parameter!

@coss
coss added a note

Oh, thanks. Not only that but more importantly the priority.

@coss
coss added a note

Oh, no, ModuleLoaderListener implements ListenerAggregateInterface. The listener takes care of attaching it to the right event.

@prolic
prolic added a note

Yes, sorry, my fault! Good job! ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@coss coss referenced this pull request from a commit in coss/zf2-documentation
@coss coss Added module class map cache option sample (zendframework/zf2#2086) a453d72
@coss

The build passes. It is a random travis error; see error and real test

@weierophinney weierophinney commented on the diff
library/Zend/ModuleManager/Listener/ConfigListener.php
@@ -386,18 +390,4 @@ protected function getCachedConfig()
{
return include $this->getOptions()->getConfigCacheFile();
}
-
- /**
- * @return ConfigListener
- */
- protected function updateCache()
@weierophinney Owner

Why is this method removed?

@weierophinney Owner

Never mind -- I see it was moved to the listener.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@weierophinney weierophinney commented on the diff
library/Zend/ModuleManager/Listener/ConfigListener.php
@@ -171,8 +171,12 @@ public function onLoadModulesPost(ModuleEvent $e)
}
// If enabled, update the config cache
- if ($this->getOptions()->getConfigCacheEnabled()) {
- $this->updateCache();
@weierophinney Owner

Why is this functionality removed?

@weierophinney Owner

Never mind -- I see it was moved to the listener.

@coss
coss added a note

Yeah, the if statement was kinda redundant, so I removed it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@weierophinney weierophinney merged commit 0314584 into zendframework:master
@weierophinney

Merged -- please write up some docs on the feature, now, please! :)

@Maks3w Maks3w referenced this pull request in zendframework/zf2-documentation
Closed

[2.1] Module class map cache option samples #240

@ghost Unknown referenced this pull request from a commit
@weierophinney weierophinney Merge branch 'feature/module-class-map-cache' of https://github.com/c…
…oss/zf2 into feature/module-class-map

PR #2086
be6f118
@weierophinney weierophinney referenced this pull request from a commit in zendframework/zend-loader
@weierophinney weierophinney Merge branch 'feature/module-class-map-cache' of https://github.com/c…
…oss/zf2 into feature/module-class-map

PR zendframework/zf2#2086
b4fd812
@weierophinney weierophinney referenced this pull request from a commit in zendframework/zend-modulemanager
@weierophinney weierophinney Merge branch 'feature/module-class-map-cache' of https://github.com/c…
…oss/zf2 into feature/module-class-map

PR zendframework/zf2#2086
dcfa8ab
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 2, 2012
  1. @coss

    Added module class map cache ability.

    coss authored
    - ModuleAutoloader uses now Exception\InvalidArgumentException instead of the built-in InvalidArgumentException
  2. @coss
  3. @coss
Commits on Sep 5, 2012
  1. @coss
Commits on Sep 8, 2012
  1. @coss
Commits on Sep 13, 2012
  1. @coss
This page is out of date. Refresh to see the latest.
View
34 library/Zend/Loader/ModuleAutoloader.php
@@ -94,6 +94,29 @@ public function setOptions($options)
}
/**
+ * Retrieves the class map for all loaded modules.
+ *
+ * @return array
+ */
+ public function getModuleClassMap()
+ {
+ return $this->moduleClassMap;
+ }
+
+ /**
+ * Sets the class map used to speed up the module autoloading.
+ *
+ * @param array $classmap
+ * @return ModuleLoader
+ */
+ public function setModuleClassMap(array $classmap)
+ {
+ $this->moduleClassMap = $classmap;
+
+ return $this;
+ }
+
+ /**
* Autoload a class
*
* @param $class
@@ -108,6 +131,11 @@ public function autoload($class)
return false;
}
+ if (isset($this->moduleClassMap[$class])) {
+ require_once $this->moduleClassMap[$class];
+ return $class;
+ }
+
$moduleName = substr($class, 0, -7);
if (isset($this->explicitPaths[$moduleName])) {
$classLoaded = $this->loadModuleFromDir($this->explicitPaths[$moduleName], $class);
@@ -267,7 +295,8 @@ public function unregister()
public function registerPaths($paths)
{
if (!is_array($paths) && !$paths instanceof Traversable) {
- throw new \InvalidArgumentException(
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php';
+ throw new Exception\InvalidArgumentException(
'Parameter to \\Zend\\Loader\\ModuleAutoloader\'s '
. 'registerPaths method must be an array or '
. 'implement the \\Traversable interface'
@@ -295,7 +324,8 @@ public function registerPaths($paths)
public function registerPath($path, $moduleName = false)
{
if (!is_string($path)) {
- throw new \InvalidArgumentException(sprintf(
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php';
+ throw new Exception\InvalidArgumentException(sprintf(
'Invalid path provided; must be a string, received %s',
gettype($path)
));
View
22 library/Zend/ModuleManager/Listener/ConfigListener.php
@@ -171,8 +171,12 @@ public function onLoadModulesPost(ModuleEvent $e)
}
// If enabled, update the config cache
- if ($this->getOptions()->getConfigCacheEnabled()) {
- $this->updateCache();
@weierophinney Owner

Why is this functionality removed?

@weierophinney Owner

Never mind -- I see it was moved to the listener.

@coss
coss added a note

Yeah, the if statement was kinda redundant, so I removed it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if (
+ $this->getOptions()->getConfigCacheEnabled()
+ && false === $this->skipConfig
+ ) {
+ $configFile = $this->getOptions()->getConfigCacheFile();
+ $this->writeArrayToFile($configFile, $this->getMergedConfig(false));
}
return $this;
@@ -386,18 +390,4 @@ protected function getCachedConfig()
{
return include $this->getOptions()->getConfigCacheFile();
}
-
- /**
- * @return ConfigListener
- */
- protected function updateCache()
@weierophinney Owner

Why is this method removed?

@weierophinney Owner

Never mind -- I see it was moved to the listener.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
- {
- if (($this->getOptions()->getConfigCacheEnabled())
- && (false === $this->skipConfig)
- ) {
- $configFile = $this->getOptions()->getConfigCacheFile();
- $this->writeArrayToFile($configFile, $this->getMergedConfig(false));
- }
- return $this;
- }
}
View
4 library/Zend/ModuleManager/Listener/DefaultListenerAggregate.php
@@ -12,7 +12,6 @@
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
-use Zend\Loader\ModuleAutoloader;
use Zend\ModuleManager\ModuleEvent;
use Zend\Stdlib\CallbackHandler;
@@ -47,10 +46,9 @@ public function attach(EventManagerInterface $events)
$options = $this->getOptions();
$configListener = $this->getConfigListener();
$locatorRegistrationListener = new LocatorRegistrationListener($options);
- $moduleAutoloader = new ModuleAutoloader($options->getModulePaths());
// 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(new ModuleLoaderListener($options));
@prolic
prolic added a note

You forgot the first parameter!

@coss
coss added a note

Oh, thanks. Not only that but more importantly the priority.

@coss
coss added a note

Oh, no, ModuleLoaderListener implements ListenerAggregateInterface. The listener takes care of attaching it to the right event.

@prolic
prolic added a note

Yes, sorry, my fault! Good job! ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
$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);
View
64 library/Zend/ModuleManager/Listener/ListenerOptions.php
@@ -58,6 +58,16 @@ class ListenerOptions extends AbstractOptions
protected $cacheDir;
/**
+ * @var string
+ */
+ protected $moduleMapCacheEnabled = false;
+
+ /**
+ * @var string
+ */
+ protected $moduleMapCacheKey;
+
+ /**
* Get an array of paths where modules reside
*
* @return array
@@ -262,6 +272,60 @@ public function setCacheDir($cacheDir)
}
/**
+ * Check if the module class map cache is enabled
+ *
+ * @return bool
+ */
+ public function getModuleMapCacheEnabled()
+ {
+ return $this->moduleMapCacheEnabled;
+ }
+
+ /**
+ * Set if the module class map cache should be enabled or not
+ *
+ * @param bool $enabled
+ * @return ListenerOptions
+ */
+ public function setModuleMapCacheEnabled($enabled)
+ {
+ $this->moduleMapCacheEnabled = (bool) $enabled;
+ return $this;
+ }
+
+ /**
+ * Get key used to create the cache file name
+ *
+ * @return string
+ */
+ public function getModuleMapCacheKey()
+ {
+ return (string) $this->moduleMapCacheKey;
+ }
+
+ /**
+ * Set key used to create the cache file name
+ *
+ * @param string $moduleMapCacheKey the value to be set
+ * @return ListenerOptions
+ */
+ public function setModuleMapCacheKey($moduleMapCacheKey)
+ {
+ $this->moduleMapCacheKey = $moduleMapCacheKey;
+ return $this;
+ }
+
+ /**
+ * Get the path to the module class map cache
+ *
+ * @return string
+ */
+ public function getModuleMapCacheFile()
+ {
+ return $this->getCacheDir() . '/module-classmap-cache.'.$this->getModuleMapCacheKey().'.php';
+ }
+
+ /**
* Normalize a path for insertion in the stack
*
* @param string $path
View
6 library/Zend/ModuleManager/Listener/LocatorRegistrationListener.php
@@ -54,14 +54,14 @@ public function onLoadModule(ModuleEvent $e)
}
/**
- * loadModulesPost
+ * loadModules
*
* Once all the modules are loaded, loop
*
* @param Event $e
* @return void
*/
- public function onLoadModulesPost(Event $e)
+ public function onLoadModules(Event $e)
{
$moduleManager = $e->getTarget();
$events = $moduleManager->getEventManager()->getSharedManager();
@@ -117,7 +117,7 @@ public function onBootstrap(Event $e)
public function attach(EventManagerInterface $events)
{
$this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, array($this, 'onLoadModule'));
- $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onLoadModulesPost'), -1000);
+ $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($this, 'onLoadModules'), -1000);
return $this;
}
View
140 library/Zend/ModuleManager/Listener/ModuleLoaderListener.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_ModuleManager
+ */
+
+namespace Zend\ModuleManager\Listener;
+
+use Zend\Loader\ModuleAutoloader;
+use Zend\ModuleManager\ModuleEvent;
+use Zend\EventManager\EventManagerInterface;
+use Zend\EventManager\ListenerAggregateInterface;
+
+/**
+ * Module loader listener
+ *
+ * @category Zend
+ * @package Zend_ModuleManager
+ * @subpackage Listener
+ */
+class ModuleLoaderListener extends AbstractListener implements ListenerAggregateInterface
+{
+ /**
+ * @var array
+ */
+ protected $moduleLoader;
+
+ /**
+ * @var bool
+ */
+ protected $generateCache;
+
+ /**
+ * @var array
+ */
+ protected $listeners = array();
+
+ /**
+ * Constructor.
+ *
+ * Creates an instance of the ModuleAutoloader and injects the module paths
+ * into it.
+ *
+ * @param ListenerOptions $options
+ */
+ public function __construct(ListenerOptions $options = null)
+ {
+ parent::__construct($options);
+
+ $this->generateCache = $this->options->getModuleMapCacheEnabled();
+ $this->moduleLoader = new ModuleAutoloader($this->options->getModulePaths());
+
+ if ($this->hasCachedClassMap()) {
+ $this->generateCache = false;
+ $this->moduleLoader->setModuleClassMap($this->getCachedConfig());
+ }
+ }
+
+ /**
+ * Attach one or more listeners
+ *
+ * @param EventManagerInterface $events
+ * @return LocatorRegistrationListener
+ */
+ public function attach(EventManagerInterface $events)
+ {
+ $this->listeners[] = $events->attach(
+ ModuleEvent::EVENT_LOAD_MODULES,
+ array($this->moduleLoader, 'register'),
+ 9000
+ );
+
+ if ($this->generateCache) {
+ $this->listeners[] = $events->attach(
+ ModuleEvent::EVENT_LOAD_MODULES_POST,
+ array($this, 'onLoadModulesPost')
+ );
+ }
+
+ return $this;
+ }
+
+ /**
+ * Detach all previously attached listeners
+ *
+ * @param EventManagerInterface $events
+ * @return void
+ */
+ public function detach(EventManagerInterface $events)
+ {
+ foreach ($this->listeners as $key => $listener) {
+ if ($events->detach($listener)) {
+ unset($this->listeners[$key]);
+ }
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ protected function hasCachedClassMap()
+ {
+ if (
+ $this->options->getModuleMapCacheEnabled()
+ && file_exists($this->options->getModuleMapCacheFile())
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ protected function getCachedConfig()
+ {
+ return include $this->options->getModuleMapCacheFile();
+ }
+
+ /**
+ * loadModulesPost
+ *
+ * Unregisters the ModuleLoader and generates the module class map cache.
+ *
+ * @param ModuleEvent $e
+ */
+ public function onLoadModulesPost(ModuleEvent $event)
+ {
+ $this->moduleLoader->unregister();
+ $this->writeArrayToFile(
+ $this->options->getModuleMapCacheFile(),
+ $this->moduleLoader->getModuleClassMap()
+ );
+ }
+}
View
12 tests/ZendTest/Loader/ModuleAutoloaderTest.php
@@ -197,4 +197,16 @@ public function testCanLoadModulesFromExplicitLocation()
$this->assertTrue(class_exists('PharModuleExplicit\Module'));
}
+ public function testCanLoadModulesFromClassMap()
+ {
+ $loader = new ModuleAutoloader();
+ $loader->setModuleClassMap(array(
+ 'BarModule\Module' => __DIR__ . '/_files/BarModule/Module.php',
+ 'PharModuleMap\Module' => __DIR__ . '/_files/PharModuleMap.phar',
+ ));
+ $loader->register();
+
+ $this->assertTrue(class_exists('BarModule\Module'));
+ $this->assertTrue(class_exists('PharModuleMap\Module'));
+ }
}
View
15 tests/ZendTest/Loader/_files/BarModule/Module.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Loader
+ */
+
+namespace BarModule;
+
+class Module
+{
+}
View
BIN  tests/ZendTest/Loader/_files/PharModuleMap.phar
Binary file not shown
View
1  tests/ZendTest/Loader/_files/_buildPhars.php
@@ -4,6 +4,7 @@
// Executable
// .phar
buildModulePhar('PharModule');
+buildModulePhar('PharModuleMap');
// .phar.gz
buildModulePhar('PharModuleGz', Phar::PHAR, Phar::GZ);
// .phar.bz2
View
96 tests/ZendTest/ModuleManager/Listener/ModuleLoaderListenerTest.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_ModuleManager
+ */
+
+namespace ZendTest\ModuleManager\Listener;
+
+use ArrayObject;
+use InvalidArgumentException;
+use PHPUnit_Framework_TestCase as TestCase;
+use Zend\ModuleManager\Listener\ModuleResolverListener;
+use Zend\ModuleManager\Listener\ModuleLoaderListener;
+use Zend\ModuleManager\Listener\ListenerOptions;
+use Zend\ModuleManager\ModuleManager;
+use Zend\ModuleManager\ModuleEvent;
+
+class ModuleLoaderListenerTest extends TestCase
+{
+ public function setUp()
+ {
+ $this->tmpdir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'zend_module_cache_dir';
+ @mkdir($this->tmpdir);
+
+ $this->moduleManager = new ModuleManager(array());
+ $this->moduleManager->getEventManager()->attach('loadModule.resolve', new ModuleResolverListener, 1000);
+ }
+
+ public function tearDown()
+ {
+ $file = glob($this->tmpdir . DIRECTORY_SEPARATOR . '*');
+ @unlink($file[0]); // change this if there's ever > 1 file
+ @rmdir($this->tmpdir);
+ }
+
+ public function testModuleLoaderListenerFunctionsAsAggregateListenerEnabledCache()
+ {
+ $options = new ListenerOptions(array(
+ 'cache_dir' => $this->tmpdir,
+ 'module_map_cache_enabled' => true,
+ 'module_map_cache_key' => 'foo',
+ ));
+
+ $moduleLoaderListener = new ModuleLoaderListener($options);
+
+ $moduleManager = $this->moduleManager;
+ $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
+ $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
+
+ $moduleLoaderListener->attach($moduleManager->getEventManager());
+ $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
+ $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
+ }
+
+ public function testModuleLoaderListenerFunctionsAsAggregateListenerDisabledCache()
+ {
+ $options = new ListenerOptions(array(
+ 'cache_dir' => $this->tmpdir,
+ ));
+
+ $moduleLoaderListener = new ModuleLoaderListener($options);
+
+ $moduleManager = $this->moduleManager;
+ $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
+ $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
+
+ $moduleLoaderListener->attach($moduleManager->getEventManager());
+ $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
+ $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
+ }
+
+ public function testModuleLoaderListenerFunctionsAsAggregateListenerHasCache()
+ {
+ $options = new ListenerOptions(array(
+ 'cache_dir' => $this->tmpdir,
+ 'module_map_cache_key' => 'foo',
+ 'module_map_cache_enabled' => true,
+ ));
+
+ file_put_contents($options->getModuleMapCacheFile(), '<?php return array();');
+
+ $moduleLoaderListener = new ModuleLoaderListener($options);
+
+ $moduleManager = $this->moduleManager;
+ $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
+ $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
+
+ $moduleLoaderListener->attach($moduleManager->getEventManager());
+ $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
+ $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
+ }
+}
Something went wrong with that request. Please try again.