Initialize Nest configuration library.
This commit is contained in:
commit
a04d49f273
7 changed files with 313 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
# IDEA
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Composer
|
||||
vendor/
|
27
composer.json
Normal file
27
composer.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"version": "1.0",
|
||||
"name": "nest/configuration",
|
||||
"description": "Nest configuration service.",
|
||||
"type": "library",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Madeorsk",
|
||||
"email": "madeorsk@protonmail.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nest\\Configuration\\": "src/"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://code.zeptotech.net/Nest/Core"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"nest/core": "dev-main"
|
||||
}
|
||||
}
|
56
composer.lock
generated
Normal file
56
composer.lock
generated
Normal file
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "456694be683ba1dd09042acde50b7e2a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "nest/core",
|
||||
"version": "dev-main",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://code.zeptotech.net/Nest/Core",
|
||||
"reference": "22296b8d7c8b528089189a8d9500395424cb6468"
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.3"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nest\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/Utils/Array.php",
|
||||
"src/Utils/Paths.php",
|
||||
"src/Utils/Reflection.php",
|
||||
"src/Utils/String.php"
|
||||
]
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Madeorsk",
|
||||
"email": "madeorsk@protonmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Nest framework core.",
|
||||
"time": "2024-11-08T11:12:38+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"nest/core": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.3"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
164
src/Configuration.php
Normal file
164
src/Configuration.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace Nest\Configuration;
|
||||
|
||||
use Nest\Application;
|
||||
use Nest\Configuration\Exceptions\ConfigurationValueNotFoundException;
|
||||
use function Nest\Utils\path_join;
|
||||
|
||||
/**
|
||||
* Nest configuration manager.
|
||||
*/
|
||||
class Configuration
|
||||
{
|
||||
/**
|
||||
* Loaded files array.
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $loadedFiles;
|
||||
|
||||
/**
|
||||
* The configuration main associative array.
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected array $config;
|
||||
|
||||
/**
|
||||
* Create a new configuration manager for the given application.
|
||||
* @param Application $application The application.
|
||||
*/
|
||||
public function __construct(protected Application $application)
|
||||
{
|
||||
$this->reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan a configuration directory.
|
||||
* @param string $path The configuration directory path.
|
||||
* @param string|null $globalContextIdentifier The global context identifier to look for, if there is one.
|
||||
* @return void
|
||||
*/
|
||||
private function scanDirectory(string $path, ?string $globalContextIdentifier = null): void
|
||||
{
|
||||
// Get all files in the config path.
|
||||
$files = scandir($path);
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
if (is_file(path_join($path, $file)) && str_ends_with($file, ".php"))
|
||||
// If it looks like a configuration file, we try to load it.
|
||||
$this->loadedFiles[] = path_join($path, $file);
|
||||
|
||||
if (!empty($globalContextIdentifier) && is_dir(path_join($path, $file)) && $globalContextIdentifier == $file)
|
||||
{ // If it looks like the global context custom configuration directory: we try to load all configuration files in it.
|
||||
$this->scanDirectory(path_join($path, $file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload all configuration files in the configuration path.
|
||||
* @return void
|
||||
*/
|
||||
public function reload(): void
|
||||
{
|
||||
// Initialize loaded files array.
|
||||
$this->loadedFiles = [];
|
||||
|
||||
// Scan the main configuration directory, searching for config files or global context custom config directory.
|
||||
$this->scanDirectory($this->application->paths()->getConfigPath(), $this->application->getGlobalContextIdentifier());
|
||||
sort($this->loadedFiles); // Sort files alphabetically.
|
||||
|
||||
// Reset configuration.
|
||||
$this->config = [];
|
||||
|
||||
// Read all sorted configuration files.
|
||||
foreach ($this->loadedFiles as $configFile)
|
||||
$this->readConfigFile($configFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a configuration file and merge it with the current configuration state.
|
||||
* @param string $filePath The configuration file path.
|
||||
* @return $this
|
||||
*/
|
||||
public function readConfigFile(string $filePath): static
|
||||
{
|
||||
// Read the configuration file.
|
||||
$config = require $filePath;
|
||||
// Merge the main configuration with the configuration we just read.
|
||||
$this->config = array_merge($this->config, $config);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursive function to get a configuration value.
|
||||
* @param array $configuration Configuration array where to find the key.
|
||||
* @param string[] $key Configuration key to find the value.
|
||||
* @param string $fullKey Full configuration key.
|
||||
* @return mixed The configuration value for the given key.
|
||||
* @throws ConfigurationValueNotFoundException
|
||||
*/
|
||||
private static function _getValue(array $configuration, array $key, string $fullKey): mixed
|
||||
{
|
||||
// Get the currently looked key.
|
||||
$currentKey = array_shift($key);
|
||||
|
||||
if (array_key_exists($currentKey, $configuration))
|
||||
{ // Configuration key exists.
|
||||
if (empty($key))
|
||||
{ // We reached the value, returning it.
|
||||
return $configuration[$currentKey];
|
||||
}
|
||||
else
|
||||
{ // We must continue to search for the configuration value.
|
||||
|
||||
if (!is_array($configuration[$currentKey]))
|
||||
// Cannot continue to search because currently pointed configuration value is not an array.
|
||||
throw new ConfigurationValueNotFoundException($fullKey);
|
||||
|
||||
// Recursive call to get the requested value.
|
||||
return static::_getValue($configuration[$currentKey], $key, $fullKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Configuration key is missing.
|
||||
throw new ConfigurationValueNotFoundException($fullKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from the loaded configuration.
|
||||
* Throw an exception if the value is not present in configuration array.
|
||||
* @param string $key Full configuration key, with "." to explore the configuration tree.
|
||||
* @return mixed The value corresponding to the given key.
|
||||
* @throws ConfigurationValueNotFoundException
|
||||
*/
|
||||
public function getValue(string $key): mixed
|
||||
{
|
||||
// Split the key.
|
||||
$explodedKey = explode(".", $key);
|
||||
// Call recursive retrieval of the value.
|
||||
return static::_getValue($this->config, $explodedKey, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from the loaded configuration.
|
||||
* @param string $key Full configuration key, with "." to explore the configuration tree.
|
||||
* @param mixed|null $default The default value, if there is none in the loaded configuration.
|
||||
* @return mixed The value corresponding to the given key.
|
||||
*/
|
||||
public function val(string $key, mixed $default = null): mixed
|
||||
{
|
||||
try
|
||||
{ // Trying to get the value corresponding to the given key.
|
||||
return $this->getValue($key);
|
||||
}
|
||||
catch (ConfigurationValueNotFoundException $exception)
|
||||
{ // Value could not be found, returning the default value.
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
}
|
30
src/ConfigurationService.php
Normal file
30
src/ConfigurationService.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Nest\Configuration;
|
||||
|
||||
/**
|
||||
* Nest configuration service.
|
||||
*/
|
||||
trait ConfigurationService
|
||||
{
|
||||
/**
|
||||
* The configuration instance.
|
||||
* @var Configuration
|
||||
*/
|
||||
private Configuration $configuration;
|
||||
|
||||
protected function __nest__ConfigurationService(): void
|
||||
{
|
||||
// Initialize the configuration instance.
|
||||
$this->configuration = new Configuration($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration service.
|
||||
* @return Configuration The configuration manager.
|
||||
*/
|
||||
public function configuration(): Configuration
|
||||
{
|
||||
return $this->configuration;
|
||||
}
|
||||
}
|
9
src/Exceptions/ConfigurationException.php
Normal file
9
src/Exceptions/ConfigurationException.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace Nest\Configuration\Exceptions;
|
||||
|
||||
use Nest\Exceptions\Exception;
|
||||
|
||||
class ConfigurationException extends Exception
|
||||
{
|
||||
}
|
21
src/Exceptions/ConfigurationValueNotFoundException.php
Normal file
21
src/Exceptions/ConfigurationValueNotFoundException.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Nest\Configuration\Exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Exception thrown when a configuration value does not exists in configuration array.
|
||||
*/
|
||||
class ConfigurationValueNotFoundException extends ConfigurationException
|
||||
{
|
||||
/**
|
||||
* @param string $key The configuration key not found.
|
||||
* @param int $code [optional] The Exception code.
|
||||
* @param null|Throwable $previous [optional] The previous throwable used for the exception chaining.
|
||||
*/
|
||||
public function __construct(public string $key, int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct("Cannot find a configuration value for key \"$this->key\".", $code, $previous);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue