Jul 182012
 

So you’re all excited to try out ZF2. You clone the skeleton, install some modules, maybe even follow Rob Allen’s excellent ZF2 tutorial, and finally, start building your application. Now, if you’re a former ZF1 user or refugee from another framework, you might be troubled at this point by the fact that, at first glance, ZF2 doesn’t appear to take into consideration environment-specific configuration values (e.g., development, testing, staging, production). Luckily, this is not the case!

The ZF2 way (recommended)

The officially sanctioned “ZF2 way” is a notion of “local” config files. That is, if a specific environment needs a different config value for something, you put that in a local config file in that environment. By convention, these local config files are ignored from source code control. This practice helps discourage committing sensitive information like database credentials into source code control, however it leaves deployment of these “local” configuration files up to the user and their particular deployment process.

Personally, for each local config file I have for my application, I commit a .dist variant of it into source code control, with any sensitive values removed. Then the deployment task is simply to copy the dist files and populate the appropriate values for each environment, or in some cases the dist files can even have the values for a specific environment already enabled (granted they don’t pose a security risk!). For example I might have a ./config/autoload/logger.local.php.dist-testing file which sets a null logger, with a post-receive hook on the testing server or before_install task on travis-ci that copies the file without the .dist-testing extension. So far, this practice has been working quite well for me.

The ZF1 way (for those stuck in the past)

However, if the whole “local” config file thing just isn’t sitting right with you, it’s extremely simple to get that old behavior back. Open up your config/application.config.php file and add an additional glob path (line 9):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
return array(
    'modules' => array(
        'Application',
    ),
    'module_listener_options' => array(
        'config_glob_paths'    => array(
            'config/autoload/{,*.}{global,local}.php',
            'config/autoload/{,*.}' . (getenv('APPLICATION_ENV') ?: 'production') . '.php',
        ),
        'module_paths' => array(
            './module',
            './vendor',
        ),
    ),
);

Note: In the above example, I have set ‘production’ as the default environment if no APPLICATION_ENV variable is set. You can of course change this, though it’s generally best practice to assume production for the off chance that the environment variable somehow becomes undefined in your production environment.

You can now add config files such as ./config/autoload/logger.staging.php, which will only be loaded on the server with the APPLICATION_ENV environment variable set to ‘staging’. This gives you that familiar functionality that config/ini sections gave you in ZF1.

Enjoy, and please remember not to commit sensitive information like database credentials into source control!

  10 Responses to “Environment-specific configuration in Zend Framework 2”

  1. Thank, this is what i was looking for.

    But, how can we achieve inheritance?

    • Read the article: “Then the deployment task is simply to copy the dist files and populate the appropriate values for each environment, or in some cases the dist files can even have the values for a specific environment already enabled (granted they don’t pose a security risk!). For example I might have a ./config/autoload/logger.local.php.dist-testing file which sets a null logger, with a post-receive hook on the testing server or before_install task on travis-ci that copies the file without the .dist-testing extension.”

      The point is that because ZF2 globs config files, you can set the precedence by which they are loaded. Typically, you should only be concerned with global settings and ones specific for the current environment — the latter can be in .dist files if they absolutely must be, but they can also be in another directory entirely, which you add to the glob patterns. This allows you to inherit easily, and have per-environment settings.

      • The problem that I see is that there is configuration that is common to a type of environment (e.g. development, staging, production, whatever) and then I have configuration that is specification a specific local environment (e.g. my development environment, Bob’s development environment). I don’t want every developer to have to copy the .local.dist files and modify a pile of settings; I want them to modify only the settings that are actually local and not common to all development environments.

        In ZF1 projects we have actually implemented something more similar to this hybrid approach anyway; we provide hierarchical configuration, which can then be overridden by copying a .local.ini.dist file to a .local.ini to override any settings as required.

        So it seems that ZF1 was flexible enough to implement the ZF2 approach if desired, and thankfully ZF2 is flexible enough to do it the ZF1 was as well ;)

  2. What is the best way to read those config values from either a Model or a Controller?

  3. Hi Evan,

    Very clean and usefull post, thanks! I translate it to Russian and post on my blog about ZF, if you don’t mind.

  4. How about the application.config.php?

    I’m trying to load up the “ZendDeveloperTools” and “BjyProfiler” modules only at development and I’d be happy to do it without the environment variable. Any ideas?

  5. This is great & perhaps I’m missing something, but the thing that I miss most about the environment variables from ZF1 is that the dev environment had error reporting set to E_ALL, which seems to be turned off somewhere in the Zend\Application class.

    I found this workaround

    http://www.thisprogrammingthing.com/2012/enabling-error-displays-in-zend-framework-2/

    But I’m wondering if this should be the accepted way to do it?

  6. @Evan: The ZF1-way — I was wondering if this is still your opinion?

    I am actually concerned that I have to maintain four (4! — development, testing, staging and production) different configuration files now and no one mentions that you it would be easier if you could use some kind of inheritance in a simple .ini file. Assuming I break up my configuration even further, this becomes a hot mess.

    I especially in development setting (early on), these files will be stale all the time. I wonder how much more code and communication overhead you need to handle configuration changes or missing configuration changes. Changes will happen and people will constantly have to catch up. Or go through error messages and hopefully figure out fast what is missing.

    Developers also need to keep your dist files up to date, and last but not least the chore of automating it all because no one likes to edit half a dozen files before they can run a project.

    I’m not sure how ZF2 made this decision, environment build in was one of the huge advantages of ZF1 though.

    • I’m inclined to agree with Till.

      On ZF1 we could just make one environment configuration and then extend to others modifying only what was different, now that seems to be gone.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre user="" computer="" color="" escaped="">