diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e9dd71..73d5619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.1.13] - 2016-02-17 +### Added +- Added `getSubConfig()` to extract the subtree at a specific level & key. +- Added corresponding tests. + ## [0.1.12] - 2016-02-17 ### Fixed - Updated `brightnucleus/exceptions` dependency. @@ -76,6 +81,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Initial release to GitHub. +[0.1.13]: https://github.com/brightnucleus/config/compare/v0.1.12...v0.1.13 [0.1.12]: https://github.com/brightnucleus/config/compare/v0.1.11...v0.1.12 [0.1.11]: https://github.com/brightnucleus/config/compare/v0.1.10...v0.1.11 [0.1.10]: https://github.com/brightnucleus/config/compare/v0.1.9...v0.1.10 diff --git a/README.md b/README.md index 0e99fff..1db1b13 100644 --- a/README.md +++ b/README.md @@ -64,24 +64,20 @@ class Example { /** * Instantiate an Example object. * - * @param ConfigInterface $config Config to parametrize the object. - * @param string|null $config_key Optional. Config key that represents the - * subtree for this class. - * @throws RuntimeException If the Config could not be parsed correctly. + * @param ConfigInterface $config Config to parametrize the object. + * @throws RuntimeException If the Config could not be parsed correctly. */ - public function __construct( ConfigInterface $config, $config_key = null ) { - $this->processConfig( $config, $config_key ?: 'BrightNucleus\Example' ); + public function __construct( ConfigInterface $config ) { + $this->processConfig( $config ); } /** * Do something. */ public function run() { - $key = 'test_key;'; + $key = 'test_key'; - // Outputs: - // The value of the config key "test_key" is "test_value". - printf( + return sprintf( _( 'The value of the config key "$1%s" is "$2%s".'), $key, $this->getConfigKey( $key ) @@ -90,6 +86,26 @@ class Example { } ``` +### Example of how to put the configuration into the class + +You can combine all of your configurations into 1 single file and only pass "Sub-Configurations" to the individual components. This way, you can save a file access and a complete validation pass for each component. + +Here's how you can pass the configuration file into the class: + +```PHP +getSubConfig( 'BrightNucleus\Example' ) ); + + // Outputs: + // The value of the config key "test_key" is "test_value". + echo $example->run(); +} +``` + See [link to post coming soon] for more details. ## Contributing diff --git a/src/AbstractConfig.php b/src/AbstractConfig.php index 153a2fe..f7205a2 100644 --- a/src/AbstractConfig.php +++ b/src/AbstractConfig.php @@ -72,17 +72,7 @@ public function __construct(array $config, $delimiter = null) */ public function getKey() { - $keys = $this->getKeyArguments(func_get_args()); - Assert\that($keys)->all()->string()->notEmpty(); - - if (! $this->hasKey($keys)) { - throw new OutOfRangeException( - sprintf( - _('The configuration key %1$s does not exist.'), - implode('->', $keys) - ) - ); - } + $keys = $this->validateKeys(func_get_args()); $keys = array_reverse($keys); $array = $this->getArrayCopy(); @@ -109,7 +99,6 @@ public function hasKey() { try { $keys = array_reverse($this->getKeyArguments(func_get_args())); - Assert\thatAll($keys)->string()->notEmpty(); $array = $this->getArrayCopy(); while (count($keys) > 0) { @@ -149,6 +138,66 @@ public function getKeys() return array_keys((array)$this); } + /** + * Get a new config at a specific sub-level. + * + * @since 0.1.13 + * + * @param string ... List of keys. + * @return ConfigInterface + * @throws BadMethodCallException If no argument was provided. + * @throws OutOfRangeException If an unknown key is requested. + */ + public function getSubConfig() + { + $keys = $this->validateKeys(func_get_args()); + + $subConfig = clone $this; + $subConfig->reduceToSubKey($keys); + + return $subConfig; + } + + /** + * Validate a set of keys to make sure they exist. + * + * @since 0.1.13 + * + * @param string ... List of keys. + * @return array List of keys. + * @throws BadMethodCallException If no argument was provided. + * @throws OutOfRangeException If an unknown key is requested. + */ + public function validateKeys() + { + $keys = $this->getKeyArguments(func_get_args()); + + Assert\that($keys)->all()->string()->notEmpty(); + + if (! $this->hasKey($keys)) { + throw new OutOfRangeException( + sprintf( + _('The configuration key %1$s does not exist.'), + implode('->', $keys) + ) + ); + } + + return $keys; + } + + /** + * Reduce the currently stored config array to a subarray at a specific level. + * + * @since 0.1.13 + * + * @param array $keys Array of keys that point to a key down in the hierarchy. + */ + protected function reduceToSubkey(array $keys) + { + $this->exchangeArray($this->getKey($keys)); + } + /** * Recursively extract the configuration key arguments from an arbitrary array. * diff --git a/src/ConfigInterface.php b/src/ConfigInterface.php index dc4b2bb..ada1410 100644 --- a/src/ConfigInterface.php +++ b/src/ConfigInterface.php @@ -62,7 +62,6 @@ public function hasKey(); * @since 0.1.4 Accepts list of keys. * * @param string ... List of keys. - * * @return mixed */ public function getKey(); @@ -93,4 +92,14 @@ public function getKeys(); * @return boolean */ public function isValid(); + + /** + * Get a new config at a specific sub-level. + * + * @since 0.1.13 + * + * @param string ... List of keys. + * @return ConfigInterface + */ + public function getSubConfig(); } diff --git a/src/ConfigTrait.php b/src/ConfigTrait.php index 1d9dc31..83e714e 100644 --- a/src/ConfigTrait.php +++ b/src/ConfigTrait.php @@ -42,8 +42,7 @@ protected function processConfig(ConfigInterface $config) try { $keys = func_get_args(); array_shift($keys); - Assert\that($keys)->all()->string()->notEmpty(); - $config = new Config($config->getKey($keys)); + $config = $config->getSubConfig($keys); } catch (Exception $exception) { throw new RuntimeException( sprintf( diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 2568eb5..c4acc79 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -30,7 +30,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase * Don't use an array const to avoid bumping PHP requirement to 5.6. */ protected static $test_array = [ - 'random_string' => 'test_value', + 'random_string' => 'test_value', 'positive_integer' => 42, 'negative_integer' => -256, 'positive_boolean' => true, @@ -354,4 +354,37 @@ public function testConfigFileWithDefaults() ); $this->assertFalse($config->getKey('some_other_key')); } + + public function testGetSubConfig() + { + $config = new Config(__DIR__ . '/fixtures/deep_config_file.php'); + $subconfig = $config->getSubConfig('vendor/package'); + $subsection1 = $config->getSubConfig('vendor', 'package', 'section_1'); + $subsection2 = $subconfig->getSubConfig('section_2'); + $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config); + $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config); + $this->assertInstanceOf('\BrightNucleus\Config\Config', $config); + $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $subconfig); + $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $subconfig); + $this->assertInstanceOf('\BrightNucleus\Config\Config', $subconfig); + $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $subsection1); + $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $subsection1); + $this->assertInstanceOf('\BrightNucleus\Config\Config', $subsection1); + $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $subsection2); + $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $subsection2); + $this->assertInstanceOf('\BrightNucleus\Config\Config', $subsection2); + $this->assertTrue($config->hasKey('vendor/package')); + $this->assertTrue($config->hasKey('vendor/package/section_1/test_key_1')); + $this->assertTrue($config->hasKey('vendor/package/section_2/test_key_2')); + $this->assertTrue($subconfig->hasKey('section_1/test_key_1')); + $this->assertTrue($subconfig->hasKey('section_2/test_key_2')); + $this->assertTrue($subsection1->hasKey('test_key_1')); + $this->assertTrue($subsection2->hasKey('test_key_2')); + $this->setExpectedException( + 'BrightNucleus\Exception\OutOfRangeException', + 'The configuration key some_other_key does not exist.' + ); + $this->assertFalse($config->getSubConfig('some_other_key')); + + } } diff --git a/tests/fixtures/deep_config_file.php b/tests/fixtures/deep_config_file.php new file mode 100644 index 0000000..445faee --- /dev/null +++ b/tests/fixtures/deep_config_file.php @@ -0,0 +1,23 @@ + + * @license GPL-2.0+ + * @link http://www.brightnucleus.com/ + * @copyright 2016 Alain Schlesser, Bright Nucleus + */ + +namespace BrightNucleus\Config; + +$test_data = [ + 'section_1' => [ + 'test_key_1' => 'test_value_1', + ], + 'section_2' => [ + 'test_key_2' => 'test_value_2', + ], +]; + +return ['vendor' => ['package' => $test_data]];