Pragmatism in the real world

Caching your ZF2 merged configuration

Zend Framework 2’s ModuleManager has the ability to cache the merged configuration information for your application. This is very useful as it allows you to separate out your configuration within the config/autoload directory into logical files without worrying about the performance implications of lots of files.

Enabling caching is simply a case of setting these configuration keys in config/application.config.php within the module_listener_options section:

	'module_listener_options' => array(
        'config_cache_enabled'     => true,
        'module_map_cache_enabled' => true,
        'cache_dir'                => 'data/cache/',
		// other keys go here (e.g. module_paths & config_glob_paths)
	),

This then creates the cache files data/cache/module-classmap-cache.php and data/cache/module-config-cache.php and you’re done. If you need to regenerate the files, simply delete then.

During development this can be a pain to remember!

We can solve this by only caching when in production. The easiest way to do this is by setting an environment variable in your virtual host. For Apache, use SetEnv; you’re on your own for any other web server.

The way I do this is to modify config/application.config.php like this:

use ZendStdlibArrayUtils;

$config = array(
	// all standard application configuration ...
);


$localAppConfigFilename = 'config/application.config.' . getenv('APPLICATION_ENV') . '.php';
if (is_readable($localAppConfigFilename)) {
    $config = ArrayUtils::merge($config, require($localAppConfigFilename));
}

return $config;

I then create a separate configuration file for each environment. For production, I turn on caching:

config/application.config.production.php:

return array(
    'module_listener_options' => array(
        'config_cache_enabled' => true,
        'module_map_cache_enabled' => true,
    ),
);

and for my local development, I add some development modules:

config/application.config.development.php:

return array(
    'modules' => array(
        'BjyProfiler',
        'ZendDeveloperTools',
    ),
);

This system allows me to have a faster production site and specific modules loaded when developing that make life easier.

7 thoughts on “Caching your ZF2 merged configuration

  1. Thank for sharing this.

    I wonder if we should change ZF 2, so that it merges application.config.local.php, so that you do not need the pain of environment variables again (like we had in ZF 1).

  2. Bart,

    That would be trivial. Just change

    $localAppConfigFilename = 'config/application.config.' . getenv('APPLICATION_ENV') . '.php';

    to

    $localAppConfigFilename = 'config/application.config.local.php';

    and you're done.

    Rob…

  3. Thanks,

    but when the cache is generated, there are some errors:

    Fatal error: Call to undefined method Closure::__set_state()

    In the module module-config-cache.php there is this:

    'authentication' =>
    Closure::__set_state(array(
    )),

    And in the original config file the authentication was this:

    'authentication' => function ($serviceManager) {
    return new CommonBundleComponentAuthenticationAuthentication(
    $serviceManager->get('authentication_credentialadapter'),
    $serviceManager->get('authentication_doctrineservice')
    );
    },

    Is this a bug of ZF2?

  4. In Symfony2 we additionally write a file into the cache that just lists all the config files used to generate the php cache file. In development we can then simply check the change time of these files to figure out if we need to regenerate the cache. There are of course cases where this fails (f.e. as some config options might be set dynamically during the Bundle initialization) and you still need to manually delete the cache. Bit this way for the most part one gets a speedy dev experience that updates the cache automatically if needed.

  5. Kristof,

    This is related to trying to serialise a closure.

    Never put closures in your config files. Always put them in your modules' service manger related getXxx() methods.

    Regards,

    Rob…

  6. @Kristof
    Either do as Rob said, or use substitute closures with factory classes. I find the latter to be more comfortable in the long run, since all the factory stuff is in MyModuleFactory*Factory.php.

  7. hello. I would like to know what is the best way to draw file containing module name, url and other descriptions, with config.ini file or through global.php and local.php with ServiceManager?

Comments are closed.