+ EXPIRE_HALF_DAY + + +
+ + + + + +
+ public
+ mixed
+ EXPIRE_HALF_DAY
+ = 43200
+
+
+
+
+
+
+
+
+
+From 82b358b3ffb1b8ab451327b72a9f8fdfaa16c5a3 Mon Sep 17 00:00:00 2001
From: jamesgober Configuration Manager Common expiration durations in seconds. Indicates whether the configuration cache has been loaded. Primary configuration storage. Primary configuration storage, including unique keys from
+grouped configurations. Stores all configuration key-value pairs, including unique keys
-generated from grouped configurations. Default configuration directory path. Whether configuration keys should be flattened. Grouped configuration storage. Grouped configuration storage, allowing access by group or
+unique key. Stores configurations by groups, allowing access by original
-source filename or unique key. Maximum allowed depth for nested configurations. This property sets a limit on how deeply nested configurations can be
-processed by the flattening logic. Exceeding this depth will result in
-a Default: 10 Maximum depth for nested configurations. This property sets a limit on how deeply nested configurations
+can be processed by the flattening logic. Exceeding this depth
+will result ina Default: 3 Constructor. Initializes the configuration manager with optional defaults. Default path for config files (optional). Optional path for configuration files. Adds or updates a configuration value. If the key contains dots, indicating a grouped or flattened list,
-the method ensures the group and config data are updated accordingly. Optimized to ensure group structures are maintained efficiently. Clears all configuration data. Clears the configuration manager. Deletes a configuration key or group. If the provided key corresponds to a group, all keys in that group
-will be removed from the configuration array before the group itself
-is deleted. Removes a specific key or group from the configuration. If the key represents
+a group, all associated keys within the group will also be removed. Deletes a cache file. The file path of the cache to delete. Path to cache. True if the cache was deleted successfully, false otherwise. True if deleted. Retrieves configuration from a file. Retrieves a configuration value. Retrieves the entire configuration array. Retrieves all configuration groups. Checks if a specific configuration key exists. This method first checks if the key exists in the main configuration.
-If not, it then checks whether the key corresponds to a group in the grouped configurations. The configuration key to check. The key to check. True if the key or group exists; otherwise, false. True if the key exists, false otherwise. Checks if the configuration cache has been loaded. True if the cache has been loaded, false otherwise. True if the cache has been loaded; otherwise, false. Loads configuration data from a file. Reads the specified file, parses its contents, and merges
-the data into the existing configuration. When flattening is enabled,
-keys are grouped by the file's base name to create unique keys. If a key
-already exists, it will be overwritten. Reads the specified file, parses its contents, and merges the data
+into the existing configuration. If the cache is already loaded,
+this method skips further processing. Absolute or relative path to the file. The file path or name (optional). Loads the configuration and groups from a cache file. Loads configuration and groups from a cache file. The file path of the cache. Path to the cache file. True if the cache was loaded successfully; otherwise, false. Loads configuration data from a stream (e.g., PSR-7 StreamInterface). A PSR-7 compatible stream. True if the cache was loaded successfully, false otherwise. True if the configuration was successfully loaded. Loads configuration data from multiple files. List of file paths. Merges new configuration data into the existing configuration. The new configuration data. Resets the configuration groups to an empty state. Saves the configuration and groups data to a cache file. Saves the current configuration to a cache file. The file path to save the cache. File path to save cache. Expiration time in seconds (0 for no expiration). Expiration time (0 for no expiration). True if the cache was saved successfully, false otherwise. True if successful; otherwise, false. Sets the configuration directory path. If the path is invalid. If the provided path is invalid. Enables or disables key flattening. Sets the maximum depth for nested configurations. Inserts configuration data into the manager. Parses a configuration file. Flattens a multidimensional array into dot-notated keys and groups. Flattens a nested configuration array. This method recursively processes a nested array, converting its keys
-into dot-notated strings for flattened storage. It tracks the current
-depth to ensure the nesting does not exceed the configured Converts nested arrays into dot-notated keys. The input array to flatten. The base key for flattening, used for constructing
-dot-notated keys. The current depth of the recursion, used to enforce
-the maximum depth constraint (default: 0). The base key for flattening. An array containing two elements: Resolves the full file path. Validates the structure of configuration and group data. The configuration data. The groups data. ConfigParserFactory Factory class for creating and managing configuration parsers. Supports default parsers
-for common file formats such as JSON, PHP, and XML, and allows custom parsers to be registered. Factory class for creating and managing configuration parsers.
+Supports default parsers for common file formats such as conf,
+ini, json, PHP, xml, yaml/yml, and allows custom parsers to be
+registered. Default mapping of file extensions to parser class names. Creates a parser instance based on the file's extension. Retrieves the list of all registered parsers. Bulk registers parsers from an associative array. Registers a custom parser, allowing users to extend or override default parsers. Unregisters a parser for a specific file extension. ConfigException Constructs a new ConfigException instance. Returns a string representation of the exception. ConfigParseException Constructs a new ConfigParseException instance. Provides a string representation of the exception. InvalidParserException Constructs a new InvalidParserException. Provides a string representation of the exception. ConfParser Parses key-value pairs from CONF configuration files. This parser supports
-flexible key-value syntax with either
+
@@ -405,6 +454,38 @@
= 86400
: array<string, mixed>
: array<string, array<string, string>>
: void
: bool
+ EXPIRE_HALF_DAY
+
+
+
+
+
+
+
+
+
+ public
+ mixed
+ EXPIRE_HALF_DAY
+ = 43200
+
+
+
+
+
+
+
+
+
+
EXPIRE_NEVER
@@ -414,9 +495,9 @@
@@ -468,6 +549,38 @@
+
+ EXPIRE_ONE_HOUR
+
+
+
+
+
+
+
+
+
+ public
+ mixed
+ EXPIRE_ONE_HOUR
+ = 3600
+
+
+
+
+
+
+
+
+
@@ -479,9 +592,9 @@
@@ -511,9 +624,9 @@
@@ -559,9 +672,9 @@
-
@@ -611,10 +725,7 @@
-
$config
= []
-
@@ -728,10 +840,7 @@
-
$groups
= []
private
int
$maxDepth
- = 10
-
-
ConfigException
being thrown to prevent performance degradation and
-manageability issues.ConfigException
being thrown to prevent
+performance degradation and manageability issues.
Parameters
+ Parameters
: string|null
= null
Parameters
@@ -923,12 +1031,12 @@
-
public
@@ -959,9 +1067,9 @@
Parameters
@@ -992,6 +1099,23 @@ Parameters
+ Tags
+
+
+
+
@@ -1011,9 +1135,9 @@
Parameters
: string
Parameters
Return values
bool
—
-
Parameters
+
+
+ Parameters
: string
Parameters
Return values
bool
—
-
Return values
bool
—
-
Parameters
@@ -1406,7 +1526,7 @@ Parameters
: string|null
= null
-
public
@@ -1479,13 +1599,103 @@
Parameters
: string
+ Tags
+
+
+
+
+
+
+
+ Return values
+ bool
+ —
+
+ loadFromStream()
+
+
+
+
+
+
+ public
+ loadFromStream(StreamInterface $stream) : bool
+
+ Parameters
+
+
+
+ Tags
+
+
+
+
@@ -1493,11 +1703,160 @@ Parameters
Return values
bool
—
-
+ loadMultiple()
+
+
+
+
+
+
+ public
+ loadMultiple(array<string|int, string> $filePaths) : void
+
+ Parameters
+
+
+
+
+
+ Tags
+
+
+
+
+
+
+
+
+
+ mergeConfig()
+
+
+
+
+
+
+ public
+ mergeConfig(array<string, mixed> $newConfig) : void
+
+ Parameters
+
+
+
+
+
+
+
+
+
+ resetGroups()
+
+
+
+
+
+
+ public
+ resetGroups() : void
+
+
public
@@ -1535,7 +1894,7 @@
Parameters
: string
Parameters
: int
= 0
Parameters
Return values
bool
—
-
-
private
- flattenArray(array<string|int, mixed> $data, string $baseKey[, int $currentDepth = 0 ]) : array<string|int, mixed>
+ flattenArray(array<string, mixed> $data, string $baseKey) : array<string, mixed>$maxDepth
.
-If the maximum depth is exceeded, a ConfigException
is thrown.Parameters
Parameters
: string
@@ -1962,15 +2307,7 @@
Return values
- array<string|int, mixed>
- —
-
-
-
Return values
+
+
+ validateConfigStructure()
+
+
+
+
+
+
+ private
+ validateConfigStructure(array<string|int, mixed> $config, array<string|int, mixed> $groups) : void
+
+ Parameters
+
+
+
+
+
+ Tags
+
+
+
+
+
+
+
+
Return values
Return values
Return values
:
or =
as separators.=
as the separator. It skips comments and empty lines
+and trims whitespace while preserving inner spaces.
Parses a CONF configuration file into an associative array.
@@ -232,10 +233,8 @@The method reads key-value pairs from the file, where keys and values are separated
-by either :
or =
. Leading and trailing whitespace is trimmed for both keys and values.
Example:
-host: localhost
+ Example:
+host = localhost
user = root
@@ -298,9 +297,9 @@
Converts string values to their respective PHP scalar types where applicable.
diff --git a/docs/php/classes/JG-Config-Parsers-IniParser.html b/docs/php/classes/JG-Config-Parsers-IniParser.html
index 2ba2cb8..93eb6fb 100644
--- a/docs/php/classes/JG-Config-Parsers-IniParser.html
+++ b/docs/php/classes/JG-Config-Parsers-IniParser.html
@@ -130,9 +130,9 @@
IniParser
@@ -211,9 +211,9 @@
Parses an INI file and returns its contents as an associative array.
diff --git a/docs/php/classes/JG-Config-Parsers-JsonParser.html b/docs/php/classes/JG-Config-Parsers-JsonParser.html
index a1a08d1..728f547 100644
--- a/docs/php/classes/JG-Config-Parsers-JsonParser.html
+++ b/docs/php/classes/JG-Config-Parsers-JsonParser.html
@@ -130,9 +130,9 @@
JsonParser
@@ -211,9 +211,9 @@
Parses a JSON configuration file and returns its contents as an associative array.
diff --git a/docs/php/classes/JG-Config-Parsers-ParserInterface.html b/docs/php/classes/JG-Config-Parsers-ParserInterface.html
index 4218d3c..8310e7e 100644
--- a/docs/php/classes/JG-Config-Parsers-ParserInterface.html
+++ b/docs/php/classes/JG-Config-Parsers-ParserInterface.html
@@ -118,9 +118,9 @@
ParserInterface
@@ -193,9 +193,9 @@
Parses a configuration file and returns its contents as an associative array.
diff --git a/docs/php/classes/JG-Config-Parsers-PhpParser.html b/docs/php/classes/JG-Config-Parsers-PhpParser.html
index 0887cff..6c10df0 100644
--- a/docs/php/classes/JG-Config-Parsers-PhpParser.html
+++ b/docs/php/classes/JG-Config-Parsers-PhpParser.html
@@ -130,9 +130,9 @@
PhpParser
@@ -211,9 +211,9 @@
Parses a PHP configuration file and returns its contents as an array.
diff --git a/docs/php/classes/JG-Config-Parsers-XmlParser.html b/docs/php/classes/JG-Config-Parsers-XmlParser.html
index 08e9ee5..6ca9b40 100644
--- a/docs/php/classes/JG-Config-Parsers-XmlParser.html
+++ b/docs/php/classes/JG-Config-Parsers-XmlParser.html
@@ -130,9 +130,9 @@
XmlParser
@@ -232,9 +232,9 @@
Parses an XML configuration file and returns its contents as an associative array.
@@ -305,9 +305,9 @@
Converts a `SimpleXMLElement` object into an associative array or scalar value.
@@ -361,9 +361,9 @@
Handles XML parsing errors by throwing an exception with detailed information.
@@ -426,9 +426,9 @@
Converts string values to their respective PHP scalar types where applicable.
diff --git a/docs/php/classes/JG-Config-Parsers-YamlParser.html b/docs/php/classes/JG-Config-Parsers-YamlParser.html
index a994771..4f8f9a6 100644
--- a/docs/php/classes/JG-Config-Parsers-YamlParser.html
+++ b/docs/php/classes/JG-Config-Parsers-YamlParser.html
@@ -130,9 +130,9 @@
YamlParser
@@ -234,9 +234,9 @@
Parses a YAML configuration file and returns its contents as an associative array.
diff --git a/docs/php/files/src-config.html b/docs/php/files/src-config.html
index 1f8a7a8..8c67ed5 100644
--- a/docs/php/files/src-config.html
+++ b/docs/php/files/src-config.html
@@ -107,7 +107,7 @@ Config.php
The core configuration management class.
Provides methods to load, parse, and manage configuration data from
-various sources, including JSON, YAML, XML, and more.
+various sources, including conf, ini, json, yaml/yml, xml, and more.
PHP version 8.2
@@ -125,6 +125,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-configparserfactory.html b/docs/php/files/src-configparserfactory.html
index a3b617a..f4cd2ef 100644
--- a/docs/php/files/src-configparserfactory.html
+++ b/docs/php/files/src-configparserfactory.html
@@ -105,8 +105,9 @@ ConfigParserFactory.php
ConfigParserFactory.php
- Factory class for creating and managing configuration parsers based on file extensions.
-Allows registration of custom parsers and overrides for default parsers.
+ Factory class for creating and managing configuration parsers
+based on file extensions. Allows registration of custom parsers
+and overrides for default parsers.
PHP version 8.2
@@ -124,6 +125,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-exceptions-configexception.html b/docs/php/files/src-exceptions-configexception.html
index 471aa78..03c8bc1 100644
--- a/docs/php/files/src-exceptions-configexception.html
+++ b/docs/php/files/src-exceptions-configexception.html
@@ -124,6 +124,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-exceptions-configparseexception.html b/docs/php/files/src-exceptions-configparseexception.html
index 9f547ee..d96da64 100644
--- a/docs/php/files/src-exceptions-configparseexception.html
+++ b/docs/php/files/src-exceptions-configparseexception.html
@@ -123,6 +123,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-exceptions-invalidparserexception.html b/docs/php/files/src-exceptions-invalidparserexception.html
index b47c54d..be5c19f 100644
--- a/docs/php/files/src-exceptions-invalidparserexception.html
+++ b/docs/php/files/src-exceptions-invalidparserexception.html
@@ -123,6 +123,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-parsers-confparser.html b/docs/php/files/src-parsers-confparser.html
index cda16be..056315e 100644
--- a/docs/php/files/src-parsers-confparser.html
+++ b/docs/php/files/src-parsers-confparser.html
@@ -106,7 +106,7 @@ ConfParser.php
Parses key-value pairs from custom CONF configuration files. These files
-typically use :
or =
as separators for key-value pairs.
+typically use =
as the separator for key-value pairs.
PHP version 8.2
@@ -124,6 +124,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-parsers-iniparser.html b/docs/php/files/src-parsers-iniparser.html
index dbb4611..c895f81 100644
--- a/docs/php/files/src-parsers-iniparser.html
+++ b/docs/php/files/src-parsers-iniparser.html
@@ -123,6 +123,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-parsers-jsonparser.html b/docs/php/files/src-parsers-jsonparser.html
index 21fa05a..b92cf48 100644
--- a/docs/php/files/src-parsers-jsonparser.html
+++ b/docs/php/files/src-parsers-jsonparser.html
@@ -124,6 +124,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-parsers-parserinterface.html b/docs/php/files/src-parsers-parserinterface.html
index 682b4cb..8434517 100644
--- a/docs/php/files/src-parsers-parserinterface.html
+++ b/docs/php/files/src-parsers-parserinterface.html
@@ -125,6 +125,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-parsers-phpparser.html b/docs/php/files/src-parsers-phpparser.html
index 8671d82..2b673d5 100644
--- a/docs/php/files/src-parsers-phpparser.html
+++ b/docs/php/files/src-parsers-phpparser.html
@@ -124,6 +124,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-parsers-xmlparser.html b/docs/php/files/src-parsers-xmlparser.html
index 80bc1e7..735d068 100644
--- a/docs/php/files/src-parsers-xmlparser.html
+++ b/docs/php/files/src-parsers-xmlparser.html
@@ -124,6 +124,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src-parsers-yamlparser.html b/docs/php/files/src-parsers-yamlparser.html
index 898938b..6f158a8 100644
--- a/docs/php/files/src-parsers-yamlparser.html
+++ b/docs/php/files/src-parsers-yamlparser.html
@@ -123,6 +123,14 @@
1.0.0
+
+
+ since
+
+
+ 1.0.0
+
+
author
diff --git a/docs/php/files/src/Config.php.txt b/docs/php/files/src/Config.php.txt
index 6666c23..eab7da6 100644
--- a/docs/php/files/src/Config.php.txt
+++ b/docs/php/files/src/Config.php.txt
@@ -4,36 +4,42 @@
*
* The core configuration management class.
* Provides methods to load, parse, and manage configuration data from
- * various sources, including JSON, YAML, XML, and more.
+ * various sources, including conf, ini, json, yaml/yml, xml, and more.
*
* PHP version 8.2
*
* @package JG\Config
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
* @copyright 2024 James Gober (https://jamesgober.com)
- */
+*/
declare(strict_types=1);
namespace JG\Config;
use \ltrim;
+use \mkdir;
use \rtrim;
use \is_dir;
-use \strtok;
-use \explode;
-use \implode;
+use \unlink;
use \is_file;
+use \is_array;
use \strtolower;
use \array_merge;
use \array_shift;
+use \json_decode;
+use \json_encode;
use \preg_replace;
-use \str_contains;
use \array_key_exists;
-use \JG\Config\ConfigParserFactory;
-use \JG\Config\Exceptions\ConfigException;
+use \file_put_contents;
+use \JSON_PRETTY_PRINT;
+use \JSON_THROW_ON_ERROR;
+use JG\Config\ConfigParserFactory;
+use Psr\Http\Message\StreamInterface;
+use JG\Config\Exceptions\ConfigException;
/**
* Configuration Manager
@@ -46,73 +52,71 @@ use \JG\Config\Exceptions\ConfigException;
*/
class Config
{
- /**
- * Common expiration durations in seconds.
- */
- public const EXPIRE_NEVER = 0;
- public const EXPIRE_ONE_DAY = 86400;
- public const EXPIRE_ONE_WEEK = 604800;
+ /** Common expiration durations in seconds. */
+ public const EXPIRE_NEVER = 0;
+ public const EXPIRE_ONE_HOUR = 3600;
+ public const EXPIRE_HALF_DAY = 43200;
+ public const EXPIRE_ONE_DAY = 86400;
+ public const EXPIRE_ONE_WEEK = 604800;
public const EXPIRE_ONE_MONTH = 2592000;
/**
* Default configuration directory path.
*
- * @var string|null
+ * @var string|null $configPath
*/
private ?string $configPath = null;
/**
* Whether configuration keys should be flattened.
*
- * @var bool
+ * @var bool $flatten
*/
private bool $flatten = true;
/**
* Maximum allowed depth for nested configurations.
*
- * This property sets a limit on how deeply nested configurations can be
- * processed by the flattening logic. Exceeding this depth will result in
- * a `ConfigException` being thrown to prevent performance degradation and
- * manageability issues.
+ * This property sets a limit on how deeply nested configurations
+ * can be processed by the flattening logic. Exceeding this depth
+ * will result ina `ConfigException` being thrown to prevent
+ * performance degradation and manageability issues.
*
- * Default: 10
+ * Default: 3
*
- * @var int Maximum depth for nested configurations.
+ * @var int $maxDepth
*/
- private int $maxDepth = 10;
+ private int $maxDepth = 3;
/**
* Indicates whether the configuration cache has been loaded.
*
- * @var bool
+ * @var bool$cacheLoaded
*/
private bool $cacheLoaded = false;
/**
- * Grouped configuration storage.
- *
- * Stores configurations by groups, allowing access by original
- * source filename or unique key.
+ * Grouped configuration storage, allowing access by group or
+ * unique key.
*
- * @var array>
+ * @var array> $groups
*/
private array $groups = [];
/**
- * Primary configuration storage.
+ * Primary configuration storage, including unique keys from
+ * grouped configurations.
*
- * Stores all configuration key-value pairs, including unique keys
- * generated from grouped configurations.
- *
- * @var array
+ * @var array $config
*/
private array $config = [];
/**
* Constructor.
*
- * @param string|null $configPath Default path for config files (optional).
+ * Initializes the configuration manager with optional defaults.
+ *
+ * @param string|null $configPath Optional path for configuration files.
* @param bool $flattenConfig Whether to enable key flattening (default: true).
*/
public function __construct(?string $configPath = null, bool $flattenConfig = true)
@@ -127,7 +131,7 @@ class Config
* @param string|null $path Absolute or relative path to the config directory.
* @return void
*
- * @throws ConfigException If the path is invalid.
+ * @throws ConfigException If the provided path is invalid.
*/
public function setConfigPath(?string $path = null): void
{
@@ -153,6 +157,7 @@ class Config
*
* @param int $depth Maximum depth to allow.
* @return void
+ *
* @throws ConfigException If the depth is less than 1.
*/
public function setMaxDepth(int $depth): void
@@ -166,7 +171,7 @@ class Config
/**
* Checks if the configuration cache has been loaded.
*
- * @return bool True if the cache has been loaded, false otherwise.
+ * @return bool True if the cache has been loaded; otherwise, false.
*/
public function isCacheLoaded(): bool
{
@@ -181,15 +186,11 @@ class Config
*/
private function resolvePath(?string $filePath): ?string
{
- if (!$filePath) {
+ if (!$filePath || (!is_file($filePath) && !$this->configPath)) {
return null;
}
- if (is_file($filePath)) {
- return $filePath;
- }
-
- return $this->configPath ? $this->configPath . ltrim($filePath, '/') : null;
+ return is_file($filePath) ? $filePath : $this->configPath . ltrim($filePath, '/');
}
/**
@@ -206,46 +207,53 @@ class Config
}
/**
- * Flattens a multidimensional array into dot-notated keys and groups.
+ * Merges new configuration data into the existing configuration.
*
- * This method recursively processes a nested array, converting its keys
- * into dot-notated strings for flattened storage. It tracks the current
- * depth to ensure the nesting does not exceed the configured `$maxDepth`.
- * If the maximum depth is exceeded, a `ConfigException` is thrown.
+ * @param array $newConfig The new configuration data.
+ * @return void
+ */
+ public function mergeConfig(array $newConfig): void
+ {
+ $this->config = array_merge($this->config, $newConfig);
+ }
+
+ /**
+ * Flattens a nested configuration array.
*
- * @param array $data The input array to flatten.
- * @param string $baseKey The base key for flattening, used for constructing
- * dot-notated keys.
- * @param int $currentDepth The current depth of the recursion, used to enforce
- * the maximum depth constraint (default: 0).
- *
- * @return array An array containing two elements:
- * - The first element is an associative array of flattened key-value pairs.
- * - The second element is an associative array of flattened key mappings to original keys.
+ * Converts nested arrays into dot-notated keys.
+ *
+ * @param array $data The input array to flatten.
+ * @param string $baseKey The base key for flattening.
+ * @param int $depth Current depth of the flattening process.
+ * @return array
*
- * @throws ConfigException If the maximum depth for nested configurations is exceeded.
+ * @throws ConfigException If the maximum depth is exceeded.
*/
- private function flattenArray(array $data, string $baseKey, int $currentDepth = 0): array
+ private function flattenArray(array $data, string $baseKey): array
{
- if ($currentDepth > $this->maxDepth) {
- throw new ConfigException(
- "Maximum depth of {$this->maxDepth} exceeded while processing configuration."
- );
- }
-
$flattenedData = [];
$groups = [];
+ $stack = [['data' => $data, 'key' => $baseKey, 'depth' => 0]];
+
+ while ($stack) {
+ $current = array_pop($stack);
+ $currentData = $current['data'];
+ $currentKey = $current['key'];
+ $currentDepth = $current['depth'];
+
+ if ($currentDepth >= $this->maxDepth) { // Correctly handle "max depth exceeded"
+ throw new ConfigException("Maximum depth of {$this->maxDepth} exceeded at key: {$currentKey}");
+ }
- foreach ($data as $key => $value) {
- $fullKey = "{$baseKey}.{$key}";
+ foreach ($currentData as $key => $value) {
+ $fullKey = "{$currentKey}.{$key}";
- if (is_array($value)) {
- [$nestedFlattened, $nestedGroups] = $this->flattenArray($value, $fullKey, $currentDepth + 1);
- $flattenedData = array_merge($flattenedData, $nestedFlattened);
- $groups = array_merge($groups, $nestedGroups);
- } else {
- $flattenedData[$fullKey] = $value;
- $groups[$fullKey] = $key;
+ if (is_array($value)) {
+ $stack[] = ['data' => $value, 'key' => $fullKey, 'depth' => $currentDepth + 1];
+ } else {
+ $flattenedData[$fullKey] = $value;
+ $groups[$fullKey] = $key;
+ }
}
}
@@ -255,40 +263,75 @@ class Config
/**
* Loads configuration data from a file.
*
- * Reads the specified file, parses its contents, and merges
- * the data into the existing configuration. When flattening is enabled,
- * keys are grouped by the file's base name to create unique keys. If a key
- * already exists, it will be overwritten.
+ * Reads the specified file, parses its contents, and merges the data
+ * into the existing configuration. If the cache is already loaded,
+ * this method skips further processing.
*
- * @param string|null $filePath Absolute or relative path to the file.
+ * @param string|null $filePath The file path or name (optional).
* @return bool True if the configuration was successfully loaded.
+ *
* @throws ConfigException If the file cannot be found or parsed.
*/
public function load(?string $filePath = null): bool
{
+ if ($this->isCacheLoaded()) {
+ return true;
+ }
+
$filePath = $this->resolvePath($filePath);
+
if (!$filePath || !is_file($filePath)) {
throw new ConfigException("Configuration file not found: {$filePath}");
}
-
- // Parse the configuration file
+
$parsedData = $this->parse($filePath);
- if ($parsedData === null) {
- throw new ConfigException("Failed to parse configuration file: {$filePath}");
+ if (!is_array($parsedData)) {
+ throw new ConfigException("Invalid configuration format in file: {$filePath}. Expected an array.");
}
-
+
if ($this->flatten) {
- // Flatten the configuration data
- $baseName = strtolower(preg_replace('/\.[^.]+$/', '', basename($filePath)));
+ $baseName = strtolower(pathinfo($filePath, PATHINFO_FILENAME));
[$flattenedData, $groups] = $this->flattenArray($parsedData, $baseName);
-
- // Insert the flattened data
$this->insert($flattenedData, [$baseName => $groups]);
- return true;
+ } else {
+ $this->insert($parsedData);
}
- // Insert non-flattened data
- $this->insert($parsedData);
+ return true;
+ }
+
+ /**
+ * Loads configuration data from multiple files.
+ *
+ * @param array $filePaths List of file paths.
+ * @return void
+ *
+ * @throws ConfigException If any file cannot be loaded or parsed.
+ */
+ public function loadMultiple(array $filePaths): void
+ {
+ foreach ($filePaths as $filePath) {
+ $this->load($filePath);
+ }
+ }
+
+ /**
+ * Loads configuration data from a stream (e.g., PSR-7 StreamInterface).
+ *
+ * @param StreamInterface $stream A PSR-7 compatible stream.
+ * @return bool True if the configuration was successfully loaded.
+ *
+ * @throws ConfigException If the stream cannot be parsed.
+ */
+ public function loadFromStream(StreamInterface $stream): bool
+ {
+ $data = json_decode($stream->getContents(), true, 512, JSON_THROW_ON_ERROR);
+
+ if (!is_array($data)) {
+ throw new ConfigException("Failed to parse configuration stream.");
+ }
+
+ $this->insert($data);
return true;
}
@@ -303,16 +346,26 @@ class Config
protected function parse(?string $filePath = null): ?array
{
$filePath = $this->resolvePath($filePath);
-
+
if (!$filePath || !is_file($filePath)) {
throw new ConfigException("Configuration file not found: {$filePath}");
}
-
+
+ $contents = file_get_contents($filePath);
+ if ($contents === false) {
+ throw new ConfigException("Failed to read configuration file: {$filePath}");
+ }
+
+ // Validate UTF-8 encoding
+ if (!mb_check_encoding($contents, 'UTF-8')) {
+ throw new ConfigException("File encoding must be UTF-8: {$filePath}");
+ }
+
$parser = ConfigParserFactory::createParser($filePath);
if (!$parser) {
throw new ConfigException("No suitable parser found for: {$filePath}");
}
-
+
return $parser->parse($filePath);
}
@@ -328,30 +381,36 @@ class Config
}
/**
- * Checks if a specific configuration key exists.
+ * Validates the structure of configuration and group data.
*
- * This method first checks if the key exists in the main configuration.
- * If not, it then checks whether the key corresponds to a group in the grouped configurations.
- *
- * @param string $key The configuration key to check.
- * @return bool True if the key or group exists; otherwise, false.
+ * @param array $config The configuration data.
+ * @param array $groups The groups data.
+ * @return void
+ *
+ * @throws ConfigException If the structures are invalid.
*/
- public function has(string $key): bool
+ private function validateConfigStructure(array $config, array $groups): void
{
- // Check if the key exists in the main configuration array
- if (array_key_exists($key, $this->config)) {
- return true;
+ if (!is_array($config) || !is_array($groups)) {
+ throw new ConfigException("Invalid configuration structure: Both 'config' and 'groups' must be arrays.");
}
+ }
- // Check if the key exists as a group
- return array_key_exists($key, $this->groups);
+ /**
+ * Checks if a specific configuration key exists.
+ *
+ * @param string $key The key to check.
+ * @return bool True if the key exists, false otherwise.
+ */
+ public function has(string $key): bool
+ {
+ return array_key_exists($key, $this->config) || array_key_exists($key, $this->groups);
}
/**
* Adds or updates a configuration value.
*
- * If the key contains dots, indicating a grouped or flattened list,
- * the method ensures the group and config data are updated accordingly.
+ * Optimized to ensure group structures are maintained efficiently.
*
* @param string $key The configuration key (supports dot notation for groups).
* @param mixed $value The configuration value.
@@ -359,17 +418,19 @@ class Config
*/
public function add(string $key, mixed $value): void
{
- // Add to config
$this->config[$key] = $value;
// If the key is dot-notated, update the group
if (str_contains($key, '.')) {
$parts = explode('.', $key);
$group = array_shift($parts);
- $subKey = implode('.', $parts);
- // Ensure the group exists
- $this->groups[$group][$key] = $subKey;
+ // Avoid redundant structure initialization
+ if (!isset($this->groups[$group])) {
+ $this->groups[$group] = [];
+ }
+
+ $this->groups[$group][$key] = implode('.', $parts);
}
}
@@ -388,25 +449,32 @@ class Config
/**
* Deletes a configuration key or group.
*
- * If the provided key corresponds to a group, all keys in that group
- * will be removed from the configuration array before the group itself
- * is deleted.
+ * Removes a specific key or group from the configuration. If the key represents
+ * a group, all associated keys within the group will also be removed.
*
* @param string $key The key or group to delete.
* @return void
+ *
+ * @throws ConfigException If the group structure is invalid.
*/
public function delete(string $key): void
{
+ // Validate group structure if the key is in groups
if (isset($this->groups[$key])) {
- // Delete all group keys from config
+ if (!is_array($this->groups[$key])) {
+ throw new ConfigException("Invalid group structure for key: {$key}. Expected an array.");
+ }
+
+ // Remove all keys in the group
foreach ($this->groups[$key] as $fullKey => $subKey) {
unset($this->config[$fullKey]);
}
+
unset($this->groups[$key]);
return;
}
-
- // Delete single key
+
+ // Remove single key
unset($this->config[$key]);
}
@@ -431,73 +499,89 @@ class Config
}
/**
- * Saves the configuration and groups data to a cache file.
+ * Resets the configuration groups to an empty state.
+ *
+ * @return void
+ */
+ public function resetGroups(): void
+ {
+ $this->groups = [];
+ }
+
+ /**
+ * Saves the current configuration to a cache file.
*
- * @param string $filePath The file path to save the cache.
- * @param int $expires Expiration time in seconds (0 for no expiration).
- * @return bool True if the cache was saved successfully, false otherwise.
+ * @param string $filePath File path to save cache.
+ * @param int $expires Expiration time (0 for no expiration).
+ * @return bool True if successful; otherwise, false.
*/
public function saveCache(string $filePath, int $expires = 0): bool
{
- // Check if the file is writable or can be created
+ if (!is_array($this->config) || !is_array($this->groups)) {
+ throw new ConfigException("Cannot save cache: 'config' and 'groups' must be arrays.");
+ }
+
$dir = dirname($filePath);
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
return false;
}
- if (is_file($filePath) && !is_writable($filePath)) {
- return false;
- }
- $cache = [
+ $data = [
'config' => $this->config,
'groups' => $this->groups,
- 'expires' => $expires > 0 ? time() + $expires : false,
+ 'expires' => $expires ? time() + $expires : 0,
];
- $json = json_encode($cache, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
-
- return file_put_contents($filePath, $json) !== false;
+ return file_put_contents($filePath, json_encode($data, JSON_PRETTY_PRINT)) !== false;
}
/**
- * Loads the configuration and groups from a cache file.
+ * Loads configuration and groups from a cache file.
*
- * @param string $filePath The file path of the cache.
- * @return bool True if the cache was loaded successfully, false otherwise.
+ * @param string $filePath Path to the cache file.
+ * @return bool True if the cache was loaded successfully; otherwise, false.
+ *
+ * @throws ConfigException If the cache format is invalid.
*/
public function loadCache(string $filePath): bool
{
if ($this->cacheLoaded) {
return true;
}
-
+
if (!is_file($filePath) || !is_readable($filePath)) {
return false;
}
-
- $data = json_decode(file_get_contents($filePath), true, 512, JSON_THROW_ON_ERROR);
-
- if (!is_array($data) || !isset($data['config'], $data['groups'], $data['expires'])) {
+
+ try {
+ $data = json_decode(file_get_contents($filePath), true, 512, JSON_THROW_ON_ERROR);
+ } catch (\JsonException $e) {
+ unlink($filePath); // Cleanup malformed cache
return false;
}
-
- if ($data['expires'] && time() > $data['expires']) {
+
+ if (!isset($data['config'], $data['groups']) || !is_array($data['config']) || !is_array($data['groups'])) {
+ unlink($filePath); // Cleanup malformed cache
+ throw new ConfigException("Invalid cache format: 'config' and 'groups' must be arrays.");
+ }
+
+ if (isset($data['expires']) && $data['expires'] > 0 && time() > $data['expires']) {
$this->deleteCache($filePath);
return false;
}
-
+
$this->config = $data['config'];
$this->groups = $data['groups'];
$this->cacheLoaded = true;
-
+
return true;
}
/**
* Deletes a cache file.
*
- * @param string $filePath The file path of the cache to delete.
- * @return bool True if the cache was deleted successfully, false otherwise.
+ * @param string $filePath Path to cache.
+ * @return bool True if deleted.
*/
public function deleteCache(string $filePath): bool
{
@@ -505,13 +589,11 @@ class Config
}
/**
- * Clears all configuration data.
- *
- * @return void
+ * Clears the configuration manager.
*/
public function clear(): void
{
- $this->config = [];
- $this->groups = [];
+ $this->groups = $this->config = [];
+ $this->cacheLoaded = false;
}
}
\ No newline at end of file
diff --git a/docs/php/files/src/ConfigParserFactory.php.txt b/docs/php/files/src/ConfigParserFactory.php.txt
index 0b50fd7..842f25f 100644
--- a/docs/php/files/src/ConfigParserFactory.php.txt
+++ b/docs/php/files/src/ConfigParserFactory.php.txt
@@ -2,13 +2,15 @@
/**
* ConfigParserFactory.php
*
- * Factory class for creating and managing configuration parsers based on file extensions.
- * Allows registration of custom parsers and overrides for default parsers.
+ * Factory class for creating and managing configuration parsers
+ * based on file extensions. Allows registration of custom parsers
+ * and overrides for default parsers.
*
* PHP version 8.2
*
* @package JG\Config
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
@@ -29,8 +31,10 @@ use JG\Config\Exceptions\InvalidParserException;
/**
* ConfigParserFactory
*
- * Factory class for creating and managing configuration parsers. Supports default parsers
- * for common file formats such as JSON, PHP, and XML, and allows custom parsers to be registered.
+ * Factory class for creating and managing configuration parsers.
+ * Supports default parsers for common file formats such as conf,
+ * ini, json, PHP, xml, yaml/yml, and allows custom parsers to be
+ * registered.
*
* @package JG\Config
*/
@@ -72,7 +76,7 @@ class ConfigParserFactory
}
throw new InvalidParserException(
- "No suitable parser found for file extension: .$extension"
+ "No suitable parser found for file extension: .$extension. File: $filePath"
);
}
@@ -81,21 +85,34 @@ class ConfigParserFactory
*
* @param string $extension The file extension for the parser (e.g., 'yaml').
* @param class-string $parserClass Fully qualified class name of the parser,
- * must implement ParserInterface.
+ * must implement ParserInterface.
* @return void
* @throws InvalidParserException If the class does not implement the required interface.
*/
public static function registerParser(string $extension, string $parserClass): void
{
- // Validate that the class implements ParserInterface
+ $extension = strtolower(ltrim($extension, '.'));
+
+ if (empty($extension)) {
+ throw new InvalidParserException("File extension cannot be empty.");
+ }
+ // Validate and instantiate the parser class
+ if ($parserClass && is_a($parserClass, ParserInterface::class, true)) {
+ self::$configParsers[$extension] = $parserClass;
+ return;
+ }
+
if (!is_a($parserClass, ParserInterface::class, true)) {
throw new InvalidParserException(
"Parser class '{$parserClass}' must implement ParserInterface."
);
}
- // Sanitize the extension and register the parser
- $extension = strtolower(ltrim($extension, '.'));
+ // Optional: prevent duplicate registration unless overwriting
+ if (isset(self::$configParsers[$extension])) {
+ throw new InvalidParserException("Parser for extension '{$extension}' is already registered.");
+ }
+
self::$configParsers[$extension] = $parserClass;
}
@@ -133,10 +150,16 @@ class ConfigParserFactory
public static function unregisterParser(string $extension): bool
{
$extension = strtolower(ltrim($extension, '.'));
+
+ if (empty($extension)) {
+ return false;
+ }
+
if (isset(self::$configParsers[$extension])) {
unset(self::$configParsers[$extension]);
return true;
}
+
return false;
}
}
\ No newline at end of file
diff --git a/docs/php/files/src/Exceptions/ConfigException.php.txt b/docs/php/files/src/Exceptions/ConfigException.php.txt
index e74f864..5cf3e7e 100644
--- a/docs/php/files/src/Exceptions/ConfigException.php.txt
+++ b/docs/php/files/src/Exceptions/ConfigException.php.txt
@@ -9,6 +9,7 @@
*
* @package JG\Config\Exceptions
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Exceptions/ConfigParseException.php.txt b/docs/php/files/src/Exceptions/ConfigParseException.php.txt
index df7065f..18aa9a1 100644
--- a/docs/php/files/src/Exceptions/ConfigParseException.php.txt
+++ b/docs/php/files/src/Exceptions/ConfigParseException.php.txt
@@ -8,6 +8,7 @@
*
* @package JG\Config\Exceptions
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Exceptions/InvalidParserException.php.txt b/docs/php/files/src/Exceptions/InvalidParserException.php.txt
index ca2dcdc..0fc660a 100644
--- a/docs/php/files/src/Exceptions/InvalidParserException.php.txt
+++ b/docs/php/files/src/Exceptions/InvalidParserException.php.txt
@@ -8,6 +8,7 @@
*
* @package JG\Config\Exceptions
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Parsers/ConfParser.php.txt b/docs/php/files/src/Parsers/ConfParser.php.txt
index 3b42dd8..cc04973 100644
--- a/docs/php/files/src/Parsers/ConfParser.php.txt
+++ b/docs/php/files/src/Parsers/ConfParser.php.txt
@@ -3,12 +3,13 @@
* ConfParser.php
*
* Parses key-value pairs from custom CONF configuration files. These files
- * typically use `:` or `=` as separators for key-value pairs.
+ * typically use `=` as the separator for key-value pairs.
*
* PHP version 8.2
*
* @package JG\Config\Parsers
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
@@ -18,19 +19,20 @@ declare(strict_types=1);
namespace JG\Config\Parsers;
+use \file;
use \trim;
-use \sprintf;
-use \is_numeric;
-use \strtolower;
-use \preg_match_all;
-use \file_get_contents;
+use \explode;
+use \is_file;
+use \preg_match;
+use \is_readable;
use \JG\Config\Exceptions\ConfigParseException;
/**
* ConfParser
*
* Parses key-value pairs from CONF configuration files. This parser supports
- * flexible key-value syntax with either `:` or `=` as separators.
+ * clean formatting with `=` as the separator. It skips comments and empty lines
+ * and trims whitespace while preserving inner spaces.
*
* @package JG\Config\Parsers
*/
@@ -39,12 +41,9 @@ class ConfParser implements ParserInterface
/**
* Parses a CONF configuration file into an associative array.
*
- * The method reads key-value pairs from the file, where keys and values are separated
- * by either `:` or `=`. Leading and trailing whitespace is trimmed for both keys and values.
- *
* Example:
* ```
- * host: localhost
+ * host = localhost
* user = root
* ```
*
@@ -58,40 +57,33 @@ class ConfParser implements ParserInterface
throw new ConfigParseException("File not found or unreadable: {$filePath}");
}
- // Attempt to retrieve the file contents
- $data = file_get_contents($filePath);
-
- if ($data === false) {
- throw new ConfigParseException(
- sprintf("Failed to read CONF configuration file: %s", $filePath)
- );
+ $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if ($lines === false) {
+ throw new ConfigParseException("Failed to read the CONF file: {$filePath}");
}
- $out = [];
+ $output = [];
- // Define regex for capturing key-value pairs with `:` or `=` as separator
- $regex = '/^(?P[a-zA-Z._\-]+[a-zA-Z0-9]*)\s*[:=]\s*(?P.*)$/m';
+ foreach ($lines as $line) {
+ $line = trim($line);
- // Process matches using the defined regex pattern
- if (preg_match_all($regex, $data, $matches, PREG_SET_ORDER)) {
- foreach ($matches as $match) {
- $key = trim($match['key']);
- $value = trim($match['value']);
+ // Skip comments
+ if (str_starts_with($line, '#') || str_starts_with($line, ';')) {
+ continue;
+ }
- // Convert scalar values (e.g., true, false, null, numbers) if applicable
- $value = $this->convertValue($value);
+ // Parse key=value pairs
+ $parts = explode('=', $line, 2);
+ if (count($parts) === 2) {
+ $key = trim($parts[0]);
+ $value = trim($parts[1]);
- if ($key !== '' && $value !== '') {
- $out[$key] = $value;
- }
+ // Convert scalar values if applicable
+ $output[$key] = $this->convertValue($value);
}
- } else {
- throw new ConfigParseException(
- sprintf("No valid key-value pairs found in CONF file: %s", $filePath)
- );
}
- return $out;
+ return $output;
}
/**
diff --git a/docs/php/files/src/Parsers/IniParser.php.txt b/docs/php/files/src/Parsers/IniParser.php.txt
index 04edfb2..7f2c0e0 100644
--- a/docs/php/files/src/Parsers/IniParser.php.txt
+++ b/docs/php/files/src/Parsers/IniParser.php.txt
@@ -8,6 +8,7 @@
*
* @package JG\Config\Parsers
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Parsers/JsonParser.php.txt b/docs/php/files/src/Parsers/JsonParser.php.txt
index 993287d..7a7743d 100644
--- a/docs/php/files/src/Parsers/JsonParser.php.txt
+++ b/docs/php/files/src/Parsers/JsonParser.php.txt
@@ -9,6 +9,7 @@
*
* @package JG\Config\Parsers
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Parsers/ParserInterface.php.txt b/docs/php/files/src/Parsers/ParserInterface.php.txt
index 835f093..de4a750 100644
--- a/docs/php/files/src/Parsers/ParserInterface.php.txt
+++ b/docs/php/files/src/Parsers/ParserInterface.php.txt
@@ -10,6 +10,7 @@
*
* @package JG\Config\Parsers
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Parsers/PhpParser.php.txt b/docs/php/files/src/Parsers/PhpParser.php.txt
index e56b88b..0f999cd 100644
--- a/docs/php/files/src/Parsers/PhpParser.php.txt
+++ b/docs/php/files/src/Parsers/PhpParser.php.txt
@@ -9,6 +9,7 @@
*
* @package JG\Config\Parsers
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Parsers/XmlParser.php.txt b/docs/php/files/src/Parsers/XmlParser.php.txt
index ff40ec9..02549e1 100644
--- a/docs/php/files/src/Parsers/XmlParser.php.txt
+++ b/docs/php/files/src/Parsers/XmlParser.php.txt
@@ -9,6 +9,7 @@
*
* @package JG\Config\Parsers
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/files/src/Parsers/YamlParser.php.txt b/docs/php/files/src/Parsers/YamlParser.php.txt
index 8553ab7..5d71ea0 100644
--- a/docs/php/files/src/Parsers/YamlParser.php.txt
+++ b/docs/php/files/src/Parsers/YamlParser.php.txt
@@ -8,6 +8,7 @@
*
* @package JG\Config\Parsers
* @version 1.0.0
+ * @since 1.0.0
* @author James Gober
* @link https://github.com/jamesgober/Config
* @license MIT License
diff --git a/docs/php/js/searchIndex.js b/docs/php/js/searchIndex.js
index 951d39a..5c3f746 100644
--- a/docs/php/js/searchIndex.js
+++ b/docs/php/js/searchIndex.js
@@ -40,16 +40,31 @@ Search.appendIndex(
"name": "insert",
"summary": "Inserts\u0020configuration\u0020data\u0020into\u0020the\u0020manager.",
"url": "classes/JG-Config-Config.html#method_insert"
+ }, {
+ "fqsen": "\\JG\\Config\\Config\u003A\u003AmergeConfig\u0028\u0029",
+ "name": "mergeConfig",
+ "summary": "Merges\u0020new\u0020configuration\u0020data\u0020into\u0020the\u0020existing\u0020configuration.",
+ "url": "classes/JG-Config-Config.html#method_mergeConfig"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003AflattenArray\u0028\u0029",
"name": "flattenArray",
- "summary": "Flattens\u0020a\u0020multidimensional\u0020array\u0020into\u0020dot\u002Dnotated\u0020keys\u0020and\u0020groups.",
+ "summary": "Flattens\u0020a\u0020nested\u0020configuration\u0020array.",
"url": "classes/JG-Config-Config.html#method_flattenArray"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003Aload\u0028\u0029",
"name": "load",
"summary": "Loads\u0020configuration\u0020data\u0020from\u0020a\u0020file.",
"url": "classes/JG-Config-Config.html#method_load"
+ }, {
+ "fqsen": "\\JG\\Config\\Config\u003A\u003AloadMultiple\u0028\u0029",
+ "name": "loadMultiple",
+ "summary": "Loads\u0020configuration\u0020data\u0020from\u0020multiple\u0020files.",
+ "url": "classes/JG-Config-Config.html#method_loadMultiple"
+ }, {
+ "fqsen": "\\JG\\Config\\Config\u003A\u003AloadFromStream\u0028\u0029",
+ "name": "loadFromStream",
+ "summary": "Loads\u0020configuration\u0020data\u0020from\u0020a\u0020stream\u0020\u0028e.g.,\u0020PSR\u002D7\u0020StreamInterface\u0029.",
+ "url": "classes/JG-Config-Config.html#method_loadFromStream"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003Aparse\u0028\u0029",
"name": "parse",
@@ -60,6 +75,11 @@ Search.appendIndex(
"name": "fetch",
"summary": "Retrieves\u0020configuration\u0020from\u0020a\u0020file.",
"url": "classes/JG-Config-Config.html#method_fetch"
+ }, {
+ "fqsen": "\\JG\\Config\\Config\u003A\u003AvalidateConfigStructure\u0028\u0029",
+ "name": "validateConfigStructure",
+ "summary": "Validates\u0020the\u0020structure\u0020of\u0020configuration\u0020and\u0020group\u0020data.",
+ "url": "classes/JG-Config-Config.html#method_validateConfigStructure"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003Ahas\u0028\u0029",
"name": "has",
@@ -90,15 +110,20 @@ Search.appendIndex(
"name": "getGroups",
"summary": "Retrieves\u0020all\u0020configuration\u0020groups.",
"url": "classes/JG-Config-Config.html#method_getGroups"
+ }, {
+ "fqsen": "\\JG\\Config\\Config\u003A\u003AresetGroups\u0028\u0029",
+ "name": "resetGroups",
+ "summary": "Resets\u0020the\u0020configuration\u0020groups\u0020to\u0020an\u0020empty\u0020state.",
+ "url": "classes/JG-Config-Config.html#method_resetGroups"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003AsaveCache\u0028\u0029",
"name": "saveCache",
- "summary": "Saves\u0020the\u0020configuration\u0020and\u0020groups\u0020data\u0020to\u0020a\u0020cache\u0020file.",
+ "summary": "Saves\u0020the\u0020current\u0020configuration\u0020to\u0020a\u0020cache\u0020file.",
"url": "classes/JG-Config-Config.html#method_saveCache"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003AloadCache\u0028\u0029",
"name": "loadCache",
- "summary": "Loads\u0020the\u0020configuration\u0020and\u0020groups\u0020from\u0020a\u0020cache\u0020file.",
+ "summary": "Loads\u0020configuration\u0020and\u0020groups\u0020from\u0020a\u0020cache\u0020file.",
"url": "classes/JG-Config-Config.html#method_loadCache"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003AdeleteCache\u0028\u0029",
@@ -108,13 +133,23 @@ Search.appendIndex(
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003Aclear\u0028\u0029",
"name": "clear",
- "summary": "Clears\u0020all\u0020configuration\u0020data.",
+ "summary": "Clears\u0020the\u0020configuration\u0020manager.",
"url": "classes/JG-Config-Config.html#method_clear"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003AEXPIRE_NEVER",
"name": "EXPIRE_NEVER",
"summary": "Common\u0020expiration\u0020durations\u0020in\u0020seconds.",
"url": "classes/JG-Config-Config.html#constant_EXPIRE_NEVER"
+ }, {
+ "fqsen": "\\JG\\Config\\Config\u003A\u003AEXPIRE_ONE_HOUR",
+ "name": "EXPIRE_ONE_HOUR",
+ "summary": "",
+ "url": "classes/JG-Config-Config.html#constant_EXPIRE_ONE_HOUR"
+ }, {
+ "fqsen": "\\JG\\Config\\Config\u003A\u003AEXPIRE_HALF_DAY",
+ "name": "EXPIRE_HALF_DAY",
+ "summary": "",
+ "url": "classes/JG-Config-Config.html#constant_EXPIRE_HALF_DAY"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003AEXPIRE_ONE_DAY",
"name": "EXPIRE_ONE_DAY",
@@ -153,12 +188,12 @@ Search.appendIndex(
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003A\u0024groups",
"name": "groups",
- "summary": "Grouped\u0020configuration\u0020storage.",
+ "summary": "Grouped\u0020configuration\u0020storage,\u0020allowing\u0020access\u0020by\u0020group\u0020or\nunique\u0020key.",
"url": "classes/JG-Config-Config.html#property_groups"
}, {
"fqsen": "\\JG\\Config\\Config\u003A\u003A\u0024config",
"name": "config",
- "summary": "Primary\u0020configuration\u0020storage.",
+ "summary": "Primary\u0020configuration\u0020storage,\u0020including\u0020unique\u0020keys\u0020from\ngrouped\u0020configurations.",
"url": "classes/JG-Config-Config.html#property_config"
}, {
"fqsen": "\\JG\\Config\\ConfigParserFactory",
diff --git a/src/Parsers/ConfParser.php b/src/Parsers/ConfParser.php
index 7af452e..cc04973 100644
--- a/src/Parsers/ConfParser.php
+++ b/src/Parsers/ConfParser.php
@@ -3,7 +3,7 @@
* ConfParser.php
*
* Parses key-value pairs from custom CONF configuration files. These files
- * typically use `:` or `=` as separators for key-value pairs.
+ * typically use `=` as the separator for key-value pairs.
*
* PHP version 8.2
*
@@ -19,19 +19,20 @@
namespace JG\Config\Parsers;
+use \file;
use \trim;
-use \sprintf;
-use \is_numeric;
-use \strtolower;
-use \preg_match_all;
-use \file_get_contents;
+use \explode;
+use \is_file;
+use \preg_match;
+use \is_readable;
use \JG\Config\Exceptions\ConfigParseException;
/**
* ConfParser
*
* Parses key-value pairs from CONF configuration files. This parser supports
- * flexible key-value syntax with either `:` or `=` as separators.
+ * clean formatting with `=` as the separator. It skips comments and empty lines
+ * and trims whitespace while preserving inner spaces.
*
* @package JG\Config\Parsers
*/
@@ -40,12 +41,9 @@ class ConfParser implements ParserInterface
/**
* Parses a CONF configuration file into an associative array.
*
- * The method reads key-value pairs from the file, where keys and values are separated
- * by either `:` or `=`. Leading and trailing whitespace is trimmed for both keys and values.
- *
* Example:
* ```
- * host: localhost
+ * host = localhost
* user = root
* ```
*
@@ -59,40 +57,33 @@ public function parse(string $filePath): array
throw new ConfigParseException("File not found or unreadable: {$filePath}");
}
- // Attempt to retrieve the file contents
- $data = file_get_contents($filePath);
-
- if ($data === false) {
- throw new ConfigParseException(
- sprintf("Failed to read CONF configuration file: %s", $filePath)
- );
+ $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if ($lines === false) {
+ throw new ConfigParseException("Failed to read the CONF file: {$filePath}");
}
- $out = [];
+ $output = [];
- // Define regex for capturing key-value pairs with `:` or `=` as separator
- $regex = '/^(?P[a-zA-Z._\-]+[a-zA-Z0-9]*)\s*[:=]\s*(?P.*)$/m';
+ foreach ($lines as $line) {
+ $line = trim($line);
- // Process matches using the defined regex pattern
- if (preg_match_all($regex, $data, $matches, PREG_SET_ORDER)) {
- foreach ($matches as $match) {
- $key = trim($match['key']);
- $value = trim($match['value']);
+ // Skip comments
+ if (str_starts_with($line, '#') || str_starts_with($line, ';')) {
+ continue;
+ }
- // Convert scalar values (e.g., true, false, null, numbers) if applicable
- $value = $this->convertValue($value);
+ // Parse key=value pairs
+ $parts = explode('=', $line, 2);
+ if (count($parts) === 2) {
+ $key = trim($parts[0]);
+ $value = trim($parts[1]);
- if ($key !== '' && $value !== '') {
- $out[$key] = $value;
- }
+ // Convert scalar values if applicable
+ $output[$key] = $this->convertValue($value);
}
- } else {
- throw new ConfigParseException(
- sprintf("No valid key-value pairs found in CONF file: %s", $filePath)
- );
}
- return $out;
+ return $output;
}
/**
diff --git a/tests/config/config.conf b/tests/config/config.conf
index fe5699d..fe40de1 100644
--- a/tests/config/config.conf
+++ b/tests/config/config.conf
@@ -1,8 +1,11 @@
# CONFIG COMMENT
-host: localhost
-port = 3306
-user: root
-password = secret
+#
+# TESTING WITH SPACES
+###########WWWWWWWWWWWWWWW
+host = localhost
+port = 3306
+user = root
+password = secret
[app]
debug = true