feature: Config helper to simplify config access (#7066)

Saves from having to check isset() and all that junk.
Uses dot separated config paths like the database.

Usage:
  Config::get('install_dir')
  Config::get('memcached.enable', false)
  Config::getDeviceSetting($device, 'retries', 'snmp', 5)
  Config::getOsSetting($device, 'nobulk')
  Config::set('poller_modules', array())
This commit is contained in:
Tony Murray
2017-07-21 17:05:07 -05:00
committed by Neil Lathwood
parent 123a90feab
commit ddc65e1bef
2 changed files with 282 additions and 0 deletions

142
LibreNMS/Config.php Normal file
View File

@@ -0,0 +1,142 @@
<?php
/**
* Config.php
*
* Config convenience class to access and set config variables.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2017 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS;
class Config
{
/**
* Get a config value, if non existent null (or default if set) will be returned
*
* @param string $key period separated config variable name
* @param mixed $default optional value to return if the setting is not set
* @return mixed
*/
public static function get($key, $default = null)
{
global $config;
$keys = explode('.', $key);
$curr = &$config;
foreach ($keys as $k) {
// do not add keys that don't exist
if (!isset($curr[$k])) {
return $default;
}
$curr = &$curr[$k];
}
if (is_null($curr)) {
return $default;
}
return $curr;
}
/**
* Get a setting from a device, if that is not set,
* fall back to the global config setting prefixed by $global_prefix
* The key must be the same for the global setting and the device setting.
*
* @param array $device Device array
* @param string $key Name of setting to fetch
* @param string $global_prefix specify where the global setting lives in the global config
* @param mixed $default will be returned if the setting is not set on the device or globally
* @return mixed
*/
public static function getDeviceSetting($device, $key, $global_prefix = null, $default = null)
{
if (isset($device[$key])) {
return $device[$key];
}
if (isset($global_prefix)) {
$key = "$global_prefix.$key";
}
return self::get($key, $default);
}
/**
* Get a setting from the $config['os'] array using the os of the given device
* The sames as Config::get("os.{$device['os']}.$key")
*
* @param array $device Device array
* @param string $key period separated config variable name
* @param mixed $default optional value to return if the setting is not set
* @return mixed
*/
public static function getOsSetting($device, $key, $default = null)
{
if (!isset($device['os'])) {
return $default;
}
return self::get("os.{$device['os']}.$key", $default);
}
/**
* Set a variable in the global config
*
* @param mixed $key period separated config variable name
* @param mixed $value
*/
public static function set($key, $value)
{
global $config;
$keys = explode('.', $key);
$curr = &$config;
foreach ($keys as $k) {
$curr = &$curr[$k];
}
$curr = $value;
}
/**
* Check if a setting is set
*
* @param string $key period separated config variable name
* @return bool
*/
public static function has($key)
{
global $config;
$keys = explode('.', $key);
$last = array_pop($keys);
$curr = &$config;
foreach ($keys as $k) {
// do not add keys that don't exist
if (!isset($curr[$k])) {
return false;
}
$curr = &$curr[$k];
}
return is_array($curr) && isset($curr[$last]);
}
}

140
tests/ConfigTest.php Normal file
View File

@@ -0,0 +1,140 @@
<?php
/**
* ConfigTest.php
*
* Tests for LibreNMS\Config
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2017 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Tests;
use LibreNMS\Config;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
public function testGetBasic()
{
$dir = realpath(__DIR__ . '/..');
$this->assertEquals($dir, Config::get('install_dir'));
}
public function testSetBasic()
{
global $config;
Config::set('basics', 'first');
$this->assertEquals('first', $config['basics']);
}
public function testGet()
{
global $config;
$config['one']['two']['three'] = 'easy';
$this->assertEquals('easy', Config::get('one.two.three'));
}
public function testGetDeviceSetting()
{
global $config;
$device = array('set' => true, 'null' => null);
$config['null'] = 'notnull!';
$config['noprefix'] = true;
$config['prefix']['global'] = true;
$this->assertNull(Config::getDeviceSetting($device, 'unset'), 'Non-existing settings should return null');
$this->assertTrue(Config::getDeviceSetting($device, 'set'), 'Could not get setting from device array');
$this->assertTrue(Config::getDeviceSetting($device, 'noprefix'), 'Failed to get setting from global config');
$this->assertEquals(
'notnull!',
Config::getDeviceSetting($device, 'null'),
'Null variables should defer to the global setting'
);
$this->assertTrue(
Config::getDeviceSetting($device, 'global', 'prefix'),
'Failed to get setting from global config with a prefix'
);
$this->assertEquals(
'default',
Config::getDeviceSetting($device, 'something', 'else', 'default'),
'Failed to return the default argument'
);
}
public function testGetOsSetting()
{
global $config;
$device = array('os' => 'nullos');
$config['os']['nullos']['fancy'] = true;
$this->assertNull(Config::getOsSetting(array(), 'unset'), '$device array missing os should return null');
$this->assertNull(Config::getOsSetting($device, 'unset'), 'Non-existing settings should return null');
$this->assertFalse(Config::getOsSetting($device, 'unset', false), 'Non-existing settings should return $default');
$this->assertTrue(Config::getOsSetting($device, 'fancy'), 'Failed to get setting');
}
public function testSet()
{
global $config;
Config::set('you.and.me', "I'll be there");
$this->assertEquals("I'll be there", $config['you']['and']['me']);
}
public function testHas()
{
Config::set('long.key.setting', 'no one cares');
Config::set('null', null);
$this->assertFalse(Config::has('null'), 'Keys set to null do not count as existing');
$this->assertTrue(Config::has('long'), 'Top level key should exist');
$this->assertTrue(Config::has('long.key.setting'), 'Exact exists on value');
$this->assertFalse(Config::has('long.key.setting.nothing'), 'Non-existent child setting');
$this->assertFalse(Config::has('off.the.wall'), 'Non-existent key');
$this->assertFalse(Config::has('off.the'), 'Config:has() should not modify the config');
}
public function testGetNonExistent()
{
$this->assertNull(Config::get('There.is.no.way.this.is.a.key'));
$this->assertFalse(Config::has('There.is.no')); // should not add kes when getting
}
public function testGetNonExistentNested()
{
$this->assertNull(Config::get('cheese.and.bologna'));
}
public function testGetSubtree()
{
Config::set('words.top', 'August');
Config::set('words.mid', 'And Everything');
Config::set('words.bot', 'After');
$expected = array(
'top' => 'August',
'mid' => 'And Everything',
'bot' => 'After'
);
$this->assertEquals($expected, Config::get('words'));
}
}