-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 90814b5
Showing
23 changed files
with
684 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.idea/ | ||
composer.lock | ||
vendor/ | ||
.phpunit.result.cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2024 commonphp | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"name": "comphp/config", | ||
"type": "library", | ||
"description": "Provides read/write access to configuration files", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "timothy.mcclatchey", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"autoload": { | ||
"psr-4": { | ||
"CommonPHP\\Configuration\\": "src/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"CommonPHP\\Tests\\Configuration\\": "tests/" | ||
} | ||
}, | ||
"require": { | ||
"php": "^8.3", | ||
"comphp/drivers": "^0.1" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "^10.5.9" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php | ||
|
||
use CommonPHP\Configuration\Attributes\ConfigurationDriverAttribute; | ||
use CommonPHP\Configuration\ConfigurationManager; | ||
use CommonPHP\Configuration\Contracts\ConfigurationDriverContract; | ||
use CommonPHP\Drivers\ServiceProviders\DriverManagerServiceProvider; | ||
use CommonPHP\ServiceManagement\ServiceManager; | ||
|
||
require '../vendor/autoload.php'; | ||
|
||
#[ConfigurationDriverAttribute('php')] | ||
class GeneralUsageExampleDriver implements ConfigurationDriverContract | ||
{ | ||
|
||
#[\Override] function canSave(): bool | ||
{ | ||
return true; | ||
} | ||
|
||
#[\Override] function load(string $filename): array | ||
{ | ||
echo 'Loading: '.$filename.PHP_EOL; | ||
return [ | ||
'foo' => 'bar', | ||
'answerToLifeUniverseEverything' => 42 | ||
]; | ||
} | ||
|
||
#[\Override] function save(string $filename, array $data): void | ||
{ | ||
echo 'Saving: '.json_encode($data).' to file: '.$filename.PHP_EOL; | ||
} | ||
} | ||
|
||
// Instantiate the ServiceManager and register the DriverManagerServiceProvider for dependency management. | ||
$serviceManager = new ServiceManager(); | ||
$serviceManager->providers->registerProvider(DriverManagerServiceProvider::class); | ||
$serviceManager->register(ConfigurationManager::class); | ||
|
||
$config = $serviceManager->get(ConfigurationManager::class); | ||
|
||
$config->loadDriver(GeneralUsageExampleDriver::class); | ||
|
||
$example = $config->get(__FILE__); | ||
var_dump($example->data); | ||
|
||
$example->save(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# CommonPHP Configuration Manager | ||
|
||
The CommonPHP Configuration Manager (`comphp/config`) is a flexible and robust library designed to simplify the management of configuration files in PHP applications. It leverages the power of dynamic driver loading and custom behaviors to provide a highly adaptable solution for application configuration. | ||
|
||
## Features | ||
|
||
- **Dynamic Driver Support**: Easily extendable to support various configuration file formats through custom drivers. | ||
- **Behavior Customization**: Control how the system handles duplicate file extensions and unsupported save operations with configurable behaviors. | ||
- **Exception Handling**: Comprehensive exception handling for precise error tracking and management. | ||
- **Attribute and Contract-Based Configuration**: Utilize PHP attributes and interfaces for defining configuration drivers, ensuring a clear and structured approach. | ||
|
||
## Installation | ||
|
||
Use Composer to install the Configuration Manager: | ||
|
||
``` | ||
composer require comphp/config | ||
``` | ||
|
||
## Basic Usage | ||
|
||
Refer to the `examples/general-usage.php` file for a detailed example. Here's a quick overview: | ||
|
||
1. **Define a Configuration Driver**: | ||
Implement the `ConfigurationDriverContract` in your driver class. Optionally, use the `ConfigurationDriverAttribute` to specify supported file extensions. | ||
|
||
2. **Load and Use the Configuration Manager**: | ||
```php | ||
use CommonPHP\Configuration\ConfigurationManager; | ||
use CommonPHP\Drivers\DriverManager; | ||
|
||
// Initialize the Driver Manager and Configuration Manager | ||
$driverManager = new DriverManager(); | ||
$configurationManager = new ConfigurationManager($driverManager); | ||
|
||
// Load a custom driver | ||
$configurationManager->loadDriver(YourCustomDriver::class); | ||
|
||
// Get configuration | ||
$config = $configurationManager->get('/path/to/your/config.file'); | ||
|
||
// Access configuration data | ||
echo $config->data['your_config_key']; | ||
``` | ||
|
||
3. **Saving Configurations**: | ||
If your driver supports saving, you can persist modifications: | ||
```php | ||
$config->data['new_key'] = 'new_value'; | ||
$config->save(); // Make sure your driver implements saving logic | ||
``` | ||
|
||
## Customizing Behavior | ||
|
||
Customize how the Configuration Manager handles certain scenarios through properties: | ||
|
||
- **Duplicate Extension Behavior**: Decide how to handle when multiple drivers claim the same file extension. | ||
- **Configuration Cannot Save Behavior**: Define behavior for when a configuration cannot be saved (e.g., driver doesn't support saving). | ||
|
||
## Creating Custom Drivers | ||
|
||
Implement the `ConfigurationDriverContract` interface in your driver class and optionally use the `ConfigurationDriverAttribute` to specify which file extensions your driver supports. | ||
|
||
## Handling Exceptions | ||
|
||
The library defines a range of exceptions for fine-grained error handling, from driver load failures to access denied scenarios. Catch these exceptions to handle different error conditions gracefully. | ||
|
||
## Contributing | ||
|
||
Contributions to the CommonPHP Configuration Manager are welcome. Please follow the repository's contributing guidelines to submit bug reports, feature requests, or pull requests. | ||
|
||
## License | ||
|
||
The CommonPHP Configuration Manager is open-sourced software licensed under the MIT license. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
/** | ||
* Marks a class as a configuration driver, specifying supported file extensions. | ||
* | ||
* @package CommonPHP\Configuration\Attributes | ||
*/ | ||
|
||
namespace CommonPHP\Configuration\Attributes; | ||
|
||
use Attribute; | ||
use CommonPHP\Drivers\Contracts\DriverAttributeContract; | ||
|
||
#[Attribute(Attribute::TARGET_CLASS)] | ||
readonly class ConfigurationDriverAttribute implements DriverAttributeContract | ||
{ | ||
/** @var string[] Supported file extensions. */ | ||
public array $extensions; | ||
public function __construct(string ... $extensions) | ||
{ | ||
$this->extensions = $extensions; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
<?php | ||
|
||
/** | ||
* Configuration Manager for CommonPHP | ||
* | ||
* Manages configuration loading and saving through various drivers, supporting dynamic driver loading and extension handling. | ||
* | ||
* @package CommonPHP\Configuration | ||
* @author Timothy McClatchey <[email protected]> | ||
* @copyright 2024 CommonPHP.org | ||
* @license http://opensource.org/licenses/MIT MIT License | ||
*/ | ||
|
||
namespace CommonPHP\Configuration; | ||
|
||
use CommonPHP\Configuration\Attributes\ConfigurationDriverAttribute; | ||
use CommonPHP\Configuration\Contracts\ConfigurationDriverContract; | ||
use CommonPHP\Configuration\Exceptions\AccessDeniedException; | ||
use CommonPHP\Configuration\Exceptions\ConfigurationLoadFailedException; | ||
use CommonPHP\Configuration\Exceptions\DriverConfigurationFailedException; | ||
use CommonPHP\Configuration\Exceptions\DriverLoadFailedException; | ||
use CommonPHP\Configuration\Exceptions\DuplicateFileExtensionException; | ||
use CommonPHP\Configuration\Exceptions\ExtensionNotSupportedException; | ||
use CommonPHP\Configuration\Exceptions\InvalidFileExtensionException; | ||
use CommonPHP\Configuration\Support\Configuration; | ||
use CommonPHP\Configuration\Support\ConfigurationCannotSaveBehavior; | ||
use CommonPHP\Configuration\Support\DuplicateExtensionBehavior; | ||
use CommonPHP\DependencyInjection\Exceptions\ClassNotDefinedException; | ||
use CommonPHP\DependencyInjection\Exceptions\ClassNotInstantiableException; | ||
use CommonPHP\DependencyInjection\Exceptions\InstantiateCircularReferenceException; | ||
use CommonPHP\DependencyInjection\Exceptions\InstantiationFailedException; | ||
use CommonPHP\DependencyInjection\Exceptions\ParameterDiscoveryFailedException; | ||
use CommonPHP\DependencyInjection\Exceptions\ParameterTypeRequiredException; | ||
use CommonPHP\DependencyInjection\Exceptions\UnsupportedReflectionTypeException; | ||
use CommonPHP\Drivers\DriverManager; | ||
use CommonPHP\Drivers\Exceptions\DriverException; | ||
use CommonPHP\Drivers\Exceptions\NotConfiguredException; | ||
use CommonPHP\Drivers\Exceptions\NotEnabledException; | ||
use ReflectionClass; | ||
use ReflectionException; | ||
|
||
final class ConfigurationManager | ||
{ | ||
/** @var DuplicateExtensionBehavior How to handle duplicate file extensions. */ | ||
public DuplicateExtensionBehavior $duplicateExtensionBehavior = DuplicateExtensionBehavior::OVERWRITE; | ||
|
||
/** @var ConfigurationCannotSaveBehavior Behavior when a configuration cannot be saved. */ | ||
public ConfigurationCannotSaveBehavior $configurationCannotSaveBehavior = ConfigurationCannotSaveBehavior::THROW; | ||
|
||
/** @var DriverManager The DriverManager instance. */ | ||
private DriverManager $driverManager; | ||
|
||
/** @var Configuration[] Array of loaded configurations. */ | ||
private array $configurations = []; | ||
|
||
/** @var class-string<ConfigurationDriverContract>[] Mapping of file extensions to driver classes. */ | ||
private array $extensions = []; | ||
|
||
/** | ||
* @throws DriverConfigurationFailedException | ||
*/ | ||
public function __construct(DriverManager $driverManager) | ||
{ | ||
try { | ||
$driverManager->configure(ConfigurationDriverAttribute::class, ConfigurationDriverContract::class); | ||
} catch (DriverException $e) { | ||
throw new DriverConfigurationFailedException($e); | ||
} | ||
$this->driverManager = $driverManager; | ||
} | ||
|
||
/** | ||
* @param string $driverClass | ||
* @throws DriverLoadFailedException | ||
* @throws DuplicateFileExtensionException | ||
* @throws InvalidFileExtensionException | ||
*/ | ||
public function loadDriver(string $driverClass): void | ||
{ | ||
try { | ||
if ($this->driverManager->isEnabled($driverClass)) return; | ||
$this->driverManager->enable($driverClass); | ||
$reflection = new ReflectionClass($driverClass); | ||
} catch (DriverException|ReflectionException $e) { | ||
throw new DriverLoadFailedException($driverClass, $e); | ||
} | ||
/** @var ConfigurationDriverAttribute $attribute */ | ||
$attribute = $reflection->getAttributes(ConfigurationDriverAttribute::class)[0]->newInstance(); | ||
foreach ($attribute->extensions as $extension) | ||
{ | ||
$extension = strtolower($extension); | ||
if (!$this->isValidFileExtension($extension)) | ||
{ | ||
throw new InvalidFileExtensionException($driverClass, $extension); | ||
} | ||
if (isset($this->extensions[$extension])) | ||
{ | ||
if ($this->duplicateExtensionBehavior == DuplicateExtensionBehavior::THROW) | ||
{ | ||
throw new DuplicateFileExtensionException($driverClass, $extension, $this->extensions[$extension]); | ||
} | ||
else if ($this->duplicateExtensionBehavior == DuplicateExtensionBehavior::WARN) | ||
{ | ||
trigger_error((new DuplicateFileExtensionException($driverClass, $extension, $this->extensions[$extension]))->getMessage(), E_USER_WARNING); | ||
} | ||
else if ($this->duplicateExtensionBehavior == DuplicateExtensionBehavior::NOTICE) | ||
{ | ||
trigger_error((new DuplicateFileExtensionException($driverClass, $extension, $this->extensions[$extension]))->getMessage()); | ||
} | ||
else if ($this->duplicateExtensionBehavior == DuplicateExtensionBehavior::OVERWRITE) | ||
{ | ||
$this->extensions[$extension] = $driverClass; | ||
} | ||
// Do nothing on skip | ||
} | ||
else | ||
{ | ||
$this->extensions[$extension] = $driverClass; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @throws ExtensionNotSupportedException | ||
* @throws ClassNotDefinedException | ||
* @throws InstantiationFailedException | ||
* @throws ParameterDiscoveryFailedException | ||
* @throws InstantiateCircularReferenceException | ||
* @throws ParameterTypeRequiredException | ||
* @throws AccessDeniedException | ||
* @throws UnsupportedReflectionTypeException | ||
* @throws NotEnabledException | ||
* @throws NotConfiguredException | ||
* @throws ConfigurationLoadFailedException | ||
* @throws ClassNotInstantiableException | ||
*/ | ||
public function get(string $absolutePath): Configuration | ||
{ | ||
if (isset($this->configurations[$absolutePath])) return $this->configurations[$absolutePath]; | ||
$extension = pathinfo($absolutePath, PATHINFO_EXTENSION); | ||
$extensionLower = strtolower($extension); | ||
if (!isset($this->extensions[$extensionLower])) | ||
{ | ||
throw new ExtensionNotSupportedException($extension); | ||
} | ||
$result = new Configuration($this, $this->driverManager->get($this->extensions[$extensionLower]), $absolutePath); | ||
$this->configurations[$absolutePath] = $result; | ||
return $result; | ||
} | ||
|
||
private function isValidFileExtension(string $extension): bool | ||
{ | ||
return strlen(trim($extension)) > 0 && !preg_match('/[^a-z0-9._-]/', $extension); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
|
||
namespace CommonPHP\Configuration\Contracts; | ||
|
||
use CommonPHP\Drivers\Contracts\DriverContract; | ||
|
||
interface ConfigurationDriverContract extends DriverContract | ||
{ | ||
function canSave(): bool; | ||
|
||
function load(string $filename): array; | ||
|
||
function save(string $filename, array $data): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
|
||
namespace CommonPHP\Configuration\Exceptions; | ||
|
||
use Throwable; | ||
|
||
class AccessDeniedException extends ConfigurationException | ||
{ | ||
public function __construct(string $path, string $access, ?Throwable $previous = null) | ||
{ | ||
parent::__construct('Access denied while trying to '.$access.' file '.$path, $previous); | ||
$this->code = 1611; | ||
} | ||
} |
Oops, something went wrong.