views:

632

answers:

6

I am using Zend_Application and it does not feel right that I am mixing in my application.ini both application and user configuration.

What I mean with this is the following. For example, my application needs some library classes in the namespace MyApp_ . So in application.ini I put autoloaderNamespaces[] = "MyApp_". This is pure application configuration, no-one except a programmer would change these. On the other hand I put there a database configuration, something that a SysAdmin would change.

My idea is that I would split options between an application.ini and an user.ini, where the options in user.ini take preference (so I can define standard values in application.ini).

Is this a good idea? How can I best implement this? The idea's I have are

  • Extending Zend_Application to take multiple config files
  • Making an init function in my Bootstrap loading the user.ini
  • Parsing the config files in my index.php and pass these to Zend_Application (sounds ugly)

What shall I do? I would like to have the 'cleanest' solution, which is prepared for the future (newer ZF versions, and other developers working on the same app)

+3  A: 

There is nothing wrong with that, I do something similar. I suggest using your second choice. I just have an _initConfig() method that takes care of loading the user config using Zend_Config_Ini. I wouldn't extend Zend_App, that seems a bit much.

Edit:

In response to your comment, you would simply do:

$this->bootstrap('config');

Thus, to ensure config is loaded before DB, you'd have something like:

protected function _initConfig()
{
    $config = new Zend_Config_Ini('/path/to/user.ini');
    return $config;
}

protected function _initDb()
{
    $this->bootstrap('config');
    $config = $this->getResource('Config');

    /* ... */
}

There is no need to use Zend_Registry as anything returned by a Bootstrap _init method is accessible using getResource()

hobodave
How do you ensure that _initConfig is invoked before all your other _init methods?
Peter Smit
This is in my opinion quite ugly. Adding in every methods a dependency on the 'config' being bootstrapped is not very generic and error-prone (the next developer working on this project will probably not notice that he has to add this to his new init method. And then he will be lucky for some time that the config is bootstrapped earlier, until somebody refactors and changes the name/order of init methods, and bwam, a nice big bug)
Peter Smit
Regardless of the perceived ugliness, that's how dependency tracking is handled with Zend_Application. If the next developer follows best practices, he shouldn't *need* the $config without knowing specifically that he needs the config. This phantom developer should ask himself, "well how do I get the config? I know it's loaded..." Then both the existing code and the ZF documentation well tell him that he can use getResource().
hobodave
Additionally, this option is still better than your other two suggestions simply because it is a _standard_ way of doing things with Zend_Application. If you extend Zend_App and hack in additional functionality, or perform some complex config merging voodoo in your index.php, it's going to be custom to your application and likely never seen before by the next developer.
hobodave
A: 

You can ensure an _initConfig() bootstrap method is invoked before others by specifying in your other bootstrap methods (that require the config object) something like:

$this->bootstrap('config');

A more complete example (context of a Bootstrap class):

protected function _initConfig() {
    $config = new Zend_Config_Ini('[filename]');
    Zend_Registry::set('config',$config);
}

protected function _initSomething() {
    $this->bootstrap('config');
    $config = Zend_Registry::get('config');
    // you can now do whatever you like with the $config object
}

Update:

As has now been mentioned in other answers, if the config is only required within the bootstrap, I would say to use the $this->getResource('Config') method. I use the registry so that config can be accessed easily in other parts of my application.

berty
There's no need to use Zend_Registry as simply returning $config makes it accessible through the bootstrap.
hobodave
True, but I like to keep my config in the registry so it can be accessed by whatever else needs it later in execution.
berty
A: 

In a similar scenario, I saw that the application specific parameters can be provided programmatically when instantiating the application. This helped to place configuration related parameters within the config.ini

I did it actually this way:

inside the index.php to bootstap the application

     $application = new Zend_Application(APPLICATION_ENV, array(
                'resources' => array(
                   'FrontController' => array(
                       'controllerDirectory' => APPLICATION_PATH . '/main/controllers',
                    ),
                'layout' => array(
                    'layoutpath' => APPLICATION_PATH . "/layouts/scripts"
                    ),
                ),
            ));

and then inside the bootstrap parse the config.ini inidependently

    protected function _initConfigFile() {
        try {
            $configuration = new Zend_Config_Ini(
                APPLICATION_PATH . '/config/app.ini',
                APPLICATION_ENV );
            $registry->configuration = $configuration;
        } catch (Zend_Exception $zExp) {
            echo "Could not read application ini file (app.ini). "
                . " Please check that it exists and has the appropriate structure.\n";
            echo("\n");
            var_dump($zExp);
            exit(1);
        }
    }

inside the bootstrap

dimitris mistriotis
How would this be done? Zend_Application takes either a php-array or an config.ini, not both, isn't it?
Peter Smit
@peter smit: you are right, this is how I implemented it...
dimitris mistriotis
A: 

An configuration file can have the item 'config' which refers to another config file. Zend_Application will include this config file. The included config-file will have preference, and overwrite the keys already defined in the standard config-file.

Yesterday there was also started a thread on the Zend Framework mailing list

Examples

application.ini:

[production]
config = APPLICATION_PATH "/configs/config.ini"
resources.db.adapter = "Mysqli"
resources.db.host = "localhost"

config.ini:

[production]
resources.db.host = "mysql.server.com"
resources.db.username = "myuser"

public/index.php:

$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);
Peter Smit
+2  A: 

I found a solution to this issue that may be new to framework version 1.10. When creating the Zend Application object, you can pass in 2 configuration file paths in the options array that get merged together:

$application = new Zend_Application( APPLICATION_ENV, array( 'config' => array(APPLICATION_PATH . '/configs/application.ini',APPLICATION_PATH . '/configs/user.ini'), ) );

Troy
+1  A: 

you know this will merge as much inis as you want?

in application.ini

[production]
config[] = APPLICATION_PATH "/configs/dsn.ini"
config[] = APPLICATION_PATH "/configs/error.ini"
...
bas
Is this new? Or is it just not documented?
Peter Smit