Pragmatism in the real world

Akrabat_Config (2nd Attempt)

Update! This version has been superceded! Check out Akrabat_Config (Take Three!) for an even better version…

Nico Edtinger was kind enough to review Akrabat_Config and pointed out that it wouldn’t handle a key with multiple dots in it. His post to fw-general:

One method I don’t “like” is processSection(). If I have a name like “foo.bar.baz” it would be saved as $config[‘foo’][‘bar’], dropping the last part because you explode without a third parameter. It should be
$pieces = explode(‘.’, $key, 2);

I’d also change the check for a dot to
if(strpos($key, ‘.’)) {

That would work with a key with a leading dot (being stored just as is instead of $config[”][…]) and the explode doesn’t need to parse a string that doesn’t have a dot anyway and create an array that’s not needed.

Thus, this is my second attempt at Akrabat_Config:

The new tests are:

< ?php require_once 'PHPUnit2/Framework/TestCase.php'; include "Zend.php"; class ConfigTest extends PHPUnit2_Framework_TestCase { protected $iniFilename; function setUp() { $this->iniFilename = dirname(__FILE__).'/data/config.ini';
}

function testLoadAll()
{
Zend::loadClass('Akrabat_Config');
$config = new Akrabat_Config($this->iniFilename, 'all');
$this->assertEquals('all', $config->hostname);
$this->assertEquals('all', $config->test['me']);
}

function testInclude()
{
Zend::loadClass('Akrabat_Config');
$config = new Akrabat_Config($this->iniFilename, 'staging');
$this->assertEquals('staging', $config->hostname);
$this->assertEquals('staging', $config->test['me']);
}

function testMultiLevels()
{
Zend::loadClass('Akrabat_Config');
$config = new Akrabat_Config($this->iniFilename, 'multi');
zend::dump($config);
$this->assertEquals('four', $config->one['two.three']);
$this->assertEquals('five', $config->one['two.three.four']);
}

function testLeadingDot()
{
Zend::loadClass('Akrabat_Config');
$config = new Akrabat_Config($this->iniFilename, 'dot');
$this->assertEquals('dot', $config->get("."));
$this->assertEquals('doubledot', $config->get(".."));
$this->assertEquals('t-dot', $config->get("t."));
$this->assertEquals('dot-t', $config->get(".t"));
}
}

?>

with data/config.ini:

[all]
hostname = all
test.me = all

[staging]
include = all
hostname = staging
test.me = staging

[multi]
one.two.three = four
one.two.three.four = five
one.two..three = dotdotthree

[dot]
. = dot
.. = doubledot
t. = t-dot
.t = dot-t

and Akrabat_Config looks like this:

< ?php class Akrabat_Config { private $_config; /** * Load the section $section from the ini file called $filename. * If any keys with $section are called "include", then the section * pointed to by the "include" is then included first. Thus, the keys * in $section will override any keys of the same name in the sections * that have been "include"ed. * * example ini file: * [all] * db.connection = database * hostname = live * * [staging] * include = all * hostname = staging * * after callgin $config = new Akrabat_Config($file, 'staging'); then * $config->hostname = staging
* $config->db['connection'] = database
*
*
* @param string $filename
* @param string $section
*/
function __construct($filename, $section)
{
$iniArray = parse_ini_file($filename, true);

$config = array();
if(isset($iniArray[$section]))
{
foreach($iniArray[$section] as $key => $value)
{
if($key == 'include')
{
if(isset($iniArray[$value]))
{
$config = array_merge($config, $this->processSection($iniArray[$value]));
}
unset($iniArray[$section][$key]);

}
}
$config = array_merge($config, $this->processSection($iniArray[$section]));
}
else
{
throw new Exception("No section '$section' in $filename'");
}
$this->_config = $config;
}

/**
* Helper function to handle single level namespace in the key
*
* @param array $section
* @return array
*/
protected function processSection($section)
{
$config = array();
foreach($section as $key=>$value)
{
if(strpos($key, '.'))
{
$pieces = explode('.', $key, 2);
if(!empty($pieces[1]))
{
$config[$pieces[0]][$pieces[1]] = $value;
}
else
{
$config[$key] = $value;
}
}
else
{
$config[$key] = $value;
}

}
return $config;
}

/**
* @param string $name
* @param mixed $default
* @return mixed
*/
function get($name, $default=false)
{
$result = $default;
if(isset($this->_config[$name]))
{
$result = $this->_config[$name];
}
return $result;
}

/**
* magic function so that $config->value will work.
*
* @param string $name
* @return mixed
*/
function __get($name)
{
return $this->get($name);
}

}
?>

2 thoughts on “Akrabat_Config (2nd Attempt)

  1. Looks interesting. I've always hated to have my settings all over the place. It's also something that I don't like in my bootstap file. It's clutter ;) Then again, there ini functions in PHP if i'm not mistaken, so this could be considered reinventing the wheel…

  2. Yes – this class is a thin wrapper around the ini handling function. Though it provides additional functionality by allowing for overriding of keys in one section with keys in another.

    On the fw-general list we are talking about allowing for loading multiple files into one config object. I quite like that idea so might play with it tonight.

Comments are closed.