Refactor ConfigLib and remove outdated tests
This commit is contained in:
parent
b405190389
commit
d44020aacf
5 changed files with 225 additions and 132 deletions
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use LogLib\Log;
|
use LogLib\Log;
|
||||||
use ncc\Runtime;
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
@ -67,15 +66,67 @@
|
||||||
|
|
||||||
if ($this->path === null)
|
if ($this->path === null)
|
||||||
{
|
{
|
||||||
// Figure out the path to the configuration file
|
$filePath = $name . '.conf';
|
||||||
try
|
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
|
||||||
{
|
{
|
||||||
$this->path = Runtime::getDataPath('net.nosial.configlib') . DIRECTORY_SEPARATOR . $name . '.conf';
|
$configDir = getenv('APPDATA') ?: getenv('LOCALAPPDATA');
|
||||||
}
|
|
||||||
catch (Exception $e)
|
if (!$configDir)
|
||||||
{
|
{
|
||||||
throw new RuntimeException('Unable to load package "net.nosial.configlib"', $e);
|
// Fallback to system temporary directory
|
||||||
|
$configDir = sys_get_temp_dir();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$configDir .= DIRECTORY_SEPARATOR . 'ConfigLib';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$homeDir = getenv('HOME') ?: '';
|
||||||
|
$configDirs = [];
|
||||||
|
|
||||||
|
if ($homeDir)
|
||||||
|
{
|
||||||
|
$configDirs[] = $homeDir . DIRECTORY_SEPARATOR . '.configlib';
|
||||||
|
$configDirs[] = $homeDir . DIRECTORY_SEPARATOR . '.config' . DIRECTORY_SEPARATOR . 'configlib';
|
||||||
|
}
|
||||||
|
|
||||||
|
$configDirs[] = '/etc/configlib';
|
||||||
|
$configDirs[] = '/var/lib/configlib';
|
||||||
|
|
||||||
|
$configDir = null;
|
||||||
|
|
||||||
|
// Iterate over the list of directories and select the first one that can be created or written to
|
||||||
|
foreach ($configDirs as $dir)
|
||||||
|
{
|
||||||
|
if (file_exists($dir) && is_writable($dir))
|
||||||
|
{
|
||||||
|
$configDir = $dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
elseif (!file_exists($dir) && mkdir($dir, 0755, true))
|
||||||
|
{
|
||||||
|
$configDir = $dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$configDir)
|
||||||
|
{
|
||||||
|
Log::warning('net.nosial.configlib', sprintf('Unable to find a proper directory to store configuration paths in, using temporary directory instead: %s', sys_get_temp_dir()));
|
||||||
|
$configDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'configlib';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the directory exists
|
||||||
|
if (!file_exists($configDir))
|
||||||
|
{
|
||||||
|
if (!mkdir($configDir, 0755, true) && !is_dir($configDir))
|
||||||
|
{
|
||||||
|
throw new RuntimeException(sprintf('Directory "%s" was not created', $configDir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->path = $configDir . DIRECTORY_SEPARATOR . $filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the name
|
// Set the name
|
||||||
|
@ -105,12 +156,12 @@
|
||||||
/**
|
/**
|
||||||
* Validates a key syntax (e.g. "key1.key2.key3")
|
* Validates a key syntax (e.g. "key1.key2.key3")
|
||||||
*
|
*
|
||||||
* @param string $input
|
* @param string $input The key to validate
|
||||||
* @return bool
|
* @return bool True if the key is valid, false otherwise
|
||||||
*/
|
*/
|
||||||
private static function validateKey(string $input): bool
|
private static function validateKey(string $input): bool
|
||||||
{
|
{
|
||||||
$pattern = '/^([a-zA-Z]+\.?)+$/';
|
$pattern = '/^([a-zA-Z0-9]+\.?)+$/';
|
||||||
|
|
||||||
if (preg_match($pattern, $input))
|
if (preg_match($pattern, $input))
|
||||||
{
|
{
|
||||||
|
@ -120,35 +171,6 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to convert a string to the correct type (int, float, bool, string)
|
|
||||||
*
|
|
||||||
* @param $input
|
|
||||||
* @return float|int|mixed|string
|
|
||||||
* @noinspection PhpUnusedPrivateMethodInspection
|
|
||||||
*/
|
|
||||||
private static function cast($input): mixed
|
|
||||||
{
|
|
||||||
if (is_numeric($input))
|
|
||||||
{
|
|
||||||
if(str_contains($input, '.'))
|
|
||||||
{
|
|
||||||
return (float)$input;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ctype_digit($input))
|
|
||||||
{
|
|
||||||
return (int)$input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif (in_array(strtolower($input), ['true', 'false']))
|
|
||||||
{
|
|
||||||
return filter_var($input, FILTER_VALIDATE_BOOLEAN);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string)$input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a value from the configuration
|
* Returns a value from the configuration
|
||||||
*
|
*
|
||||||
|
@ -179,8 +201,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the value at the end of the path
|
// Return the value at the end of the path, or the default if the value is null
|
||||||
return $current;
|
return $current ?? $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,6 +215,7 @@
|
||||||
*/
|
*/
|
||||||
public function set(string $key, mixed $value, bool $create = false): bool
|
public function set(string $key, mixed $value, bool $create = false): bool
|
||||||
{
|
{
|
||||||
|
// Validate the provided key
|
||||||
if (!self::validateKey($key))
|
if (!self::validateKey($key))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -201,27 +224,61 @@
|
||||||
$path = explode('.', $key);
|
$path = explode('.', $key);
|
||||||
$current = &$this->configuration;
|
$current = &$this->configuration;
|
||||||
|
|
||||||
// Navigate to the parent of the value to set
|
foreach ($path as $keyPart)
|
||||||
foreach ($path as $key_value)
|
|
||||||
{
|
{
|
||||||
if (is_array($current) && array_key_exists($key_value, $current))
|
if (!is_array($current))
|
||||||
{
|
{
|
||||||
$current = &$current[$key_value];
|
$current = [];
|
||||||
}
|
}
|
||||||
elseif($create)
|
|
||||||
|
if (!array_key_exists($keyPart, $current))
|
||||||
{
|
{
|
||||||
$current[$key_value] = [];
|
if ($create)
|
||||||
$current = &$current[$key_value];
|
{
|
||||||
|
$current[$keyPart] = [];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$current = &$current[$keyPart];
|
||||||
}
|
}
|
||||||
|
|
||||||
$current = $value;
|
$current = $value;
|
||||||
$this->modified = true;
|
$this->modified = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a configuration key exists
|
||||||
|
*
|
||||||
|
* @param string $key The key to check (e.g. "key1.key2.key3")
|
||||||
|
* @return bool True if the key exists, false otherwise
|
||||||
|
*/
|
||||||
|
public function exists(string $key): bool
|
||||||
|
{
|
||||||
|
// Validate the provided key
|
||||||
|
if (!self::validateKey($key))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = explode('.', $key);
|
||||||
|
$current = $this->configuration;
|
||||||
|
|
||||||
|
foreach ($path as $keyPart)
|
||||||
|
{
|
||||||
|
if (is_array($current) && array_key_exists($keyPart, $current))
|
||||||
|
{
|
||||||
|
$current = $current[$keyPart];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -229,9 +286,9 @@
|
||||||
/**
|
/**
|
||||||
* Sets the default value for a key if it does not exist
|
* Sets the default value for a key if it does not exist
|
||||||
*
|
*
|
||||||
* @param string $key
|
* @param string $key The key to set (e.g. "key1.key2.key3")
|
||||||
* @param mixed $value
|
* @param mixed $value The value to set
|
||||||
* @return bool
|
* @return bool True if the value was set, false otherwise
|
||||||
*/
|
*/
|
||||||
public function setDefault(string $key, mixed $value): bool
|
public function setDefault(string $key, mixed $value): bool
|
||||||
{
|
{
|
||||||
|
@ -243,42 +300,11 @@
|
||||||
return $this->set($key, $value, true);
|
return $this->set($key, $value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given key exists in the configuration
|
|
||||||
*
|
|
||||||
* @param string $key
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function exists(string $key): bool
|
|
||||||
{
|
|
||||||
if(!self::validateKey($key))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$path = explode('.', $key);
|
|
||||||
$current = $this->configuration;
|
|
||||||
|
|
||||||
foreach ($path as $key_value)
|
|
||||||
{
|
|
||||||
if (is_array($current) && array_key_exists($key_value, $current))
|
|
||||||
{
|
|
||||||
$current = $current[$key_value];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the current configuration data
|
* Clears the current configuration data
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @noinspection PhpUnused
|
|
||||||
*/
|
*/
|
||||||
public function clear(): void
|
public function clear(): void
|
||||||
{
|
{
|
||||||
|
@ -317,9 +343,8 @@
|
||||||
/**
|
/**
|
||||||
* Loads the Configuration File from the disk
|
* Loads the Configuration File from the disk
|
||||||
*
|
*
|
||||||
* @param bool $force
|
* @param bool $force If true, the configuration will be reloaded even if it was not modified
|
||||||
* @return void
|
* @return void
|
||||||
* @noinspection PhpUnused
|
|
||||||
*/
|
*/
|
||||||
public function load(bool $force=false): void
|
public function load(bool $force=false): void
|
||||||
{
|
{
|
||||||
|
@ -381,6 +406,7 @@
|
||||||
{
|
{
|
||||||
$current[$key_value] = [];
|
$current[$key_value] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$current = &$current[$key_value];
|
$current = &$current[$key_value];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -399,7 +425,7 @@
|
||||||
/**
|
/**
|
||||||
* Returns the name of the configuration
|
* Returns the name of the configuration
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string The name of the configuration
|
||||||
* @noinspection PhpUnused
|
* @noinspection PhpUnused
|
||||||
*/
|
*/
|
||||||
public function getName(): string
|
public function getName(): string
|
||||||
|
@ -410,7 +436,7 @@
|
||||||
/**
|
/**
|
||||||
* Returns the path of the configuration file on disk
|
* Returns the path of the configuration file on disk
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string The path of the configuration file
|
||||||
*/
|
*/
|
||||||
public function getPath(): string
|
public function getPath(): string
|
||||||
{
|
{
|
||||||
|
@ -420,7 +446,7 @@
|
||||||
/**
|
/**
|
||||||
* Returns the configuration
|
* Returns the configuration
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array The configuration
|
||||||
* @noinspection PhpUnused
|
* @noinspection PhpUnused
|
||||||
*/
|
*/
|
||||||
public function getConfiguration(): array
|
public function getConfiguration(): array
|
||||||
|
@ -431,11 +457,11 @@
|
||||||
/**
|
/**
|
||||||
* Returns a formatted yaml string of the current configuration
|
* Returns a formatted yaml string of the current configuration
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string The configuration in YAML format
|
||||||
*/
|
*/
|
||||||
public function toYaml(): string
|
public function toYaml(): string
|
||||||
{
|
{
|
||||||
return Yaml::dump($this->configuration, 4, 2);
|
return Yaml::dump($this->configuration, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -459,7 +485,7 @@
|
||||||
/**
|
/**
|
||||||
* Imports a YAML file into the configuration
|
* Imports a YAML file into the configuration
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path The path to the YAML file
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function import(string $path): void
|
public function import(string $path): void
|
||||||
|
@ -481,7 +507,7 @@
|
||||||
/**
|
/**
|
||||||
* Exports the configuration to a YAML file
|
* Exports the configuration to a YAML file
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path The path to export the configuration to
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function export(string $path): void
|
public function export(string $path): void
|
||||||
|
|
100
tests/ConfigLib/ConfigurationTest.php
Normal file
100
tests/ConfigLib/ConfigurationTest.php
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace ConfigLib;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ConfigurationTest extends TestCase
|
||||||
|
{
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
unlink($config->getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConstruct(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration();
|
||||||
|
$this->assertInstanceOf(Configuration::class, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetExists(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
|
||||||
|
$this->assertTrue($config->set('key1.key2', 'value', true));
|
||||||
|
$this->assertEquals('value', $config->get('key1.key2'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetNotExists(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$this->assertFalse($config->set('key1.key3', 'value'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetInvalidKey(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$this->assertFalse($config->set('invalid\key', 'value'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetExists(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$config->set('key1.key2', 'value');
|
||||||
|
$this->assertEquals('value', $config->get('key1.key2'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* Test get method when provided with existing key
|
||||||
|
*/
|
||||||
|
public function testGetMethodWithValidKey(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$config->set('key1.key2', 'value');
|
||||||
|
$this->assertEquals('value', $config->get('key1.key2'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* Test get method when provided with non-existing key
|
||||||
|
*/
|
||||||
|
public function testGetMethodWithInvalidKey(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$this->assertNull($config->get('non.existing.key'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* Test get method when key format is not valid
|
||||||
|
*/
|
||||||
|
public function testGetMethodWithIncorrectKeyFormat(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$this->assertNull($config->get('incorrect\format'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* Test get method when provided with existing key and expecting the default value to be returned
|
||||||
|
*/
|
||||||
|
public function testGetMethodWithValidKeyExpectingDefaultValue(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$config->set('key1.key2', null);
|
||||||
|
$this->assertEquals('default', $config->get('key1.key2', 'default'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* Test setDefault method when non-existing key is provided
|
||||||
|
*/
|
||||||
|
public function testSetDefaultWithNonExistingKey(): void
|
||||||
|
{
|
||||||
|
$config = new Configuration('test');
|
||||||
|
$this->assertTrue($config->setDefault('non.existing.key', 'default'));
|
||||||
|
$this->assertEquals('default', $config->get('non.existing.key'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require 'ncc';
|
|
||||||
import('net.nosial.configlib');
|
|
||||||
|
|
||||||
$config = new \ConfigLib\Configuration('test');
|
|
||||||
|
|
||||||
$config->setDefault('database.host', '127.0.0.1');
|
|
||||||
$config->setDefault('database.port', 3306);
|
|
||||||
$config->setDefault('database.username', 'root');
|
|
||||||
$config->setDefault('database.password', null);
|
|
||||||
$config->setDefault('database.name', 'test');
|
|
||||||
|
|
||||||
$config->save();
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require 'ncc';
|
|
||||||
import('net.nosial.configlib');
|
|
||||||
|
|
||||||
$config = new \ConfigLib\Configuration('test');
|
|
||||||
|
|
||||||
$config->set('database.host', '192.168.1.1');
|
|
||||||
$config->set('database.username', 'super_root');
|
|
||||||
|
|
||||||
$config->save();
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require 'ncc';
|
|
||||||
import('net.nosial.configlib');
|
|
||||||
|
|
||||||
$config = new \ConfigLib\Configuration('test');
|
|
||||||
|
|
||||||
var_dump($config->getConfiguration());
|
|
Loading…
Add table
Add a link
Reference in a new issue