Keep application.ini in version control without conflicting

The Problem with application.ini

One of the most common problems when working on large projects with several people are the different configurations. For example: every developer may have different application.ini configuration settings or different include paths on his system, moreover on the staging and live environment the configuration will differ for sure from what is being kept in version control.

One way I’ve seen this being handled is to use the configuration extending functionality provided by Zend, so there is a [production] section, [development : production] section, and from there every developer defines it’s own section (ex. [samurai : development]) and so on. This is a working approach to the problem but it has several drawbacks:

  • Everybody sees everybody’s database login credentials and other configuration setting that may be private in some way (ex. passwords)
  • The application.ini becomes a huge sheet full with sections overriding one another that have nothing to do with the actual project.

Keeping the configurations out of version control is also a bad idea when it comes to deployment of the project on a server or on another developer machine since someone will have to send the latest copy of his configuration to the person doing the deployment. Also if a certain task requires adding a new configuration option it will be inefficient sending the change to the other team members by mail, chat or some other means of communication.

The Solution

A very practical solution is to have two configurations – one that stays in version control and one that every developer creates manually on his machine. Then regardless of what section of the application.ini the project is currently using (development, production, etc.) the values from the local non-versioned configuration override the values from the “official” application.ini that stays under version control.

For example the project’s application.ini looks like this:

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

resources.db.adapter = "mysqli"
resources.db.params.host = "localhost"
resources.db.params.username = "production_db_username"
resources.db.params.password = "production_db_password"
resources.db.params.dbname = "production_db_name"
resources.db.isDefaultTableAdapter = true
resources.db.params.charset = "utf8"

;... imagine other configuration stuff here ...

[staging : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 0

resources.db.params.username = "staging_db_username"
resources.db.params.password = "staging_db_password"
resources.db.params.dbname = "staging_db_name"

And everyone can create in the “application/configs” directory a file called application.local.ini that looks like this:

phpSettings.display_errors = 1

resources.db.params.username = "staging_db_username"
resources.db.params.password = "staging_db_password"
resources.db.params.dbname = "staging_db_name"

And override the settings in the currently loaded section.

This functionality doesn’t come built in Zend, but it isn’t difficult at all adding it. Just edit the application/Bootstrap.php file and override the __construct method like this:

public function __construct($application)
{
    /* @var $application Zend_Application|Zend_Application_Bootstrap_Bootstrapper */

    $applicationConfig = new Zend_Config($application->getOptions(), true);

    // overriding default configs with default configurations
    $applicationLocalConfigPath = APPLICATION_PATH . '/configs/application.local.ini';
    
    if(is_readable($applicationLocalConfigPath))
    {
        $applicationLocalConfig = new Zend_Config_Ini($applicationLocalConfigPath);
        $applicationConfig->merge($applicationLocalConfig);
    }

    $this->setApplication($application);
    $options = $applicationConfig->toArray();
    $this->setOptions($options);

    if($application->hasOption('resourceloader'))
    {
        $this->setOptions(array(
            'resourceloader' => $application->getOption('resourceloader')
        ));
    }
 
    $this->getResourceLoader();

    if(!$this->hasPluginResource('FrontController'))
    {
        $this->registerPluginResource('FrontController');
    }
}

And it will search for application.local.ini file in application/configs and will merge the currently loaded section of the application.ini with the local settings. Also it’s a good idea to configure the project repository to ignore the application.local.ini file if someone accidentally tries to add/commit it.

Leave a Reply

Your email address will not be published. Required fields are marked *


× 5 = twenty five

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>