Advanced Configuration Tricks

Configuration of zend-mvc applications happens in several steps:

  • Initial configuration is passed to the Application instance and used to seed the ModuleManager and ServiceManager. In this tutorial, we will call this configuration system configuration.
  • The ModuleManager's ConfigListener aggregates configuration and merges it while modules are being loaded. In this tutorial, we will call this configurationapplication configuration.
  • Once configuration is aggregated from all modules, the ConfigListener will also merge application configuration globbed in specified directories (typically config/autoload/).
  • Finally, immediately prior to the merged application configuration being passed to the ServiceManager, it is passed to a special EVENT_MERGE_CONFIGevent to allow further modification.

In this tutorial, we'll look at the exact sequence, and how you can tie into it.

System configuration

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 inconfig/application.config.php. The defaults look like this:

  1. return [
  2. // Retrieve list of modules used in this application.
  3. 'modules' => require __DIR__ . '/modules.config.php',
  4. // These are various options for the listeners attached to the ModuleManager
  5. 'module_listener_options' => [
  6. // This should be an array of paths in which modules reside.
  7. // If a string key is provided, the listener will consider that a module
  8. // namespace, the value of that key the specific path to that module's
  9. // Module class.
  10. 'module_paths' => [
  11. './module',
  12. './vendor',
  13. ],
  14. // An array of paths from which to glob configuration files after
  15. // modules are loaded. These effectively override configuration
  16. // provided by modules themselves. Paths may use GLOB_BRACE notation.
  17. 'config_glob_paths' => [
  18. realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local}.php',
  19. ],
  20. // Whether or not to enable a configuration cache.
  21. // If enabled, the merged configuration will be cached and used in
  22. // subsequent requests.
  23. 'config_cache_enabled' => true,
  24. // The key used to create the configuration cache file name.
  25. 'config_cache_key' => 'application.config.cache',
  26. // Whether or not to enable a module class map cache.
  27. // If enabled, creates a module class map cache which will be used
  28. // by in future requests, to reduce the autoloading process.
  29. 'module_map_cache_enabled' => true,
  30. // The key used to create the class map cache file name.
  31. 'module_map_cache_key' => 'application.module.cache',
  32. // The path in which to cache merged configuration.
  33. 'cache_dir' => 'data/cache/',
  34. // Whether or not to enable modules dependency checking.
  35. // Enabled by default, prevents usage of modules that depend on other modules
  36. // that weren't loaded.
  37. // 'check_dependencies' => true,
  38. ],
  39. // Used to create an own service manager. May contain one or more child arrays.
  40. //'service_listener_options' => [
  41. // [
  42. // 'service_manager' => $stringServiceManagerName,
  43. // 'config_key' => $stringConfigKey,
  44. // 'interface' => $stringOptionalInterface,
  45. // 'method' => $stringRequiredMethodName,
  46. // ],
  47. // ],
  48. // Initial configuration with which to seed the ServiceManager.
  49. // Should be compatible with Zend\ServiceManager\Config.
  50. // 'service_manager' => [],
  51. ];

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, with the exception of the values under theservice_manager key, it cannot be overridden by a module.

This leads us to our first trick: how do you provide environment-specific system configuration?

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:

  • We want to use the ZendDeveloperTools module in development only.
  • We want to have configuration caching on in production only.

zfcampus/zf-development-mode provides a concise and conventions-based approach to switching between specifically production and development. The package is installed by default with version 3+ skeletons, and can be installed with existing v2 skeletons using the following:

  1. $ composer require zfcampus/zf-development-mode

The approach it takes is as follows:

  • The user provides production settings in config/application.config.php.
  • The user provides development settings inconfig/development.config.php.dist to override bootstrap-level settings such as modules and configuration caching, and optionally also inconfig/autoload/development.local.php.dist (to override application settings).
  • The bootstrap script (public/index.php) checks forconfig/development.config.php, and, if found, merges its configuration with the application configuration prior to configuring the Application instance.

When you execute:

  1. $ ./vendor/bin/zf-development-mode enable

The .dist files are copied to versions removing the suffix; doing so ensures they will then be used when invoking the application.

As such, to accomplish our goals, we will do the following:

  • In config/development.config.php.dist, add ZendDeveloperTools to the list of modules:
  1. 'modules' => [
  2. 'ZendDeveloperTools',
  3. ],
  • Also in config/development.config.php.dist, we will disable config caching:
  1. 'config_cache_enable' => false,
  • In config/application.config.php, we will enable config caching:
  1. 'config_cache_enable' => true,

Enabling development mode now enables the selected module, and disables configuration caching; disabling development mode enables configuration caching. (Also, either operation clears the configuration cache.)

If you require additional environments, you can extend zf-development-mode to address them using the same workflow.

Environment-specific application configuration

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 viaZend\ModuleManager\Listener\ConfigListener, by specifying a glob path in thesystem 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 theconfig/autoload directory, in the following order:

  • global.php
  • *.global.php
  • local.php
  • *.local.php

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.

Additional glob patterns for development mode

When using zf-development-mode, as detailed in the previous section, the shipped config/development.config.php.dist file provides an additional glob pattern for specifying development configuration:

  • config/autoload/{,*.}{global,local}-development.php

This will match files such as:

  • database.global-development.php
  • database.local-development.php

These will only be considered when development mode is enabled!

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 &mdash such as a "testing" or "staging" environment — and they each have their own specific overrides?

To accomplish this, we'll provide an environment variable via 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.

  1. 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.

With that in place, We can alter the glob path in the system configuration slightly:

  1. 'config_glob_paths' => [
  2. realpath(__DIR__) . sprintf('config/autoload/{,*.}{global,%s,local}.php', getenv('APP_ENV') ?: 'production')
  3. ],

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:

  1. config/
  2. autoload/
  3. global.php
  4. local.php
  5. users.development.php
  6. users.testing.php
  7. users.local.php

If $env evaluates to testing, then the following files will be merged, in the following order:

  1. global.php
  2. users.testing.php
  3. local.php
  4. 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.

Order of config merging

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 thesystem configuration (config/application.config.php).

Module Configuration

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 implementZend\ModuleManager\Feature\ConfigProviderInterface and/or a getConfig()method can return their configuration. The default, recommended implementation of the getConfig() method is:

  1. public function getConfig()
  2. {
  3. return include __DIR__ . '/config/module.config.php';
  4. }

where module.config.php returns a PHP array. From that PHP array you can provide general configuration as well as configuration for all the availableManager classes provided by the ServiceManager. Please refer to theConfiguration 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.

Most interfaces are in the Zend\ModuleManager\Feature namespace (some have moved to the individual components), and each is expected to return an array of configuration for a service manager, as denoted in the section on default service configuration.

Configuration mapping table

Manager name Interface name Module method name Config key name
ControllerPluginManager ControllerPluginProviderInterface getControllerPluginConfig() controller_plugins
ControllerManager 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
LogProcessorManager LogProcessorProviderInterface getLogProcessorConfig log_processors
LogWriterManager LogWriterProviderInterface getLogWriterConfig log_writers

Configuration Priority

Considering that you may have service configuration in your module configuration file, what has precedence?

The order in which they are merged is:

  • configuration returned by the various service configuration methods in a module class
  • configuration returned by getConfig()

In other words, your getConfig() wins over the various service configuration methods. Additionally, and of particular note: the configuration returned from those methods will not be cached.

Use cases for service configuration methods

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.

Manipulating merged configuration

Occasionally you will want to not just override an application configuration key, but actually remove it. Since merging will not remove keys, how can you handle this?

Zend\ModuleManager\Listener\ConfigListener triggers a special event,Zend\ModuleManager\ModuleEvent::EVENT_MERGE_CONFIG, after merging all configuration, but prior to it being passed to the ServiceManager. By listening to this event, you can inspect the merged configuration and manipulate it.

The ConfigListener itself listens to the event at priority 1000 (i.e., very high), which is when the configuration is merged. You can tie into this to modify the merged configuration from your module, via the init() method.

  1. namespace Foo;
  2. use Zend\ModuleManager\ModuleEvent;
  3. use Zend\ModuleManager\ModuleManager;
  4. class Module
  5. {
  6. public function init(ModuleManager $moduleManager)
  7. {
  8. $events = $moduleManager->getEventManager();
  9. // Registering a listener at default priority, 1, which will trigger
  10. // after the ConfigListener merges config.
  11. $events->attach(ModuleEvent::EVENT_MERGE_CONFIG, array($this, 'onMergeConfig'));
  12. }
  13. public function onMergeConfig(ModuleEvent $e)
  14. {
  15. $configListener = $e->getConfigListener();
  16. $config = $configListener->getMergedConfig(false);
  17. // Modify the configuration; here, we'll remove a specific key:
  18. if (isset($config['some_key'])) {
  19. unset($config['some_key']);
  20. }
  21. // Pass the changed configuration back to the listener:
  22. $configListener->setMergedConfig($config);
  23. }
  24. }

At this point, the merged application configuration will no longer contain the key some_key.

Cached configuration and merging

If a cached config is used by the ModuleManager, the EVENT_MERGE_CONFIGevent will not be triggered. However, typically that means that what is cached will be what was originally manipulated by your listener.

Configuration merging workflow

To cap off the tutorial, let's review how and when configuration is defined and merged.

  • System configuration
  • Defined in config/application.config.php
  • No merging occurs
  • Allows manipulation programmatically, which allows the ability to:
    • Alter flags based on computed values
    • Alter the configuration glob path based on computed values
    • Configuration is passed to the Application instance, and then theModuleManager in order to initialize the system.
  • Application configuration
  • The ModuleManager loops through each module class in the order defined in the system configuration
    • Service configuration defined in Module class methods is aggregated
    • Configuration returned by Module::getConfig() is aggregated
    • Files detected from the service configuration config_glob_paths setting are merged, based on the order they resolve in the glob path.
    • ConfigListener triggers EVENT_MERGE_CONFIG:
    • ConfigListener merges configuration
    • Any other event listeners manipulate the configuration
    • Merged configuration is finally passed to the ServiceManager

Advanced Configuration Tricks的更多相关文章

  1. openwrt advanced configuration

    openwrt高级配置(汗 照着标题就翻译过来了) openwrt Kamikaze 8.09的一般配置文件都在目录 /etc/config 下面,可以使用脚本来调用参数和设置参数. 比如 sbin/ ...

  2. Bing Advanced Search Tricks You Should Know

    Bing is one of the world's most popular search engines that has gained many fans with its ease of us ...

  3. Google Analytics Advanced Configuration - Google Analytics 高级配置

    该文档提供了Android SDK v3的部分元素的高级配置说明. Overview - 概述 Android Google Analytics SDK提供了Tracker类,应用可以用它给Googl ...

  4. Nginx - Configuration File Syntax

    Configuration Directives The Nginx configuration file can be described as a list of directives organ ...

  5. Jmeter-Maven-Plugin高级应用:Remote Server Configuration

    Remote Server Configuration Pages 12 Home Adding additional libraries to the classpath Advanced Conf ...

  6. Jmeter-Maven-Plugin高级应用:Proxy Configuration

    Proxy Configuration Pages 12 Home Adding additional libraries to the classpath Advanced Configuratio ...

  7. Spring Boot Reference Guide

    Spring Boot Reference Guide Authors Phillip Webb, Dave Syer, Josh Long, Stéphane Nicoll, Rob Winch,  ...

  8. App Distribution Guide--(三)---Configuring Your Xcode Project for Distribution

    Configuring Your Xcode Project for Distribution You can edit your project settings anytime, but some ...

  9. gentoo 安装

    加载完光驱后 1进行ping命令查看网络是否通畅 2设置硬盘的标识为GPT(主要用于64位且启动模式为UEFI,还有一个是MBR,主要用于32位且启动模式为bois) parted -a optima ...

随机推荐

  1. log4net 将日志写入数据库

    asp.net利用log4net写入日志到SqlServer数据库,Log4net是一个开源的错误日志记录项目,易用性强,源自log4j,品质值得信赖. 下面就我的安装部署log4net到MS sql ...

  2. Diamond

    Diamond主要提供持久配置的发布和订阅服务,最大特点是结构简单,稳定可靠.Diamond的主要使用场景是用来进行动态数据库切换与扩容,进行一些业务系统运行时开关配置的推送.Diamond产品专注于 ...

  3. C++模拟键盘鼠标消息

    #include <Windows.h> /* * === FUNCTION ======================================================= ...

  4. js跟着鼠标移动的文字

    废话不多说,直接上代码,有注释: <head> <title></title> <style type="text/css"> sp ...

  5. Deep learning:三十四(用NN实现数据的降维)

    数据降维的重要性就不必说了,而用NN(神经网络)来对数据进行大量的降维是从2006开始的,这起源于2006年science上的一篇文章:reducing the dimensionality of d ...

  6. 【UR #12】实验室外的攻防战(BIT)

    [题目链接] http://uoj.ac/problem/180 [题意] 给定两个1..n的排列AB,只有当ai<ai+1才能交换ai和ai+1,问是否能够将A转换为B. [思路] 令a[i] ...

  7. codeforce 609A - USB Flash Drives

    排序水题 #include<iostream> #include<cstdlib> #include<cstdio> #include<algorithm&g ...

  8. cocos2d-x3.0+Eclipse配置说明

    假如我们已经装了JavaJDK.Cygwin,也解压了2013-08-27之后最新的AndroidSDK,其实最新的AndroidSDK已经集成了eclipse,eclipse里面已经配置好了Andr ...

  9. leetcode@ [49] Group Anagrams (Hashtable)

    https://leetcode.com/problems/anagrams/ Given an array of strings, group anagrams together. For exam ...

  10. android AudioRecord 与 AudioTrack的录音加回放的使用

    http://stackoverflow.com/questions/32682952/audiotrack-audiotack-not-playing-fully-recorded-audio