Yii Framework Forum: Configuration/DI container - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Configuration/DI container something I've been working on

#1 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 26 July 2012 - 07:43 PM

After thinking about configuration for a while, I came up with some new ideas, and I've been tinkering with a configuration container class, which is now fairly complete:

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?
1

#2 User is offline   Keith 

  • Elite Member
  • Yii
  • Group: Moderators
  • Posts: 1,655
  • Joined: 04-March 10
  • Location:UK

Posted 27 July 2012 - 03:30 AM

I really like the look of that. I'll be interested to see the core team's opinions.
0

#3 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,745
  • Joined: 17-January 09
  • Location:Russia

Posted 27 July 2012 - 04:40 AM

Interesting approach. IDE support is a big pro of it.
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#4 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 27 July 2012 - 08:11 AM

Thanks :-)

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 :-)
0

#5 User is offline   Ben 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 273
  • Joined: 15-March 09

Posted 27 July 2012 - 08:26 AM

One weakness I see: IDE support doesn't come from the classes you're trying to configure. Instead, you have to replicate all configurable properties into the doc block of your ConfigContainer specialization. If you modify a class, you always have to take care to also modify the related config class. Not sure if or how this could be solved though...

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.
Don't like ads in my sig...
0

#6 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 27 July 2012 - 09:54 AM

View PostBen, on 27 July 2012 - 08:26 AM, said:

One weakness I see: IDE support doesn't come from the classes you're trying to configure. Instead, you have to replicate all configurable properties into the doc block of your ConfigContainer specialization. If you modify a class, you always have to take care to also modify the related config class.


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.

View PostBen, on 27 July 2012 - 08:26 AM, said:

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.


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.
0

#7 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,745
  • Joined: 17-January 09
  • Location:Russia

Posted 27 July 2012 - 06:16 PM

Any example on why and how to use it in a real application?
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#8 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 28 July 2012 - 04:19 PM

You would use this the same way you use configuration-files now - it's not really different from what you're doing with "config/main.php" right now, except of course the syntax is different, and plus all the benefits listed above. I think I've listed plenty of reasons "why"? :-)

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...
0

#9 User is offline   yJeroen 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 94
  • Joined: 06-September 11
  • Location:The Netherlands

Posted 28 July 2012 - 08:07 PM

mindplay, question but isnt this a repost of your other thread that's very similar to this? (objects vs arrays)

http://www.yiiframew...paringly-in-20/
0

#10 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 28 July 2012 - 08:33 PM

Hardly a repost, since this is an actual solution and code - although this definitely does relate to that general discussion, this implementation addresses the issue of configuration specifically. Each of the components that currently rely on arrays could receive similar treatments - and it is possible that there's a subset of functionality in this class that could be separated for reuse in other components...
0

#11 User is offline   ekerazha 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 526
  • Joined: 10-October 08
  • Location:European Union

Posted 29 July 2012 - 04:55 AM

Brilliant.
Moreover we finally have some good reasons to not have Db config
Yii user #37
0

#12 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 30 July 2012 - 10:19 AM

View Postekerazha, on 29 July 2012 - 04:55 AM, said:

Brilliant.
Moreover we finally have some good reasons to not have Db config


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.
0

#13 User is offline   ekerazha 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 526
  • Joined: 10-October 08
  • Location:European Union

Posted 30 July 2012 - 12:17 PM

I didn't refer to that :D
Yii user #37
0

#14 User is offline   fsb 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 123
  • Joined: 09-January 11

Posted 30 July 2012 - 03:03 PM

I can't say I entirely understand the code but I think I get some of it.

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?
Join the happiest place on Freenode: #yii
We've got a MrFisk the bot, hilarious banter and all kinds of other groovy stuff going on.
Comparison of Internet Relay Chat clients
Web IRC client
0

#15 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 30 July 2012 - 08:16 PM

"mixed" is supported - basically just turns off the type-checking for the property.

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...
0

#16 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 30 July 2012 - 08:24 PM

I know Yii 2.0 is targeting PHP 5.3, but with PHP 5.4 you could simplify some things by adjusting the calling-context on the closures - so, for instance, $this in the anonymous functions would refer to the configuration-container, which would give you better control over initialization of co-dependent components.

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...
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users