Configuration/DI container something I've been working on
#1
Posted 26 July 2012 - 07:43 PM
https://gist.github.com/3183156
There's an example at the end of the file, and inline notes describing what it is and what it does.
Essentially, I wanted a configuration container that will play well with an IDE, protects against errors and missing configuration, simplifies components with co-dependencies, and still supports late construction.
Figured I'd share this as inspiration for Yii 2.0.
Let me know what you think?
#2
Posted 27 July 2012 - 03:30 AM
#4
Posted 27 July 2012 - 08:11 AM
I just got fed up with the array-array-array-ness of it all, and started thinking about how to fix that.
I don't know yet how this compares in terms of performance - it's going to be a lot more function-calls, as it is right now. Though I could reduce the number of function-calls quite a bit by allowing you to pass multiple configuration-functions with one call, e.g. one per configuration-file.
There's also more work to do still on actually loading configuration-files - it's not finished, but it shows off the important bits :-)
#5
Posted 27 July 2012 - 08:26 AM
Another thing which I think could come in handy is a cache. The container should be able to serve a validated configuration without the need to re-build and re-validate on every request.
#6
Posted 27 July 2012 - 09:54 AM
Ben, on 27 July 2012 - 08:26 AM, said:
No - take another look. The properties are only defined using doc-blocks, you don't need to modify the class itself. There is no duplication - IDE support and run-time support both come from the @property-annotations.
Ben, on 27 July 2012 - 08:26 AM, said:
As I said, I haven't benchmarked it yet - it may need optimization. I'm not sure a cache would solve anything though - depending on the caching medium, it could even slow things down.
Perhaps better would be a $debug-flag, so you could turn off type-checking (and perhaps other checks) on production-systems?
I just posted an update with a load() method, more inline comments and additional documentation.
#8
Posted 28 July 2012 - 04:19 PM
As for "how", there are still some unfinished parts here - but let's assume that this had been integrated with the application-object in Yii, and here's a partial example to give you a general idea.
First, the configuration-class for your application:
<?php # "component/MyAppConf.php"
/**
* @property string $rootPath the root-path (e.g. "protected" folder)
* @property CDbConnection $connection primary database-connection
* @property CCache $cache common cache for db-connection and others
*/
class MyAppConf extends Configuration
{}
Next, the "index.php" main dispatch script - I'm skipping some parts here, and probably getting some property-names wrong etc., but just to give you a general idea:
<?php # "index.php"
// (bootstrap Yii here...)
Yii::app()->config->load('main.php');
if ($_SERVER['HTTP_HOST'] == 'localhost') {
// load additional configuration for test/development environment:
Yii::app()->config->load('test.php');
}
Yii::app()->run();
Now your application-wide configuration file - this one is always loaded first, so this should contain a complete configuration with defaults for everything:
<?php # "config/main.php"
$this->rootPath = dirname(dirname(__FILE__));
$this->connection = function(CCache $cache) {
// note that $cache will automatically initialize when CDbConnection is initialized.
$db = new CDbConnection();
$db->host = 'db.foo.com';
$db->username = 'foo';
$db->password = 'bar';
$db->cache = $cache;
return $db;
};
$this->cache = function($rootPath) {
$c = new CFileCache();
$c->path = $rootPath.'/runtime/cache';
return $c;
};
And now my local configuration-overrides for testing - as you saw in "index.php", this only loads when the hostname is "localhost", so I can put my local configuration-overrides here:
<?php # "config/test.php"
$this->configure(function(CDbConnection $connection) {
$connection->host = 'localhost';
$connection->username = 'root';
$connection->password = '';
});
That's it, a very basic example, probably with some errors here and there, I just typed this up quick to give you some idea of how you would use this...
#9
Posted 28 July 2012 - 08:07 PM
http://www.yiiframew...paringly-in-20/
#10
Posted 28 July 2012 - 08:33 PM
#12
Posted 30 July 2012 - 10:19 AM
ekerazha, on 29 July 2012 - 04:55 AM, said:
There are different ways you could approach that - for really hard dependencies like a db username and password, you could add those to the configuration-container itself, alongside the connection-component, e.g.:
<?php
### "components/AppConfig.php"
/**
* ...
* @property CDbConnection $connection
* @property string $dbUsername
* @property string $dbPassword
*/
class AppConfig extends Configuration
{}
### "config/main.php"
$this->connection = function($dbUsername, $dbPassword) {
$c = new CDbConnection;
$c->username = $dbUsername;
$c->password = $dbPassword;
return $c;
};
### "config/local.php"
$this->dbUsername = 'root';
$this->dbPassword = '*****';
In this example, dbUsername and dbPassword properties will be injected when the connection-property is fisrt accessed, and checked when you seal() the configuration-container - so having a username and password for the DB becomes a defined requirement, and you'll get an exception if you forget to configure those.
#14
Posted 30 July 2012 - 03:03 PM
I guess it's possible to write type checkers for some other common type notations: arrays of scalars such as string[], and where a list of types is separated by |.
What about the type spec 'mixed' (the lazy programmer's friend)?
And could it work recursively for example, @param CDataColumn[] $columns?
We've got a YiiBot and all kinds of other groovy stuff going on.
Comparison of Internet Relay Chat clients
Web IRC client
#15
Posted 30 July 2012 - 08:16 PM
Collection-type syntax (CDataColumn[] etc.) is not supported, and neither is multiple types with "|" - supporting these would take more than the 10 lines of code for the very simple @property-parser I built into this. I think if I were going to support full annotation-parsing, I would lean towards a real meta-data library, rather than hard-coding support into this class.
Configuration groupings can be implemented at the moment by declaring several configuration-types, and defining a property as another Configuration-type - this would provide even more "laziness", as nested Configuration-types would themselves load and initialize late, e.g.:
<?php
# "MainConfig.php"
/**
* ...
* @property SubConfig $sub
*/
# "SubConfig.php"
/**
* ...
* @property mixed $foo
* @property mixed $bar
*/
# "index.php"
$config = new MainConfig;
$config->sub = function() {
$c = new SubConfig;
$c->foo = 123;
return $c;
};
// using late configuration and DI for sub-configuration:
$config->configure(function(SubConfig $sub)) {
$sub->configure(function($bar, $foo) {
return $foo+456;
});
});
And so on...
#16
Posted 30 July 2012 - 08:24 PM
For example, you could conditionally (if/else) select a dependent component - by going back to $this for the component you need, only the one you select would be initialized, where currently they would both must be initialized before the function is called.
That's probably an exotic requirement though - only very few cases could make use of that optimization.
And you would not get IDE support for $this...

Help

This topic is locked











