Configuration of Zend Framework 2 applications happens in several steps:
In this tutorial, we’ll look at the exact sequence, and how you can tie into it.
To begin module loading, we have to tell the Application instance about the available modules and where they live, optionally provide some information to the default module listeners (e.g., where application configuration lives, and what files to load; whether to cache merged configuration, and where; etc.), and optionally seed the ServiceManager. For purposes of this tutorial we will call this the system configuration.
When using the skeleton application, the system configuration is by default in config/application.config.php. The defaults look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | <?php
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Application',
),
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => array(
// This should be an array of paths in which modules reside.
// If a string key is provided, the listener will consider that a module
// namespace, the value of that key the specific path to that module's
// Module class.
'module_paths' => array(
'./module',
'./vendor',
),
// An array of paths from which to glob configuration files after
// modules are loaded. These effectively overide configuration
// provided by modules themselves. Paths may use GLOB_BRACE notation.
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
// Whether or not to enable a configuration cache.
// If enabled, the merged configuration will be cached and used in
// subsequent requests.
//'config_cache_enabled' => $booleanValue,
// The key used to create the configuration cache file name.
//'config_cache_key' => $stringKey,
// Whether or not to enable a module class map cache.
// If enabled, creates a module class map cache which will be used
// by in future requests, to reduce the autoloading process.
//'module_map_cache_enabled' => $booleanValue,
// The key used to create the class map cache file name.
//'module_map_cache_key' => $stringKey,
// The path in which to cache merged configuration.
//'cache_dir' => $stringPath,
// Whether or not to enable modules dependency checking.
// Enabled by default, prevents usage of modules that depend on other modules
// that weren't loaded.
// 'check_dependencies' => true,
),
// Used to create an own service manager. May contain one or more child arrays.
//'service_listener_options' => array(
// array(
// 'service_manager' => $stringServiceManagerName,
// 'config_key' => $stringConfigKey,
// 'interface' => $stringOptionalInterface,
// 'method' => $stringRequiredMethodName,
// ),
// )
// Initial configuration with which to seed the ServiceManager.
// Should be compatible with Zend\ServiceManager\Config.
// 'service_manager' => array(),
);
|
The system configuration is for the bits and pieces related to the MVC that run before your application is ready. The configuration is usually brief, and quite minimal.
Also, system configuration is used immediately, and is not merged with any other configuration – which means it cannot be overridden by a module.
This leads us to our first trick: how do you provide environment-specific system configuration?
What happens when you want to change the set of modules you use based on the environment? Or if the configuration caching should be enabled based on environment?
It is for this reason that the default system configuration we provide in the skeleton application is in PHP; providing it in PHP means you can programmatically manipulate it.
As an example, let’s make the following requirements:
To make this happen, we’ll set an environment variable in our web server configuration, APP_ENV. In Apache, you’d put a directive like the following in either your system-wide apache.conf or httpd.conf, or in the definition for your virtual host; alternately, it can be placed in an .htaccess file.
SetEnv "APP_ENV" "development"
For other web servers, consult the web server documentation to determine how to set environment variables.
To simplify matters, we’ll assume the environment is “production” if no environment variable is present.
We’ll modify the config/application.config.php file to read as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <?php
$env = getenv('APP_ENV') ?: 'production';
// Use the $env value to determine which modules to load
$modules = array(
'Application',
);
if ($env == 'development') {
$modules[] = 'ZendDeveloperTools';
}
return array(
'modules' => $modules,
'module_listener_options' => array(
'module_paths' => array(
'./module',
'./vendor',
),
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
// Use the $env value to determine the state of the flag
'config_cache_enabled' => ($env == 'production'),
'config_cache_key' => 'app_config',
// Use the $env value to determine the state of the flag
'module_map_cache_enabled' => ($env == 'production'),
'module_map_cache_key' => 'module_map',
'cache_dir' => 'data/config/',
// Use the $env value to determine the state of the flag
'check_dependencies' => ($env != 'production'),
),
);
|
This approach gives you flexibility to alter system-level settings.
However, how about altering application specific settings (not system configuration) based on the environment?
Sometimes you want to change application configuration to load things such as database adapters, log writers, cache adapters, and more based on the environment. These are typically managed in the service manager, and may be defined by modules. You can override them at the application level via Zend\ModuleManager\Listener\ConfigListener, by specifying a glob path in the system configuration – the module_listener_options.config_glob_paths key from the previous examples.
The default value for this is config/autoload/{,*.}{global,local}.php. What this means is that it will look for application configuration files in the config/autoload directory, in the following order:
This allows you to define application-level defaults in “global” configuration files, which you would then commit to your version control system, and environment-specific overrides in your “local” configuration files, which you would omit from version control.
This is a great solution for development, as it allows you to specify alternate configuration that’s specific to your development environment without worrying about accidently deploying it. However, what if you have more environments – such as a “testing” or “staging” environment – and they each have their own specific overrides?
Again, the application environment variable comes to play. We can alter the glob path in the system configuration slightly:
'config_glob_paths' => array(
sprintf('config/autoload/{,*.}{global,%s,local}.php', $env)
),
The above will allow you to define an additional set of application configuration files per environment; furthermore, these will be loaded only if that environment is detected!
As an example, consider the following tree of configuration files:
config/
autoload/
global.php
local.php
users.development.php
users.testing.php
users.local.php
If $env evaluates to testing, then the following files will be merged, in the following order:
global.php
users.testing.php
local.php
users.local.php
Note that users.development.php is not loaded – this is because it will not match the glob pattern!
Also, because of the order in which they are loaded, you can predict which values will overwrite the others, allowing you to both selectively overwrite as well as debug later.
Note
The files under config/autoload/ are merged after your module configuration, detailed in next section. We have detailed it here, however, as setting up the application configuration glob path happens within the system configuration (config/application.config.php).
One responsibility of modules is to provide their own configuration to the application. Modules have two general mechanisms for doing this.
First, modules that either implement Zend\ModuleManager\Feature\ConfigProviderInterface and/or a getConfig() method can return their configuration. The default, recommended implementation of the getConfig() method is:
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
where module.config.php returns a PHP array. From that PHP array you can provide general configuration as well as configuration for all the available Manager classes provided by the ServiceManager. Please refer to the Configuration mapping table to see which configuration key is used for each specific Manager.
Second, modules can implement a number of interfaces and/or methods related to specific service manager or plugin manager configuration. You will find an overview of all interfaces and their matching Module Configuration functions inside the Configuration mapping table.
All interfaces are in the Zend\ModuleManager\Feature namespace, and each is expected to return an array of configuration for a service manager, as denoted in the section on default service configuration.
Manager name | Interface name | Module Method name | Config key name |
---|---|---|---|
ControllerPluginManager | ControllerPluginProviderInterface | getControllerPluginConfig() | controller_plugins |
ControllerLoader | ControllerProviderInterface | getControllerConfig() | controllers |
FilterManager | FilterProviderInterface | getFilterConfig() | filters |
FormElementManager | FormElementProviderInterface | getFormElementConfig() | form_elements |
HydratorManager | HydratorProviderInterface | getHydratorConfig() | hydrators |
InputFilterManager | InputFilterProviderInterface | getInputFilterConfig() | input_filters |
RoutePluginManager | RouteProviderInterface | getRouteConfig() | route_manager |
SerializerAdapterManager | SerializerProviderInterface | getSerializerConfig() | serializers |
ServiceLocator | ServiceProviderInterface | getServiceConfig() | service_manager |
ValidatorManager | ValidatorProviderInterface | getValidatorConfig() | validators |
ViewHelperManager | ViewHelperProviderInterface | getViewHelperConfig() | view_helpers |
Considering that you may have service configuration in your module configuration file, what has precedence?
The order in which they are merged is:
In other words, your various service configuration methods win. Additionally, and of particular note: the configuration returned from those methods will not be cached. The reason for this is that it is not uncommon to use closures or factory instances in configuration returned from your Module class – which cannot be cached reliably.
Note
Use the various service configuration methods when you need to define closures or instance callbacks for factories, abstract factories, and initializers. This prevents caching problems, and also allows you to write your configuration files in other markup formats.
To cap off the tutorial, let’s review how and when configuration is defined and merged.
The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.