I'd intended to work on other bits of KnowledgeTree over the weekend, but I got a bit sidetracked on configuration for some reason. The thing about tangeants is usually that they're nowhere near as useful as the stuff they're leading you from, and I suspect that's the case here. But some aspects of using a PHP file for configuration have obviously taken root because I've now designed something ever so much more complex.

Let's start with the initial problem definition: Using PHP as a configuration format for a file means that users fumble with escaping backslashes (arg, if ever one needed a reason to hate Microsoft...) and forgetting semi-colons and inverted commas and putting whitespace in the non-PHP portion of the file (screwing up setting headers).

<?php

...

// ldap settings
$default->ldapServer = "192.168.1.9";
$default->ldapRootDn = "o=Organisation";
// current supported types=iPlanet, ActiveDirectory;
$default->ldapServerType = "iPlanet";
$default->ldapDomain = "domain.com";
$default->ldapSearchUser = "searchUser@domain.com";
$default->ldapSearchPassword = "pwd";

// email settings
$default->emailServer = "localhost";
$default->emailFrom = "kt@" . $default->serverName;
$default->emaiFromName = "KnowledgeTree Document Management System";
$default->emailAdmin = "kt@" . $default->serverName;
$default->emailAdminName = "DMS Administrator";

...

?>

The ideal file format? Well, anything particularly structured is going to get in their way. I decided that .ini format (like php.ini, for example) was a good idea. And I found a .ini file reader in PEAR called Config that reads a few file formats. And looks to be extensible enough to perhaps write a storage class to store some configuration in a database.

...

[ldap]
; ldap settings
; current supported types=iPlanet, ActiveDirectory;
ldapServer = 192.168.1.9
ldapRootDn = o=Organisation
ldapServerType = iPlanet
ldapDomain = domain.com
ldapSearchUser = searchUser@domain.com
ldapSearchPassword = pwd

...

The major downside is that in PHP you can do all sorts of wonderful things in your configuration file, and in the .ini file you can't. Actually, that's perhaps not a downside at all. But certain variables reference values in other variables. Variable expansion to the rescue!

...

[email]
; email settings
emailServer = localhost
emailFrom = kt@${serverName}
emaiFromName = KnowledgeTree Document Management System
emailAdmin = kt@${serverName}
emailAdminName = DMS Administrator

...

This took about five minutes to get working nicely. And one advantage is that the expansion happens at the time you use the "get" method on the configuration wrapper.

The .ini format allows for sections using square brackets, which starts the ability to namespace variables. Repeat after me: Namespaces are one honking great idea.

Of course, this is all getting retrofitted onto a flat namespace, but it does make life nicer when some evil plans I'm working on in KnowledgeTree come to fruition.

So, here's the API of KTConfig:

<?php

require_once("Config.php");

class KTConfig {
...
    function loadFile($filename) { ... }

    function setns($seck, $k, $v) { ... }

    function expand($val) { ... }

    function get($var) { ... }

    function &getSingleton() {
        global $KTConfig;
        return $KTConfig;
    }
}

$KTConfig =& new KTConfig;

?>

Here's one of the config files I used in my tests:

[expand]
a = b
b = ${expand/a}b

[mail]
serverName = mail.example.org
emailFrom = kt@${mail/serverName}

[multi]
a = asdf
b = rewq
c = zxcv${multi/a}zxcv${multi/b}zxcv${multi/a}

So, you can use $KTConfig->get("multi/c"), and get "zxcvasdfzxcvrewqzxcvasdf" out.

Next opportunity to ponder: saving the configuration.

There are only a few configuration items that can't be stored in, say, a database. Such as the database configuration items. The rest can live in a simple key => "multi/c", value => "zxcv${multi/a}zxcv${multi/b}zxcv${multi/a}" format.

But, we have to decide what to save into the database (or a file). We don't want to save auto-configured/default values, unless they're specifically set. Well, I think that's quite important.

I think I'll stop at what I have for now, and get back to the contract-related work tomorrow (working weekends is something I avoid, but this is just really enjoyable). I can't help but be excited by the KnowledgeTree stuff that's planned over the next three months.