Skip to content
This repository
Browse code

Added module class map cache ability.

- ModuleAutoloader uses now Exception\InvalidArgumentException instead of the built-in InvalidArgumentException
  • Loading branch information...
commit c7c559127c7217fc1bd8d521cfbad07f11f9f851 1 parent f30ec3f
Eric Boh coss authored
34 library/Zend/Loader/ModuleAutoloader.php
@@ -95,6 +95,29 @@ public function setOptions($options)
95 95 }
96 96
97 97 /**
  98 + * Retrieves the class map for all loaded modules.
  99 + *
  100 + * @return array
  101 + */
  102 + public function getModuleClassMap()
  103 + {
  104 + return $this->moduleClassMap;
  105 + }
  106 +
  107 + /**
  108 + * Sets the class map used to speed up the module autoloading.
  109 + *
  110 + * @param array $classmap
  111 + * @return ModuleLoader
  112 + */
  113 + public function setModuleClassMap(array $classmap)
  114 + {
  115 + $this->moduleClassMap = $classmap;
  116 +
  117 + return $this;
  118 + }
  119 +
  120 + /**
98 121 * Autoload a class
99 122 *
100 123 * @param $class
@@ -109,6 +132,11 @@ public function autoload($class)
109 132 return false;
110 133 }
111 134
  135 + if (isset($this->moduleClassMap[$class])) {
  136 + require_once $this->moduleClassMap[$class];
  137 + return $class;
  138 + }
  139 +
112 140 $moduleName = substr($class, 0, -7);
113 141 if (isset($this->explicitPaths[$moduleName])) {
114 142 $classLoaded = $this->loadModuleFromDir($this->explicitPaths[$moduleName], $class);
@@ -268,7 +296,8 @@ public function unregister()
268 296 public function registerPaths($paths)
269 297 {
270 298 if (!is_array($paths) && !$paths instanceof Traversable) {
271   - throw new \InvalidArgumentException(
  299 + require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  300 + throw new Exception\InvalidArgumentException(
272 301 'Parameter to \\Zend\\Loader\\ModuleAutoloader\'s '
273 302 . 'registerPaths method must be an array or '
274 303 . 'implement the \\Traversable interface'
@@ -296,7 +325,8 @@ public function registerPaths($paths)
296 325 public function registerPath($path, $moduleName = false)
297 326 {
298 327 if (!is_string($path)) {
299   - throw new \InvalidArgumentException(sprintf(
  328 + require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  329 + throw new Exception\InvalidArgumentException(sprintf(
300 330 'Invalid path provided; must be a string, received %s',
301 331 gettype($path)
302 332 ));
22 library/Zend/ModuleManager/Listener/ConfigListener.php
@@ -171,8 +171,12 @@ public function onLoadModulesPost(ModuleEvent $e)
171 171 }
172 172
173 173 // If enabled, update the config cache
174   - if ($this->getOptions()->getConfigCacheEnabled()) {
175   - $this->updateCache();
  174 + if (
  175 + $this->getOptions()->getConfigCacheEnabled()
  176 + && false === $this->skipConfig
  177 + ) {
  178 + $configFile = $this->getOptions()->getConfigCacheFile();
  179 + $this->writeArrayToFile($configFile, $this->getMergedConfig(false));
176 180 }
177 181
178 182 return $this;
@@ -386,18 +390,4 @@ protected function getCachedConfig()
386 390 {
387 391 return include $this->getOptions()->getConfigCacheFile();
388 392 }
389   -
390   - /**
391   - * @return ConfigListener
392   - */
393   - protected function updateCache()
394   - {
395   - if (($this->getOptions()->getConfigCacheEnabled())
396   - && (false === $this->skipConfig)
397   - ) {
398   - $configFile = $this->getOptions()->getConfigCacheFile();
399   - $this->writeArrayToFile($configFile, $this->getMergedConfig(false));
400   - }
401   - return $this;
402   - }
403 393 }
4 library/Zend/ModuleManager/Listener/DefaultListenerAggregate.php
@@ -12,7 +12,6 @@
12 12
13 13 use Zend\EventManager\EventManagerInterface;
14 14 use Zend\EventManager\ListenerAggregateInterface;
15   -use Zend\Loader\ModuleAutoloader;
16 15 use Zend\ModuleManager\ModuleEvent;
17 16 use Zend\Stdlib\CallbackHandler;
18 17
@@ -47,10 +46,9 @@ public function attach(EventManagerInterface $events)
47 46 $options = $this->getOptions();
48 47 $configListener = $this->getConfigListener();
49 48 $locatorRegistrationListener = new LocatorRegistrationListener($options);
50   - $moduleAutoloader = new ModuleAutoloader($options->getModulePaths());
51 49
52 50 // High priority, we assume module autoloading (for FooNamespace\Module classes) should be available before anything else
53   - $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULES, array($moduleAutoloader, 'register'), 9000);
  51 + $this->listeners[] = $events->attach(new ModuleLoaderListener($options));
54 52 $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE_RESOLVE, new ModuleResolverListener);
55 53 // High priority, because most other loadModule listeners will assume the module's classes are available via autoloading
56 54 $this->listeners[] = $events->attach(ModuleEvent::EVENT_LOAD_MODULE, new AutoloaderListener($options), 9000);
64 library/Zend/ModuleManager/Listener/ListenerOptions.php
@@ -58,6 +58,16 @@ class ListenerOptions extends AbstractOptions
58 58 protected $cacheDir;
59 59
60 60 /**
  61 + * @var string
  62 + */
  63 + protected $moduleMapCacheEnabled = false;
  64 +
  65 + /**
  66 + * @var string
  67 + */
  68 + protected $moduleMapCacheKey;
  69 +
  70 + /**
61 71 * Get an array of paths where modules reside
62 72 *
63 73 * @return array
@@ -262,6 +272,60 @@ public function setCacheDir($cacheDir)
262 272 }
263 273
264 274 /**
  275 + * Check if the module class map cache is enabled
  276 + *
  277 + * @return bool
  278 + */
  279 + public function getModuleMapCacheEnabled()
  280 + {
  281 + return $this->moduleMapCacheEnabled;
  282 + }
  283 +
  284 + /**
  285 + * Set if the module class map cache should be enabled or not
  286 + *
  287 + * @param bool $enabled
  288 + * @return ListenerOptions
  289 + */
  290 + public function setModuleMapCacheEnabled($enabled)
  291 + {
  292 + $this->moduleMapCacheEnabled = (bool) $enabled;
  293 + return $this;
  294 + }
  295 +
  296 + /**
  297 + * Get key used to create the cache file name
  298 + *
  299 + * @return string
  300 + */
  301 + public function getModuleMapCacheKey()
  302 + {
  303 + return (string) $this->moduleMapCacheKey;
  304 + }
  305 +
  306 + /**
  307 + * Set key used to create the cache file name
  308 + *
  309 + * @param string $moduleMapCacheKey the value to be set
  310 + * @return ListenerOptions
  311 + */
  312 + public function setModuleMapCacheKey($moduleMapCacheKey)
  313 + {
  314 + $this->moduleMapCacheKey = $moduleMapCacheKey;
  315 + return $this;
  316 + }
  317 +
  318 + /**
  319 + * Get the path to the module class map cache
  320 + *
  321 + * @return string
  322 + */
  323 + public function getModuleMapCacheFile()
  324 + {
  325 + return $this->getCacheDir() . '/module-classmap-cache.'.$this->getModuleMapCacheKey().'.php';
  326 + }
  327 +
  328 + /**
265 329 * Normalize a path for insertion in the stack
266 330 *
267 331 * @param string $path
140 library/Zend/ModuleManager/Listener/ModuleLoaderListener.php
... ... @@ -0,0 +1,140 @@
  1 +<?php
  2 +/**
  3 + * Zend Framework (http://framework.zend.com/)
  4 + *
  5 + * @link http://github.com/zendframework/zf2 for the canonical source repository
  6 + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  7 + * @license http://framework.zend.com/license/new-bsd New BSD License
  8 + * @package Zend_ModuleManager
  9 + */
  10 +
  11 +namespace Zend\ModuleManager\Listener;
  12 +
  13 +use Zend\Loader\ModuleAutoloader;
  14 +use Zend\ModuleManager\ModuleEvent;
  15 +use Zend\EventManager\EventManagerInterface;
  16 +use Zend\EventManager\ListenerAggregateInterface;
  17 +
  18 +/**
  19 + * Module loader listener
  20 + *
  21 + * @category Zend
  22 + * @package Zend_ModuleManager
  23 + * @subpackage Listener
  24 + */
  25 +class ModuleLoaderListener extends AbstractListener implements ListenerAggregateInterface
  26 +{
  27 + /**
  28 + * @var array
  29 + */
  30 + protected $moduleLoader;
  31 +
  32 + /**
  33 + * @var bool
  34 + */
  35 + protected $generateCache;
  36 +
  37 + /**
  38 + * @var array
  39 + */
  40 + protected $listeners = array();
  41 +
  42 + /**
  43 + * Constructor.
  44 + *
  45 + * Creates an instance of the ModuleAutoloader and injects the module paths
  46 + * into it.
  47 + *
  48 + * @param ListenerOptions $options
  49 + */
  50 + public function __construct(ListenerOptions $options = null)
  51 + {
  52 + parent::__construct($options);
  53 +
  54 + $this->generateCache = $this->options->getModuleMapCacheEnabled();
  55 + $this->moduleLoader = new ModuleAutoloader($this->options->getModulePaths());
  56 +
  57 + if ($this->hasCachedClassMap()) {
  58 + $this->generateCache = false;
  59 + $this->moduleLoader->setModuleClassMap($this->getCachedConfig());
  60 + }
  61 + }
  62 +
  63 + /**
  64 + * Attach one or more listeners
  65 + *
  66 + * @param EventManagerInterface $events
  67 + * @return LocatorRegistrationListener
  68 + */
  69 + public function attach(EventManagerInterface $events)
  70 + {
  71 + $this->listeners[] = $events->attach(
  72 + ModuleEvent::EVENT_LOAD_MODULES,
  73 + array($this->moduleLoader, 'register'),
  74 + 9000
  75 + );
  76 +
  77 + if ($this->generateCache) {
  78 + $this->listeners[] = $events->attach(
  79 + ModuleEvent::EVENT_LOAD_MODULES_POST,
  80 + array($this, 'onLoadModulesPost')
  81 + );
  82 + }
  83 +
  84 + return $this;
  85 + }
  86 +
  87 + /**
  88 + * Detach all previously attached listeners
  89 + *
  90 + * @param EventManagerInterface $events
  91 + * @return void
  92 + */
  93 + public function detach(EventManagerInterface $events)
  94 + {
  95 + foreach ($this->listeners as $key => $listener) {
  96 + if ($events->detach($listener)) {
  97 + unset($this->listeners[$key]);
  98 + }
  99 + }
  100 + }
  101 +
  102 + /**
  103 + * @return bool
  104 + */
  105 + protected function hasCachedClassMap()
  106 + {
  107 + if (
  108 + $this->options->getModuleMapCacheEnabled()
  109 + && file_exists($this->options->getConfigCacheFile())
  110 + ) {
  111 + return true;
  112 + }
  113 +
  114 + return false;
  115 + }
  116 +
  117 + /**
  118 + * @return array
  119 + */
  120 + protected function getCachedConfig()
  121 + {
  122 + return include $this->options->getModuleMapCacheFile();
  123 + }
  124 +
  125 + /**
  126 + * loadModulesPost
  127 + *
  128 + * Unregisters the ModuleLoader and generates the module class map cache.
  129 + *
  130 + * @param ModuleEvent $e
  131 + */
  132 + public function onLoadModulesPost(ModuleEvent $event)
  133 + {
  134 + $this->moduleLoader->unregister();
  135 + $this->writeArrayToFile(
  136 + $this->options->getModuleMapCacheFile(),
  137 + $this->moduleLoader->getModuleClassMap()
  138 + );
  139 + }
  140 +}
12 tests/Zend/Loader/ModuleAutoloaderTest.php
@@ -197,4 +197,16 @@ public function testCanLoadModulesFromExplicitLocation()
197 197 $this->assertTrue(class_exists('PharModuleExplicit\Module'));
198 198 }
199 199
  200 + public function testCanLoadModulesFromClassMap()
  201 + {
  202 + $loader = new ModuleAutoloader();
  203 + $loader->setModuleClassMap(array(
  204 + 'BarModule\Module' => __DIR__ . '/_files/BarModule/Module.php',
  205 + 'PharModuleMap\Module' => __DIR__ . '/_files/PharModuleMap.phar',
  206 + ));
  207 + $loader->register();
  208 +
  209 + $this->assertTrue(class_exists('BarModule\Module'));
  210 + $this->assertTrue(class_exists('PharModuleMap\Module'));
  211 + }
200 212 }
15 tests/Zend/Loader/_files/BarModule/Module.php
... ... @@ -0,0 +1,15 @@
  1 +<?php
  2 +/**
  3 + * Zend Framework (http://framework.zend.com/)
  4 + *
  5 + * @link http://github.com/zendframework/zf2 for the canonical source repository
  6 + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  7 + * @license http://framework.zend.com/license/new-bsd New BSD License
  8 + * @package Zend_Loader
  9 + */
  10 +
  11 +namespace BarModule;
  12 +
  13 +class Module
  14 +{
  15 +}
BIN  tests/Zend/Loader/_files/PharModuleMap.phar
Binary file not shown
1  tests/Zend/Loader/_files/_buildPhars.php
@@ -4,6 +4,7 @@
4 4 // Executable
5 5 // .phar
6 6 buildModulePhar('PharModule');
  7 +buildModulePhar('PharModuleMap');
7 8 // .phar.gz
8 9 buildModulePhar('PharModuleGz', Phar::PHAR, Phar::GZ);
9 10 // .phar.bz2
96 tests/Zend/ModuleManager/Listener/ModuleLoaderListenerTest.php
... ... @@ -0,0 +1,96 @@
  1 +<?php
  2 +/**
  3 + * Zend Framework (http://framework.zend.com/)
  4 + *
  5 + * @link http://github.com/zendframework/zf2 for the canonical source repository
  6 + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  7 + * @license http://framework.zend.com/license/new-bsd New BSD License
  8 + * @package Zend_ModuleManager
  9 + */
  10 +
  11 +namespace ZendTest\ModuleManager\Listener;
  12 +
  13 +use ArrayObject;
  14 +use InvalidArgumentException;
  15 +use PHPUnit_Framework_TestCase as TestCase;
  16 +use Zend\ModuleManager\Listener\ModuleResolverListener;
  17 +use Zend\ModuleManager\Listener\ModuleLoaderListener;
  18 +use Zend\ModuleManager\Listener\ListenerOptions;
  19 +use Zend\ModuleManager\ModuleManager;
  20 +use Zend\ModuleManager\ModuleEvent;
  21 +
  22 +class ModuleLoaderListenerTest extends TestCase
  23 +{
  24 + public function setUp()
  25 + {
  26 + $this->tmpdir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'zend_module_cache_dir';
  27 + @mkdir($this->tmpdir);
  28 +
  29 + $this->moduleManager = new ModuleManager(array());
  30 + $this->moduleManager->getEventManager()->attach('loadModule.resolve', new ModuleResolverListener, 1000);
  31 + }
  32 +
  33 + public function tearDown()
  34 + {
  35 + $file = glob($this->tmpdir . DIRECTORY_SEPARATOR . '*');
  36 + @unlink($file[0]); // change this if there's ever > 1 file
  37 + @rmdir($this->tmpdir);
  38 + }
  39 +
  40 + public function testModuleLoaderListenerFunctionsAsAggregateListenerEnabledCache()
  41 + {
  42 + $options = new ListenerOptions(array(
  43 + 'cache_dir' => $this->tmpdir,
  44 + 'module_map_cache_enabled' => true,
  45 + 'module_map_cache_key' => 'foo',
  46 + ));
  47 +
  48 + $configListener = new ModuleLoaderListener($options);
  49 +
  50 + $moduleManager = $this->moduleManager;
  51 + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
  52 + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
  53 +
  54 + $configListener->attach($moduleManager->getEventManager());
  55 + $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
  56 + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
  57 + }
  58 +
  59 + public function testModuleLoaderListenerFunctionsAsAggregateListenerDisabledCache()
  60 + {
  61 + $options = new ListenerOptions(array(
  62 + 'cache_dir' => $this->tmpdir,
  63 + ));
  64 +
  65 + $configListener = new ModuleLoaderListener($options);
  66 +
  67 + $moduleManager = $this->moduleManager;
  68 + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
  69 + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
  70 +
  71 + $configListener->attach($moduleManager->getEventManager());
  72 + $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
  73 + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
  74 + }
  75 +
  76 + public function testModuleLoaderListenerFunctionsAsAggregateListenerHasCache()
  77 + {
  78 + $options = new ListenerOptions(array(
  79 + 'cache_dir' => $this->tmpdir,
  80 + 'module_map_cache_enabled' => true,
  81 + 'module_map_cache_key' => 'foo',
  82 + ));
  83 +
  84 + file_put_contents($options->getModuleMapCacheFile(), '<?php return array();');
  85 +
  86 + $configListener = new ModuleLoaderListener($options);
  87 +
  88 + $moduleManager = $this->moduleManager;
  89 + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
  90 + $this->assertEquals(0, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
  91 +
  92 + $configListener->attach($moduleManager->getEventManager());
  93 + $this->assertEquals(2, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES)));
  94 + $this->assertEquals(1, count($moduleManager->getEventManager()->getListeners(ModuleEvent::EVENT_LOAD_MODULES_POST)));
  95 + }
  96 +}

0 comments on commit c7c5591

Please sign in to comment.
Something went wrong with that request. Please try again.