How to use the global.php/local.php configs in the getConfig() of a module in a Zend Framework 2 application?

14,273

Solution 1

You're not supposed to access other Modules setting in your Module#getConfig(). If you rely on other configuration, that CAN ONLY BE for service purposes. Ergo you'd rely on Module#getServiceConfig() and inside the factories you do have access to the ServiceManagerand access your configs with $serviceManager->get('config');. (see Sam's comment)

The loading order of the configs is by default:

  1. /config/application.config.php, that is the initial config file; not for module configs; here is the filename pattern for the config files to load defined ('config_glob_paths' => array('config/autoload/{,*.}{global,local}.php')).
  2. {ModuleNamespace}\Module#getConfig() (e.g. Cache\Module#getConfig()), that by convention should load its /module/{ModuleNamespace}/config/module.config.php;
  3. /config/autoload/global.php, that should not contain any module specific configs (see below);
  4. /config/autoload/local.php, that contains environment specific settings also should not contain any module specific configs (see below); it should not versioned/deployed;
  5. /config/autoload/{ModuleNamespaceLowerCased}.local.php (e.g. cache.local.php), that contains only the module AND environment specific settings and should not be versioned/;

For the Cache module above there can be following config files:

  • /module/Cache/config/module.config.php -- a complete set of module configs; loaded by Cache\Module#getConfig()
  • /module/Cache/config/cache.local.php.dist -- an example for /config/autoload/cache.local.php
  • /config/autoload/cache.local.php -- environment specific module configs

The setting ttl can be accessed from any place, where one has access to the Service Locator. For example in factory methods of Cache\Module#getServiceConfig()

class Module {

    public function getConfig() {
        $moduleConfig = include __DIR__ . '/config/module.config.php';
        $application = $this->getApplicationSomehow(); // <-- how?
        $applicationModuleConfig = $application->getConfig()['modules'][__NAMESPACE__];
        $config = array_merge($moduleConfig, $applicationModuleConfig);
        return $config;
    }
    ...
    public function getServiceConfig() {
        try {
            return array (
                'factories' => array(
                    'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
                        return new MemcachedOptions(array(
                            'ttl'            => $serviceManager->get('Config')['ttl'],
                            ...
                        ));
                    },
                    ...
                )
            );
        }
        ...
    }
    ...
}

For futher information about how configs are managed in ZF2 see Sam's answer and blog article.

Solution 2

Every single configuration of every single loaded Module will be merged into one single config. Namely this would be:

$serviceManager->get('config');

The reason behind (global|local).config.php is merely for usage purpose. Global configuration files should always be deployed. Local configuration files however should only be deployed as distributionables, alias local.config.php.dist.

Distributionals will not be loaded, no matter where they are places. However common notion of ZF2 is to copy the distributionables into the /config/autoload-directory of the ZF2 Application and rename them to local.config.php

One example:

// YourModule/config/module.config.php
return array(
    'key' => 1337
);

// YourModule/config/local.yourmodule.php.dist
return array(
    'key' => 7331
);

Now when you publish / deploy your application, only module.config.php will be used. If someone wants to change the configuration of your Module, they would never touch module.config.php, as this file would constantly be overwritten when your module will be updated.

However what people can do is to copy:

YourModule/config/local.yourmodule.php.dist
to
/config/autoload/local.yourmodule.php

And change the config values inside this local configuration.

To understand:

  • You should always configure your module as best as possible for a LIVE-Scenario.
  • If you have environment-specific needs, overwrite this config using a local-config
  • local configs are never deployed automatically, this is a manual task needing to be done from inside the environment itself

Hope this got a little more clear

Ultimately:

  • configure your module for a LIVE-Scenario
  • On your development machine create a /config/autoload/mymodule.local.php and overwrite your ttl with it's development value

LoadOrder:

The last interesting part, which i have completely forgotten about, would be the load order of the configuration files. As all files are merged, this is important to note!

  • First to load is /config/application.config.php
  • Second to load would be each Modules /modules/{module}/config/module.config.php *
  • Last but not least the autoloadable files will be loaded /config/autoload/{filename}.php

asterix It is actually NOT module.config.php which is called, but rather the Module-classes configuration functions. Mainly these are:

If i understand this part of the ConfigListener correctly, then getConfig() will be called first and all of the specialiced {feature}ProviderInterfaces will overwrite the data of getConfig(), but don't take this for granted, it would need a check!

Share:
14,273
automatix
Author by

automatix

Updated on June 05, 2022

Comments

  • automatix
    automatix almost 2 years

    In a ZF2 application I have some cofigs, that: 1. need to be different dependening on the environment; 2. are specific for a concrete module. I'm curently using it like here described:

    global.php & local.php

    return array(
        ...
        'modules' => array(
            'Cache' => array(
                'ttl' => 1, // 1 second
            )
        )
        ...
    );
    

    Module class

    Module {
        ...
        public function getServiceConfig() {
            try {
                return array (
                    'factories' => array(
                        'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
                            return new MemcachedOptions(array(
                                'ttl'           => $this->getConfig()['modules']['Cache']['ttl'],
                                ...
                            ));
                        },
                        ...
                    )
                );
            }
            ...
        }
        ...
    }
    

    It's working fine, but I believe, that the module specific settings should be accessed over one central place in the module -- the getConfig() method of the Module class. Like this:

    class Module {
    
        public function getConfig() {
            $moduleConfig = include __DIR__ . '/config/module.config.php';
            $application = $this->getApplicationSomehow(); // <-- how?
            $applicationModuleConfig = $application->getConfig()['modules'][__NAMESPACE__];
            $config = array_merge($moduleConfig, $applicationModuleConfig);
            return $config;
        }
        ...
        public function getServiceConfig() {
            try {
                return array (
                    'factories' => array(
                        'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
                            return new MemcachedOptions(array(
                                'ttl'            => $serviceManager->get('Config')['modules']['Cache']['ttl'],
                                ...
                            ));
                        },
                        ...
                    )
                );
            }
            ...
        }
        ...
    }
    

    The problem is, that I don't get, how to access the global.php/local.php configs in the getConfig() of a module. How can I do it?

  • automatix
    automatix about 11 years
    OK, I think, I got the logic. local.%module%.php.dist (an example for local.%module%.php) and module.config.php (default settings) in /module/Cache/config and local.%module%.php (real settings for the current environment) in /config/autoload. local.%module%.php files are merged "automatically" (magic?) to the /config/autoload/local.php and has a higher prioroty than module.config.php. 1. Do I understand this right? 2. What about the keys? If the local.%module%.php files are directly merged to local.php, how are conflicts avoided? 3. How can/should I access the settings?
  • automatix
    automatix about 11 years
    At Sam: Thank you very much for your detailed answer and the update. Sorry, I still cannot understand, how to load the /autoload/local.{modulename}.php files. I've created /autoload/local.cache.php for my module Cache, but it is not loaded. Can you please post an elementary example, how you would set the setting mysetting(in all possible relevant files in the module and application config folder) for a module MyModule and how you would access this setting from your module class?
  • automatix
    automatix about 11 years
    @Sam To "If i understand this part of the ConfigListener correctly [...]": I've just debugged a module simply setting a breakpoint into each of its config methods (this module implements only three config interfaces). The loading order is: getAutoloaderConfig(), getConfig(), getServiceConfig().
  • Sam
    Sam about 11 years
    @automatix I know, just today i've blogged about my findings from here;) samminds.com/2013/04/understanding-zf2-configuration
  • automatix
    automatix about 11 years
    How do you call the settings? I'm currently doing this with $mySetting = $this->getConfig()['mySetting'] and it cannot work, since the getConfig() just returns the configs from {module root directory} . '/config/module.config.php'.
  • Sam
    Sam about 11 years
    I feel like you gotta provide ALL your code on github or so. What's $this->getConfig()? The global configuration will be fetched from the ServiceManager (i.e. inside a controller via $this->getServiceLocator()->get('config'); or iirc what you need would be $serviceManager->get('config')
  • automatix
    automatix about 11 years
    I just wanted to understand, how to use settings in MyModule#getConfig() (and other places, where I cannot access the ServiceLocator). Yes, I can access the settings over $serviceManager->get('Config')['myConfig']. But I don't have the access to the ServiceLocator from everywhere. E.g. from MyModule#getConfig() or a table mapper class or so.
  • Sam
    Sam about 11 years
    You're not supposed to access other Modules setting in your Module#getConfig(). If you rely on other configuration, that CAN ONLY BE for service purposes. Ergo you'd rely on Module#getServiceConfig() and inside the factories you do have access to the ServiceManager
  • Marcel Djaman
    Marcel Djaman almost 9 years
    Why u did not accept @sam answer as valid answer to your question?
  • automatix
    automatix almost 9 years
    It's a very good theoretical article (+1 for it), but it didn't give me directly the answer to my question. Anyway it helped me to understand, how configs work, and to find an answer. I posted it here and accepted / marked as "valid answer".