├── phpunit.xml.dist
├── .gitignore
├── .coveralls.yml
├── tests
├── fixtures
│ ├── dummy_file.txt
│ ├── override_config_file.php
│ ├── deep_config_file.php
│ ├── config_file.php
│ ├── override_deep_config_file.php
│ └── schema_config_file.php
├── bootstrap.php
├── TestCase.php
├── ConfigSchemaTest.php
├── ConfigFactoryTest.php
├── ConfigTraitTest.php
└── ConfigTest.php
├── phpcs.xml.dist
├── .github
└── workflows
│ ├── code-quality.yml
│ └── testing.yml
├── .docheader
├── src
├── Exception
│ ├── ConfigException.php
│ ├── KeyNotFoundException.php
│ ├── FailedToLoadConfigException.php
│ ├── InvalidConfigException.php
│ ├── FailedToProcessConfigException.php
│ ├── FailedToInstantiateParentException.php
│ ├── FailedToResolveConfigException.php
│ └── InvalidConfigurationSourceException.php
├── ConfigValidatorInterface.php
├── ConfigSchemaInterface.php
├── Loader.php
├── Loader
│ ├── LoaderInterface.php
│ ├── AbstractLoader.php
│ ├── JSONLoader.php
│ ├── PHPLoader.php
│ └── LoaderFactory.php
├── AbstractConfigSchema.php
├── ConfigInterface.php
├── ConfigSchema.php
├── ConfigTrait.php
├── AbstractConfig.php
├── Config.php
└── ConfigFactory.php
├── repositories.yaml
├── phpunit.xml
├── LICENSE
├── composer.json
├── CHANGELOG.md
└── README.md
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | composer.lock
3 |
--------------------------------------------------------------------------------
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | json_path: coveralls-upload.json
2 |
--------------------------------------------------------------------------------
/tests/fixtures/dummy_file.txt:
--------------------------------------------------------------------------------
1 | # Readme File to force an exception from Config constructor
2 |
3 | Just some random content.
4 |
--------------------------------------------------------------------------------
/phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 | The coding standard for the Bright Nucleus Config package.
4 |
5 | src
6 | tests
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.github/workflows/code-quality.yml:
--------------------------------------------------------------------------------
1 | name: Code Quality Checks
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - main
8 | - master
9 |
10 | jobs:
11 | code-quality:
12 | uses: brightnucleus/.github/.github/workflows/reusable-code-quality.yml@main
13 |
--------------------------------------------------------------------------------
/.docheader:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | $test_data = [
15 |
16 | 'random_string' => 'override_value',
17 |
18 | ];
19 |
20 | return $test_data;
21 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Tests;
13 |
14 | use Yoast\PHPUnitPolyfills\TestCases\TestCase as PolyfilledTestCase;
15 |
16 | class TestCase extends PolyfilledTestCase
17 | {
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/tests/fixtures/deep_config_file.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | $test_data = [
15 | 'section_1' => [
16 | 'test_key_1' => 'test_value_1',
17 | ],
18 | 'section_2' => [
19 | 'test_key_2' => 'test_value_2',
20 | ],
21 | ];
22 |
23 | return ['vendor' => ['package' => $test_data]];
24 |
--------------------------------------------------------------------------------
/tests/fixtures/config_file.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | $test_data = [
15 |
16 | 'random_string' => 'test_value',
17 | 'positive_integer' => 42,
18 | 'negative_integer' => -256,
19 | 'positive_boolean' => true,
20 | 'negative_boolean' => false,
21 |
22 | ];
23 |
24 | return $test_data;
25 |
--------------------------------------------------------------------------------
/src/Exception/ConfigException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\ExceptionInterface;
15 |
16 | /**
17 | * Interface ConfigException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | interface ConfigException extends ExceptionInterface
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/tests/fixtures/override_deep_config_file.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | $test_data = [
15 | 'section_1' => [
16 | 'test_key_3' => 'override_value_3',
17 | ],
18 | 'section_2' => [
19 | 'test_key_2' => 'override_value_2',
20 | ],
21 | 'section_3' => [
22 | 'test_key_4' => 'override_value_4',
23 | ],
24 | ];
25 |
26 | return ['vendor' => ['package' => $test_data]];
27 |
--------------------------------------------------------------------------------
/src/Exception/KeyNotFoundException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\OutOfRangeException;
15 |
16 | /**
17 | * Class KeyNotFoundException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | class KeyNotFoundException extends OutOfRangeException implements ConfigException
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/Exception/FailedToLoadConfigException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\RuntimeException;
15 |
16 | /**
17 | * Class FailedToLoadConfigException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | class FailedToLoadConfigException extends RuntimeException implements ConfigException
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/Exception/InvalidConfigException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\UnexpectedValueException;
15 |
16 | /**
17 | * Class FailedToLoadConfigException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | class InvalidConfigException extends UnexpectedValueException implements ConfigException
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/Exception/FailedToProcessConfigException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\RuntimeException;
15 |
16 | /**
17 | * Class FailedToProcessConfigException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | class FailedToProcessConfigException extends RuntimeException implements ConfigException
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/Exception/FailedToInstantiateParentException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\RuntimeException;
15 |
16 | /**
17 | * Class FailedToInstantiateParentException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | class FailedToInstantiateParentException extends RuntimeException implements ConfigException
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/Exception/FailedToResolveConfigException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\UnexpectedValueException;
15 |
16 | /**
17 | * Class FailedToResolveConfigException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | class FailedToResolveConfigException extends UnexpectedValueException implements ConfigException
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/Exception/InvalidConfigurationSourceException.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Exception;
13 |
14 | use BrightNucleus\Exception\InvalidArgumentException;
15 |
16 | /**
17 | * Class InvalidConfigurationSourceException.
18 | *
19 | * @since 0.4.0
20 | *
21 | * @package BrightNucleus\Config\Exception
22 | * @author Alain Schlesser
23 | */
24 | class InvalidConfigurationSourceException extends InvalidArgumentException implements ConfigException
25 | {
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/ConfigValidatorInterface.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | /**
15 | * Contract to deal with configuration value validation.
16 | *
17 | * @since 0.1.0
18 | *
19 | * @package BrightNucleus\Config
20 | * @author Alain Schlesser
21 | */
22 | interface ConfigValidatorInterface
23 | {
24 |
25 | /**
26 | * Check whether the passed-in Config is valid.
27 | *
28 | * @since 0.1.0
29 | *
30 | * @param ConfigInterface $config
31 | *
32 | * @return bool
33 | */
34 | public function isValid(ConfigInterface $config);
35 | }
36 |
--------------------------------------------------------------------------------
/tests/fixtures/schema_config_file.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Core;
13 |
14 | $test_schema = [
15 |
16 | 'random_string' => [
17 | 'default' => 'default_test_value',
18 | 'required' => true,
19 | ],
20 | 'positive_integer' => [
21 | 'default' => 99,
22 | 'required' => 'TRUE',
23 | ],
24 | 'negative_integer' => [
25 | 'required' => 'Yes',
26 | ],
27 | 'positive_boolean' => [
28 | 'default' => true,
29 | 'required' => false,
30 | ],
31 | 'negative_boolean' => [
32 | 'required' => 'No',
33 | ],
34 |
35 | ];
36 |
37 | return $test_schema;
38 |
--------------------------------------------------------------------------------
/repositories.yaml:
--------------------------------------------------------------------------------
1 | # BrightNucleus Repository Sync Configuration
2 | # ==========================================
3 |
4 | # GitHub organization name
5 | organization: brightnucleus
6 |
7 | # Repositories to exclude from sync (e.g., the dev repo itself)
8 | exclude_repos:
9 | - brightnucleus.dev
10 |
11 | # Common default branch names to check (in order of preference)
12 | default_branch_names:
13 | - main
14 | - master
15 | - develop
16 |
17 | # Safety checks before updating repositories
18 | safety_checks:
19 | # Check for uncommitted changes before updating
20 | check_uncommitted: true
21 |
22 | # Check for unpushed commits before updating
23 | check_unpushed: true
24 |
25 | # Create backup before updating (not implemented yet)
26 | create_backup: false
27 |
28 | # Additional repository-specific configurations
29 | # You can override settings for specific repositories
30 | repository_overrides: []
31 | # Example:
32 | # - name: specific-repo
33 | # default_branch: custom-branch
34 | # skip_update: false
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 | tests
18 |
19 |
20 |
21 |
23 |
24 | src
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Alain Schlesser, Bright Nucleus
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | this software and associated documentation files (the "Software"), to deal in
6 | the Software without restriction, including without limitation the rights to
7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 | of the Software, and to permit persons to whom the Software is furnished to do
9 | so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 |
--------------------------------------------------------------------------------
/src/ConfigSchemaInterface.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | /**
15 | * Contract to deal with configuration requirements.
16 | *
17 | * @since 0.1.0
18 | *
19 | * @package BrightNucleus\Config
20 | * @author Alain Schlesser
21 | */
22 | interface ConfigSchemaInterface
23 | {
24 |
25 | /**
26 | * Get the set of defined options.
27 | *
28 | * @since 0.1.0
29 | *
30 | * @return array|null
31 | */
32 | public function getDefinedOptions();
33 |
34 | /**
35 | * Get the set of default options.
36 | *
37 | * @since 0.1.0
38 | *
39 | * @return array|null
40 | */
41 | public function getDefaultOptions();
42 |
43 | /**
44 | * Get the set of required options.
45 | *
46 | * @since 0.1.0
47 | *
48 | * @return array|null
49 | */
50 | public function getRequiredOptions();
51 | }
52 |
--------------------------------------------------------------------------------
/src/Loader.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | use BrightNucleus\Config\Exception\FailedToLoadConfigException;
15 | use BrightNucleus\Config\Loader\LoaderFactory;
16 |
17 | /**
18 | * Class Loader.
19 | *
20 | * @since 0.4.0
21 | *
22 | * @package BrightNucleus\Config
23 | * @author Alain Schlesser
24 | */
25 | class Loader
26 | {
27 |
28 | /**
29 | * Static convenience function to load a configuration from an URI.
30 | *
31 | * @since 0.4.0
32 | *
33 | * @param string $uri URI of the resource to load.
34 | *
35 | * @return array|null Parsed data loaded from the resource.
36 | * @throws FailedToLoadConfigException If the configuration could not be loaded.
37 | */
38 | public static function load($uri)
39 | {
40 | $loader = LoaderFactory::createFromUri($uri);
41 |
42 | return $loader->load($uri);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Loader/LoaderInterface.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Loader;
13 |
14 | /**
15 | * Interface LoaderInterface.
16 | *
17 | * @since 0.4.0
18 | *
19 | * @package BrightNucleus\Config\Loader
20 | * @author Alain Schlesser
21 | */
22 | interface LoaderInterface
23 | {
24 |
25 | /**
26 | * Check whether the loader is able to load a given URI.
27 | *
28 | * @since 0.4.0
29 | *
30 | * @param string $uri URI to check.
31 | *
32 | * @return bool Whether the loader can load the given URI.
33 | */
34 | public static function canLoad($uri);
35 |
36 | /**
37 | * Load the configuration from an URI.
38 | *
39 | * @since 0.4.0
40 | *
41 | * @param string $uri URI of the resource to load.
42 | *
43 | * @return array|null Data contained within the resource. Null if no data could be loaded/parsed.
44 | * @throws FailedToLoadConfigException If the configuration could not be loaded.
45 | */
46 | public function load($uri);
47 | }
48 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "brightnucleus/config",
3 | "description": "Minimal, reusable Config component.",
4 | "minimum-stability": "dev",
5 | "prefer-stable": true,
6 | "require-dev": {
7 | "malukenho/docheader": "^1",
8 | "mikey179/vfsstream": "^1.6",
9 | "yoast/phpunit-polyfills": "^3",
10 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5 || ^10",
11 | "squizlabs/php_codesniffer": "^3",
12 | "php-parallel-lint/php-parallel-lint": "^1.4"
13 | },
14 | "license": "MIT",
15 | "authors": [
16 | {
17 | "name": "Alain Schlesser",
18 | "email": "alain.schlesser@gmail.com"
19 | }
20 | ],
21 | "require": {
22 | "php": ">=8.0",
23 | "symfony/options-resolver": ">=2.8",
24 | "brightnucleus/exceptions": ">=0.4"
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "BrightNucleus\\Config\\": "src/"
29 | }
30 | },
31 | "autoload-dev": {
32 | "psr-4": {
33 | "BrightNucleus\\Config\\Tests\\": "tests/"
34 | }
35 | },
36 | "scripts": {
37 | "check": [
38 | "@cs-check",
39 | "@test"
40 | ],
41 | "upload-coverage": "vendor/bin/coveralls -v --coverage_clover clover.xml",
42 | "cs-check": "vendor/bin/phpcs -ps --colors",
43 | "cs-fix": "vendor/bin/phpcbf -ps --colors",
44 | "test": "vendor/bin/phpunit --colors",
45 | "test-coverage": "vendor/bin/phpunit --colors --coverage-clover clover.xml",
46 | "license-check": "vendor/bin/docheader --ansi check src/"
47 | }
48 | }
--------------------------------------------------------------------------------
/tests/ConfigSchemaTest.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Tests;
13 |
14 | use BrightNucleus\Config\Config;
15 | use BrightNucleus\Config\ConfigSchema;
16 |
17 | class ConfigSchemaTest extends TestCase
18 | {
19 |
20 | /**
21 | * @covers \BrightNucleus\Config\ConfigSchema::__construct
22 | */
23 | public function testInstantiation()
24 | {
25 | $schema_config = $this->getMockBuilder('\BrightNucleus\Config\ConfigInterface')
26 | ->getMock();
27 | $schema_config->method('getArrayCopy')
28 | ->willReturn([]);
29 | $schema = new ConfigSchema($schema_config);
30 | $this->assertInstanceOf(
31 | '\BrightNucleus\Config\ConfigSchemaInterface',
32 | $schema
33 | );
34 | $this->assertInstanceOf(
35 | '\BrightNucleus\Config\AbstractConfigSchema',
36 | $schema
37 | );
38 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigSchema', $schema);
39 | $this->expectException('BrightNucleus\Exception\InvalidArgumentException');
40 | $this->expectExceptionMessage('Invalid schema source:');
41 | new ConfigSchema(25);
42 | }
43 |
44 | /**
45 | * @covers \BrightNucleus\Config\ConfigSchema::parseSchema
46 | * @covers \BrightNucleus\Config\ConfigSchema::parseDefined
47 | * @covers \BrightNucleus\Config\ConfigSchema::parseDefault
48 | * @covers \BrightNucleus\Config\ConfigSchema::parseRequired
49 | * @covers \BrightNucleus\Config\ConfigSchema::isTruthy
50 | */
51 | public function testParsing()
52 | {
53 | $schema_config = new Config(__DIR__ . '/fixtures/schema_config_file.php');
54 | $schema = new ConfigSchema($schema_config);
55 | $this->assertInstanceOf(
56 | '\BrightNucleus\Config\ConfigSchemaInterface',
57 | $schema
58 | );
59 | $this->assertInstanceOf(
60 | '\BrightNucleus\Config\AbstractConfigSchema',
61 | $schema
62 | );
63 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigSchema', $schema);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/AbstractConfigSchema.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | /**
15 | * Handles basic validation of the config schema.
16 | *
17 | * @since 0.1.0
18 | *
19 | * @package BrightNucleus\Config
20 | * @author Alain Schlesser
21 | */
22 | abstract class AbstractConfigSchema implements ConfigSchemaInterface
23 | {
24 |
25 | /**
26 | * The defined values that are recognized.
27 | *
28 | * @var ConfigInterface
29 | */
30 | protected $defined;
31 |
32 | /**
33 | * The default values that can be overwritten.
34 | *
35 | * @var ConfigInterface
36 | */
37 | protected $defaults;
38 |
39 | /**
40 | * The required values that need to be set.
41 | *
42 | * @var ConfigInterface
43 | */
44 | protected $required;
45 |
46 | /**
47 | * Get the set of defined options.
48 | *
49 | * @since 0.1.0
50 | *
51 | * @return array|null
52 | */
53 | public function getDefinedOptions()
54 | {
55 | if (! $this->defined) {
56 | return null;
57 | }
58 |
59 | if ($this->defined instanceof ConfigInterface) {
60 | return $this->defined->getArrayCopy();
61 | }
62 |
63 | return (array)$this->defined;
64 | }
65 |
66 | /**
67 | * Get the set of default options.
68 | *
69 | * @since 0.1.0
70 | *
71 | * @return array|null
72 | */
73 | public function getDefaultOptions()
74 | {
75 | if (! $this->defaults) {
76 | return null;
77 | }
78 |
79 | if ($this->defaults instanceof ConfigInterface) {
80 | return $this->defaults->getArrayCopy();
81 | }
82 |
83 | return (array)$this->defaults;
84 | }
85 |
86 | /**
87 | * Get the set of required options.
88 | *
89 | * @since 0.1.0
90 | *
91 | * @return array|null
92 | */
93 | public function getRequiredOptions()
94 | {
95 | if (! $this->required) {
96 | return null;
97 | }
98 |
99 | if ($this->required instanceof ConfigInterface) {
100 | return $this->required->getArrayCopy();
101 | }
102 |
103 | return (array)$this->required;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/Loader/AbstractLoader.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Loader;
13 |
14 | use BrightNucleus\Config\Exception\FailedToLoadConfigException;
15 | use Exception;
16 |
17 | /**
18 | * Class AbstractLoader.
19 | *
20 | * @since 0.4.0
21 | *
22 | * @package BrightNucleus\Config\Loader
23 | * @author Alain Schlesser
24 | */
25 | abstract class AbstractLoader implements LoaderInterface
26 | {
27 |
28 | /**
29 | * Load the configuration from an URI.
30 | *
31 | * @since 0.4.0
32 | *
33 | * @param string $uri URI of the resource to load.
34 | *
35 | * @return array|null Data contained within the resource. Null if no data could be loaded/parsed.
36 | * @throws FailedToLoadConfigException If the configuration could not be loaded.
37 | */
38 | public function load($uri)
39 | {
40 | try {
41 | $uri = $this->validateUri($uri);
42 | $data = $this->loadUri($uri);
43 |
44 | return $this->parseData($data);
45 | } catch (Exception $exception) {
46 | throw new FailedToLoadConfigException(
47 | sprintf(
48 | _('Could not load resource located at "%1$s". Reason: "%2$s".'),
49 | $uri,
50 | $exception->getMessage()
51 | ),
52 | $exception->getCode(),
53 | $exception
54 | );
55 | }
56 | }
57 |
58 | /**
59 | * Validate and return the URI.
60 | *
61 | * @since 0.4.0
62 | *
63 | * @param string $uri URI of the resource to load.
64 | *
65 | * @return string Validated URI.
66 | */
67 | protected function validateUri($uri)
68 | {
69 | return $uri;
70 | }
71 |
72 | /**
73 | * Parse the raw data and return it in parsed form.
74 | *
75 | * @since 0.4.0
76 | *
77 | * @param array|null $data Raw data to be parsed.
78 | *
79 | * @return array|null Data in parsed form. Null if no parsable data found.
80 | */
81 | protected function parseData($data)
82 | {
83 | return $data;
84 | }
85 |
86 | /**
87 | * Load the contents of an resource identified by an URI.
88 | *
89 | * @since 0.4.0
90 | *
91 | * @param string $uri URI of the resource.
92 | *
93 | * @return array|null Raw data loaded from the resource. Null if no data found.
94 | */
95 | abstract protected function loadUri($uri);
96 | }
97 |
--------------------------------------------------------------------------------
/src/Loader/JSONLoader.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Loader;
13 |
14 | use BrightNucleus\Config\Exception\FailedToLoadConfigException;
15 | use Exception;
16 |
17 | /**
18 | * Class JSONLoader.
19 | *
20 | * @since 0.1.0
21 | *
22 | * @package BrightNucleus\Config\Loader
23 | * @author Pascal Knecht
24 | */
25 | class JSONLoader extends AbstractLoader
26 | {
27 |
28 | /**
29 | * Check whether the loader is able to load a given URI.
30 | *
31 | * @since 0.4.0
32 | *
33 | * @param string $uri URI to check.
34 | *
35 | * @return bool Whether the loader can load the given URI.
36 | */
37 | public static function canLoad($uri)
38 | {
39 | $path = pathinfo($uri);
40 |
41 | return 'json' === mb_strtolower($path['extension']);
42 | }
43 |
44 | /**
45 | * Load the contents of an resource identified by an URI.
46 | *
47 | * @since 0.4.0
48 | *
49 | * @param string $uri URI of the resource.
50 | *
51 | * @return array|null Raw data loaded from the resource. Null if no data found.
52 | * @throws FailedToLoadConfigException If the resource could not be loaded.
53 | */
54 | protected function loadUri($uri)
55 | {
56 | try {
57 | ob_start();
58 | $data = json_decode(file_get_contents($uri), true);
59 | ob_end_clean();
60 |
61 | return (array)$data;
62 | } catch (Exception $exception) {
63 | throw new FailedToLoadConfigException(
64 | sprintf(
65 | _('Could not include JSON config file "%1$s". Reason: "%2$s".'),
66 | $uri,
67 | $exception->getMessage()
68 | ),
69 | $exception->getCode(),
70 | $exception
71 | );
72 | }
73 | }
74 |
75 | /**
76 | * Validate and return the URI.
77 | *
78 | * @since 0.4.0
79 | *
80 | * @param string $uri URI of the resource to load.
81 | *
82 | * @return string Validated URI.
83 | * @throws FailedToLoadConfigException If the URI does not exist or is not readable.
84 | */
85 | protected function validateUri($uri)
86 | {
87 | if (! is_readable($uri)) {
88 | throw new FailedToLoadConfigException(
89 | sprintf(
90 | _('The requested JSON config file "%1$s" does not exist or is not readable.'),
91 | $uri
92 | )
93 | );
94 | }
95 |
96 | return $uri;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Loader/PHPLoader.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Loader;
13 |
14 | use BrightNucleus\Config\Exception\FailedToLoadConfigException;
15 | use Exception;
16 |
17 | /**
18 | * Class PHPLoader.
19 | *
20 | * @since 0.4.0
21 | *
22 | * @package BrightNucleus\Config\Loader
23 | * @author Alain Schlesser
24 | */
25 | class PHPLoader extends AbstractLoader
26 | {
27 |
28 | /**
29 | * Check whether the loader is able to load a given URI.
30 | *
31 | * @since 0.4.0
32 | *
33 | * @param string $uri URI to check.
34 | *
35 | * @return bool Whether the loader can load the given URI.
36 | */
37 | public static function canLoad($uri)
38 | {
39 | $path = pathinfo($uri);
40 |
41 | return 'php' === mb_strtolower($path['extension']);
42 | }
43 |
44 | /**
45 | * Load the contents of an resource identified by an URI.
46 | *
47 | * @since 0.4.0
48 | *
49 | * @param string $uri URI of the resource.
50 | *
51 | * @return array|null Raw data loaded from the resource. Null if no data found.
52 | * @throws FailedToLoadConfigException If the resource could not be loaded.
53 | */
54 | protected function loadUri($uri)
55 | {
56 | try {
57 | // Try to load the file through PHP's include().
58 | // Make sure we don't accidentally create output.
59 | ob_start();
60 | $data = include($uri);
61 | ob_end_clean();
62 |
63 | return $data;
64 | } catch (Exception $exception) {
65 | throw new FailedToLoadConfigException(
66 | sprintf(
67 | _('Could not include PHP config file "%1$s". Reason: "%2$s".'),
68 | $uri,
69 | $exception->getMessage()
70 | ),
71 | $exception->getCode(),
72 | $exception
73 | );
74 | }
75 | }
76 |
77 | /**
78 | * Validate and return the URI.
79 | *
80 | * @since 0.4.0
81 | *
82 | * @param string $uri URI of the resource to load.
83 | *
84 | * @return string Validated URI.
85 | * @throws FailedToLoadConfigException If the URI does not exist or is not readable.
86 | */
87 | protected function validateUri($uri)
88 | {
89 | if (! is_readable($uri)) {
90 | throw new FailedToLoadConfigException(
91 | sprintf(
92 | _('The requested PHP config file "%1$s" does not exist or is not readable.'),
93 | $uri
94 | )
95 | );
96 | }
97 |
98 | return $uri;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/ConfigInterface.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | use ArrayAccess;
15 | use Countable;
16 | use IteratorAggregate;
17 | use Serializable;
18 |
19 | /**
20 | * Contract to deal with configuration values.
21 | *
22 | * @since 0.1.0
23 | *
24 | * @package BrightNucleus\Config
25 | * @author Alain Schlesser
26 | */
27 | interface ConfigInterface extends IteratorAggregate, ArrayAccess, Serializable, Countable
28 | {
29 |
30 | /**
31 | * Creates a copy of the ArrayObject.
32 | *
33 | * Returns a copy of the array. When the ArrayObject refers to an object an
34 | * array of the public properties of that object will be returned.
35 | * This is implemented by \ArrayObject.
36 | *
37 | * @since 0.1.0
38 | *
39 | * @return array Copy of the array.
40 | */
41 | public function getArrayCopy();
42 |
43 | /**
44 | * Check whether the Config has a specific key.
45 | *
46 | * To check a value several levels deep, add the keys for each level as a comma-separated list.
47 | *
48 | * @since 0.1.0
49 | * @since 0.1.4 Accepts list of keys.
50 | *
51 | * @param string $_ List of keys.
52 | *
53 | * @return bool
54 | */
55 | public function hasKey($_);
56 |
57 | /**
58 | * Get the value of a specific key.
59 | *
60 | * To get a value several levels deep, add the keys for each level as a comma-separated list.
61 | *
62 | * @since 0.1.0
63 | * @since 0.1.4 Accepts list of keys.
64 | *
65 | * @param string $_ List of keys.
66 | *
67 | * @return mixed
68 | */
69 | public function getKey($_);
70 |
71 | /**
72 | * Get a (multi-dimensional) array of all the configuration settings.
73 | *
74 | * @since 0.1.4
75 | *
76 | * @return array
77 | */
78 | public function getAll();
79 |
80 | /**
81 | * Get the an array with all the keys
82 | *
83 | * @since 0.1.0
84 | *
85 | * @return mixed
86 | */
87 | public function getKeys();
88 |
89 | /**
90 | * Is the Config valid?
91 | *
92 | * @since 0.1.0
93 | *
94 | * @return boolean
95 | */
96 | public function isValid();
97 |
98 | /**
99 | * Get a new config at a specific sub-level.
100 | *
101 | * @since 0.1.13
102 | *
103 | * @param string $_ List of keys.
104 | *
105 | * @return ConfigInterface
106 | */
107 | public function getSubConfig($_);
108 |
109 | /**
110 | * Serialize the config.
111 | *
112 | * @since 0.1.13
113 | *
114 | * @return array
115 | */
116 | public function __serialize(): array;
117 |
118 | /**
119 | * Unserialize the config.
120 | *
121 | * @since 0.1.13
122 | *
123 | * @param array $data The data to unserialize.
124 | */
125 | public function __unserialize(array $data): void;
126 | }
127 |
--------------------------------------------------------------------------------
/src/Loader/LoaderFactory.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Loader;
13 |
14 | use BrightNucleus\Config\Exception\FailedToLoadConfigException;
15 | use Exception;
16 |
17 | /**
18 | * Class LoaderFactory.
19 | *
20 | * @since 0.4.0
21 | *
22 | * @package BrightNucleus\Config\Loader
23 | * @author Alain Schlesser
24 | */
25 | class LoaderFactory
26 | {
27 |
28 | /**
29 | * Array of fully qualified class names of known loaders.
30 | *
31 | * @var array
32 | *
33 | * @since 0.4.0
34 | */
35 | protected static $loaders = [
36 | 'BrightNucleus\Config\Loader\PHPLoader',
37 | 'BrightNucleus\Config\Loader\JSONLoader',
38 | ];
39 |
40 | /**
41 | * Array of instantiated loaders.
42 | *
43 | * These are lazily instantiated and added as needed.
44 | *
45 | * @var LoaderInterface[]
46 | *
47 | * @since 0.4.0
48 | */
49 | protected static $loaderInstances = [];
50 |
51 | /**
52 | * Create a new Loader from an URI.
53 | *
54 | * @since 0.4.0
55 | *
56 | * @param string $uri URI of the resource to create a loader for.
57 | *
58 | * @return LoaderInterface Loader that is able to load the given URI.
59 | * @throws FailedToLoadConfigException If no suitable loader was found.
60 | */
61 | public static function createFromUri($uri)
62 | {
63 | foreach (static::$loaders as $loader) {
64 | if ($loader::canLoad($uri)) {
65 | return static::getLoader($loader);
66 | }
67 | }
68 |
69 | throw new FailedToLoadConfigException(
70 | sprintf(
71 | _('Could not find a suitable loader for URI "%1$s".'),
72 | $uri
73 | )
74 | );
75 | }
76 |
77 | /**
78 | * Get an instance of a specific loader.
79 | *
80 | * The loader is lazily instantiated if needed.
81 | *
82 | * @since 0.4.0
83 | *
84 | * @param string $loaderClass Fully qualified class name of the loader to get.
85 | *
86 | * @return LoaderInterface Instance of the requested loader.
87 | * @throws FailedToLoadConfigException If the loader class could not be instantiated.
88 | */
89 | public static function getLoader($loaderClass)
90 | {
91 | try {
92 | if (! array_key_exists($loaderClass, static::$loaderInstances)) {
93 | static::$loaderInstances[$loaderClass] = new $loaderClass;
94 | }
95 |
96 | return static::$loaderInstances[$loaderClass];
97 | } catch (Exception $exception) {
98 | throw new FailedToLoadConfigException(
99 | sprintf(
100 | _('Could not instantiate the requested loader class "%1$s".'),
101 | $loaderClass
102 | )
103 | );
104 | }
105 | }
106 |
107 | /**
108 | * Register a new loader.
109 | *
110 | * @since 0.4.0
111 | *
112 | * @param string $loader Fully qualified class name of a loader implementing LoaderInterface.
113 | */
114 | public static function registerLoader($loader)
115 | {
116 | if (in_array($loader, static::$loaders, true)) {
117 | return;
118 | }
119 |
120 | static::$loaders [] = $loader;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/ConfigSchema.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | use BrightNucleus\Exception\InvalidArgumentException;
15 |
16 | /**
17 | * Generic implementation of a configuration requirements check.
18 | *
19 | * @since 0.1.0
20 | *
21 | * @package BrightNucleus\Config
22 | * @author Alain Schlesser
23 | */
24 | class ConfigSchema extends AbstractConfigSchema
25 | {
26 |
27 | /**
28 | * The key that is used in the schema to define a default value.
29 | */
30 | const DEFAULT_VALUE = 'default';
31 | /**
32 | * The key that is used in the schema to define a required value.
33 | */
34 | const REQUIRED_KEY = 'required';
35 |
36 | /**
37 | * Instantiate a ConfigSchema object.
38 | *
39 | * @since 0.1.0
40 | *
41 | * @param ConfigInterface|array $schema The schema to parse.
42 | *
43 | * @throws InvalidArgumentException
44 | */
45 | public function __construct($schema)
46 | {
47 | if ($schema instanceof ConfigInterface) {
48 | $schema = $schema->getArrayCopy();
49 | }
50 |
51 | if (! is_array($schema)) {
52 | throw new InvalidArgumentException(
53 | sprintf(
54 | _('Invalid schema source: %1$s'),
55 | print_r($schema, true)
56 | )
57 | );
58 | }
59 |
60 | array_walk($schema, [$this, 'parseSchema']);
61 | }
62 |
63 | /**
64 | * Parse a single provided schema entry.
65 | *
66 | * @since 0.1.0
67 | *
68 | * @param mixed $data The data associated with the key.
69 | * @param string $key The key of the schema data.
70 | */
71 | protected function parseSchema($data, $key)
72 | {
73 | $this->parseDefined($key);
74 |
75 | if (array_key_exists(self::REQUIRED_KEY, $data)) {
76 | $this->parseRequired(
77 | $key,
78 | $data[self::REQUIRED_KEY]
79 | );
80 | }
81 |
82 | if (array_key_exists(self::DEFAULT_VALUE, $data)) {
83 | $this->parseDefault(
84 | $key,
85 | $data[self::DEFAULT_VALUE]
86 | );
87 | }
88 | }
89 |
90 | /**
91 | * Parse the set of defined values.
92 | *
93 | * @since 0.1.0
94 | *
95 | * @param string $key The key of the schema data.
96 | */
97 | protected function parseDefined($key)
98 | {
99 | $this->defined[] = $key;
100 | }
101 |
102 | /**
103 | * Parse the set of required values.
104 | *
105 | * @since 0.1.0
106 | *
107 | * @param string $key The key of the schema data.
108 | * @param mixed $data The data associated with the key.
109 | */
110 | protected function parseRequired($key, $data)
111 | {
112 | if ($this->isTruthy($data)) {
113 | $this->required[] = $key;
114 | }
115 | }
116 |
117 | /**
118 | * Parse the set of default values.
119 | *
120 | * @since 0.1.0
121 | *
122 | * @param string $key The key of the schema data.
123 | * @param mixed $data The data associated with the key.
124 | */
125 | protected function parseDefault($key, $data)
126 | {
127 | $this->defaults[$key] = $data;
128 | }
129 |
130 | /**
131 | * Return a boolean true or false for an arbitrary set of data. Recognizes
132 | * several different string values that should be valued as true.
133 | *
134 | * @since 0.1.0
135 | *
136 | * @param mixed $data The data to evaluate.
137 | *
138 | * @return bool
139 | */
140 | protected function isTruthy($data)
141 | {
142 | $truthy_values = [
143 | true,
144 | 1,
145 | 'true',
146 | 'True',
147 | 'TRUE',
148 | 'y',
149 | 'Y',
150 | 'yes',
151 | 'Yes',
152 | 'YES',
153 | '√',
154 | ];
155 |
156 | return in_array($data, $truthy_values, true);
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/ConfigTrait.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | use BrightNucleus\Config\Exception\FailedToProcessConfigException;
15 | use Exception;
16 |
17 | /**
18 | * Basic config processing that can be included within classes.
19 | *
20 | * @since 0.1.2
21 | *
22 | * @package BrightNucleus\Config
23 | * @author Alain Schlesser
24 | */
25 | trait ConfigTrait
26 | {
27 |
28 | /**
29 | * Reference to the Config object.
30 | *
31 | * @since 0.1.2
32 | *
33 | * @var ConfigInterface
34 | */
35 | protected $config;
36 |
37 | /**
38 | * Process the passed-in configuration file.
39 | *
40 | * @since 0.1.2
41 | *
42 | * @param ConfigInterface $config The Config to process.
43 | * @param string ... List of keys.
44 | *
45 | * @throws FailedToProcessConfigException If the arguments could not be parsed into a Config.
46 | */
47 | protected function processConfig(ConfigInterface $config)
48 | {
49 | if (func_num_args() > 1) {
50 | try {
51 | $keys = func_get_args();
52 | array_shift($keys);
53 | $config = $config->getSubConfig($keys);
54 | } catch (Exception $exception) {
55 | throw new FailedToProcessConfigException(
56 | sprintf(
57 | _('Could not process the config with the arguments "%1$s".'),
58 | print_r(func_get_args(), true)
59 | )
60 | );
61 | }
62 | }
63 | $this->config = $config;
64 | }
65 |
66 | /**
67 | * Check whether the Config has a specific key.
68 | *
69 | * To get a value several levels deep, add the keys for each level as a comma-separated list.
70 | *
71 | * @since 0.1.2
72 | * @since 0.1.5 Accepts list of keys.
73 | *
74 | * @param string|array $_ List of keys.
75 | *
76 | * @return bool Whether the key is known.
77 | */
78 | protected function hasConfigKey($_)
79 | {
80 | $keys = func_get_args();
81 |
82 | return $this->config->hasKey($keys);
83 | }
84 |
85 | /**
86 | * Get the Config value for a specific key.
87 | *
88 | * To get a value several levels deep, add the keys for each level as a comma-separated list.
89 | *
90 | * @since 0.1.2
91 | * @since 0.1.5 Accepts list of keys.
92 | *
93 | * @param string|array $_ List of keys.
94 | *
95 | * @return mixed Value of the key.
96 | */
97 | protected function getConfigKey($_)
98 | {
99 | $keys = func_get_args();
100 |
101 | return $this->config->getKey($keys);
102 | }
103 |
104 | /**
105 | * Get the callable Config value for a specific key.
106 | *
107 | * If the fetched value is indeed a callable, it will be executed with the provided arguments, and the resultant
108 | * value will be returned instead.
109 | *
110 | * @since 0.4.8
111 | *
112 | * @param string|array $key Key or array of nested keys.
113 | * @param array $args Optional. Array of arguments to pass to the callable.
114 | *
115 | * @return mixed Resultant value of the key's callable.
116 | */
117 | protected function getConfigCallable($key, array $args = [])
118 | {
119 | $value = $this->config->getKey($key);
120 |
121 | if (is_callable($value)) {
122 | $value = $value(...$args);
123 | }
124 |
125 | return $value;
126 | }
127 |
128 | /**
129 | * Get a (multi-dimensional) array of all the configuration settings.
130 | *
131 | * @since 0.1.4
132 | *
133 | * @return array All the configuration settings.
134 | */
135 | protected function getConfigArray()
136 | {
137 | return $this->config->getAll();
138 | }
139 |
140 | /**
141 | * Get an array of all the keys that are known by the Config.
142 | *
143 | * @since 0.1.2
144 | *
145 | * @return array Array of strings containing all the keys.
146 | */
147 | protected function getConfigKeys()
148 | {
149 | return $this->config->getKeys();
150 | }
151 |
152 | /**
153 | * Get a default configuration in case none was injected into the constructor.
154 | *
155 | * The name and path of the configuration needs to be set as a const called DEFAULT_CONFIG within the class
156 | * containing the trait. The path needs to be relative to the location of the containing class file.
157 | *
158 | * @since 0.4.2
159 | *
160 | * @return ConfigInterface Configuration settings to use.
161 | */
162 | protected function fetchDefaultConfig()
163 | {
164 | $configFile = method_exists($this, 'getDefaultConfigFile')
165 | ? $this->getDefaultConfigFile()
166 | : __DIR__ . '/../config/defaults.php';
167 |
168 | return $this->fetchConfig($configFile);
169 | }
170 |
171 | /**
172 | * Get a configuration from a specified $file.
173 | *
174 | * If file is not accessible or readable, returns an empty Config.
175 | *
176 | * @since 0.4.2
177 | *
178 | * @return ConfigInterface Configuration settings to use.
179 | */
180 | protected function fetchConfig($configFile)
181 | {
182 | if (is_string($configFile) && ! is_readable($configFile)) {
183 | $configFile = [];
184 | }
185 |
186 | return ConfigFactory::create($configFile);
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/AbstractConfig.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | use ArrayObject;
15 | use BrightNucleus\Config\Exception\KeyNotFoundException;
16 | use Exception;
17 |
18 | /**
19 | * Handles basic manipulation of configuration values.
20 | *
21 | * @since 0.1.0
22 | *
23 | * @package BrightNucleus\Config
24 | * @author Alain Schlesser
25 | */
26 | abstract class AbstractConfig extends ArrayObject implements ConfigInterface
27 | {
28 |
29 | /**
30 | * Array of strings that are used as delimiters to parse configuration keys.
31 | *
32 | * @since 0.1.6
33 | *
34 | * @var array
35 | */
36 | protected $delimiter = ['\\', '/', '.'];
37 |
38 | /**
39 | * Instantiate the AbstractConfig object.
40 | *
41 | * @since 0.1.0
42 | * @since 0.1.6 Accepts a delimiter to parse configuration keys.
43 | *
44 | * @param array $config Array with settings.
45 | * @param string[]|string|null $delimiter A string or array of strings that are used as delimiters to parse
46 | * configuration keys. Defaults to "\", "/" & ".".
47 | */
48 | public function __construct(array $config, $delimiter = null)
49 | {
50 | // Make sure the config entries can be accessed as properties.
51 | parent::__construct($config, ArrayObject::ARRAY_AS_PROPS);
52 |
53 | if (null !== $delimiter) {
54 | $this->delimiter = (array)$delimiter;
55 | }
56 | }
57 |
58 | /**
59 | * Get the value of a specific key.
60 | *
61 | * To get a value several levels deep, add the keys for each level as a comma-separated list.
62 | *
63 | * @since 0.1.0
64 | * @since 0.1.4 Accepts list of keys.
65 | *
66 | * @param string|array $_ List of keys.
67 | *
68 | * @return mixed
69 | * @throws KeyNotFoundException If an unknown key is requested.
70 | */
71 | public function getKey($_)
72 | {
73 | $keys = $this->validateKeys(func_get_args());
74 |
75 | $keys = array_reverse($keys);
76 | $array = $this->getArrayCopy();
77 | while (count($keys) > 0) {
78 | $key = array_pop($keys);
79 | $array = $array[$key];
80 | }
81 |
82 | return $array;
83 | }
84 |
85 | /**
86 | * Check whether the Config has a specific key.
87 | *
88 | * To check a value several levels deep, add the keys for each level as a comma-separated list.
89 | *
90 | * @since 0.1.0
91 | * @since 0.1.4 Accepts list of keys.
92 | *
93 | * @param string|array $_ List of keys.
94 | *
95 | * @return bool
96 | */
97 | public function hasKey($_)
98 | {
99 | try {
100 | $keys = array_reverse($this->getKeyArguments(func_get_args()));
101 |
102 | $array = $this->getArrayCopy();
103 | while (count($keys) > 0) {
104 | $key = array_pop($keys);
105 | if (! array_key_exists($key, $array)) {
106 | return false;
107 | }
108 | $array = $array[$key];
109 | }
110 | } catch (Exception $exception) {
111 | return false;
112 | }
113 |
114 | return true;
115 | }
116 |
117 | /**
118 | * Get a (multi-dimensional) array of all the configuration settings.
119 | *
120 | * @since 0.1.4
121 | *
122 | * @return array
123 | */
124 | public function getAll()
125 | {
126 | return $this->getArrayCopy();
127 | }
128 |
129 | /**
130 | * Get the an array with all the keys
131 | *
132 | * @since 0.1.0
133 | * @return array
134 | */
135 | public function getKeys()
136 | {
137 | return array_keys((array)$this);
138 | }
139 |
140 | /**
141 | * Get a new config at a specific sub-level.
142 | *
143 | * @since 0.1.13
144 | *
145 | * @param string|array $_ List of keys.
146 | *
147 | * @return ConfigInterface
148 | * @throws KeyNotFoundException If an unknown key is requested.
149 | */
150 | public function getSubConfig($_)
151 | {
152 | $keys = $this->validateKeys(func_get_args());
153 |
154 | $subConfig = clone $this;
155 | $subConfig->reduceToSubKey($keys);
156 |
157 | return $subConfig;
158 | }
159 |
160 | /**
161 | * Validate a set of keys to make sure they exist.
162 | *
163 | * @since 0.1.13
164 | *
165 | * @param string|array $_ List of keys.
166 | *
167 | * @return array List of keys.
168 | * @throws KeyNotFoundException If an unknown key is requested.
169 | */
170 | public function validateKeys($_)
171 | {
172 | $keys = $this->getKeyArguments(func_get_args());
173 |
174 | if (! $this->hasKey($keys)) {
175 | throw new KeyNotFoundException(
176 | sprintf(
177 | _('The configuration key %1$s does not exist.'),
178 | implode('->', $keys)
179 | )
180 | );
181 | }
182 |
183 | return $keys;
184 | }
185 |
186 | /**
187 | * Reduce the currently stored config array to a subarray at a specific level.
188 | *
189 | * @since 0.1.13
190 | *
191 | * @param array $keys Array of keys that point to a key down in the hierarchy.
192 | */
193 | protected function reduceToSubKey(array $keys)
194 | {
195 | $this->exchangeArray($this->getKey($keys));
196 | }
197 |
198 | /**
199 | * Recursively extract the configuration key arguments from an arbitrary array.
200 | *
201 | * @since 0.1.6
202 | *
203 | * @param array $arguments Array as fetched through get_func_args().
204 | *
205 | * @return array Array of strings.
206 | */
207 | protected function getKeyArguments($arguments)
208 | {
209 | $keys = [];
210 | foreach ($arguments as $argument) {
211 | if (is_array($argument)) {
212 | $keys = array_merge($keys, $this->getKeyArguments($argument));
213 | }
214 | if (is_string($argument)) {
215 | $keys = array_merge($keys, $this->parseKeysString($argument));
216 | }
217 | }
218 |
219 | return $keys;
220 | }
221 |
222 | /**
223 | * Extract individual keys from a delimited string.
224 | *
225 | * @since 0.1.6
226 | *
227 | * @param string $keyString Delimited string of keys.
228 | *
229 | * @return array Array of key strings.
230 | */
231 | protected function parseKeysString($keyString)
232 | {
233 | // Replace all of the configured delimiters by the first one, so that we can then use explode().
234 | $normalizedString = str_replace($this->delimiter, $this->delimiter[0], $keyString);
235 |
236 | return (array)explode($this->delimiter[0], $normalizedString);
237 | }
238 |
239 | /**
240 | * Validate the Config file.
241 | *
242 | * @since 0.1.0
243 | * @return boolean
244 | */
245 | abstract public function isValid();
246 | }
247 |
--------------------------------------------------------------------------------
/src/Config.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | use BrightNucleus\Config\ConfigSchemaInterface as Schema;
15 | use BrightNucleus\Config\ConfigValidatorInterface as Validator;
16 | use BrightNucleus\Config\Exception\FailedToInstantiateParentException;
17 | use BrightNucleus\Config\Exception\FailedToLoadConfigException;
18 | use BrightNucleus\Config\Exception\FailedToResolveConfigException;
19 | use BrightNucleus\Config\Exception\InvalidConfigException;
20 | use BrightNucleus\Config\Exception\InvalidConfigurationSourceException;
21 | use Exception;
22 | use Symfony\Component\OptionsResolver\OptionsResolver;
23 |
24 | /**
25 | * Generic implementation of a Config object.
26 | *
27 | * @since 0.1.0
28 | *
29 | * @package BrightNucleus\Config
30 | * @author Alain Schlesser
31 | */
32 | class Config extends AbstractConfig
33 | {
34 |
35 | /**
36 | * The schema of the Config file.
37 | *
38 | * @var Schema
39 | */
40 | protected $schema;
41 |
42 | /**
43 | * The Validator class that gets asked to do the validation of the config.
44 | *
45 | * @since 0.1.0
46 | *
47 | * @var Validator
48 | */
49 | protected $validator;
50 |
51 | /**
52 | * Instantiate the Config object.
53 | *
54 | * It accepts either an array with the configuration settings, or a
55 | * filename pointing to a PHP file it can include.
56 | *
57 | * @since 0.1.0
58 | * @since 0.1.6 Accepts a delimiter to parse configuration keys.
59 | *
60 | * @param array|string $config Array with settings or filename for the
61 | * settings file.
62 | * @param Schema|null $schema Optional. Config that contains default
63 | * values that can get overwritten.
64 | * @param Validator|null $validator Optional. Validator class that does the
65 | * actual validation.
66 | * @param string[]|string|null $delimiter A string or array of strings that are used as delimiters to parse
67 | * configuration keys. Defaults to "\", "/" & ".".
68 | *
69 | * @throws InvalidConfigurationSourceException If the config source is not a string or array.
70 | * @throws FailedToInstantiateParentException If the parent class could not be instantiated.
71 | * @throws FailedToLoadConfigException If loading of the config source failed.
72 | * @throws FailedToResolveConfigException If the config file could not be resolved.
73 | * @throws InvalidConfigException If the config file is not valid.
74 | */
75 | public function __construct(
76 | $config,
77 | ?Schema $schema = null,
78 | ?Validator $validator = null,
79 | $delimiter = null
80 | ) {
81 | $this->schema = $schema;
82 | $this->validator = $validator;
83 |
84 | // Make sure $config is either a string or array.
85 | if (! (is_string($config) || is_array($config))) {
86 | throw new InvalidConfigurationSourceException(
87 | sprintf(
88 | _('Invalid configuration source: %1$s'),
89 | print_r($config, true)
90 | )
91 | );
92 | }
93 |
94 | if (is_string($config)) {
95 | $config = Loader::load($config);
96 | }
97 |
98 | // Run the $config through the OptionsResolver.
99 | $config = $this->resolveOptions($config);
100 |
101 | // Instantiate the parent class.
102 | try {
103 | parent::__construct($config, $delimiter);
104 | } catch (Exception $exception) {
105 | throw new FailedToInstantiateParentException(
106 | sprintf(
107 | _('Could not instantiate the configuration through its parent. Reason: %1$s'),
108 | $exception->getMessage()
109 | )
110 | );
111 | }
112 |
113 | // Finally, validate the resulting config.
114 | if (! $this->isValid()) {
115 | throw new InvalidConfigException(
116 | sprintf(
117 | _('ConfigInterface file is not valid: %1$s'),
118 | print_r($config, true)
119 | )
120 | );
121 | }
122 | }
123 |
124 | /**
125 | * Validate the Config file.
126 | *
127 | * @since 0.1.0
128 | *
129 | * @return boolean
130 | */
131 | public function isValid()
132 | {
133 | if ($this->validator) {
134 | return $this->validator->isValid($this);
135 | }
136 |
137 | return true;
138 | }
139 |
140 | /**
141 | * Process the passed-in defaults and merge them with the new values, while
142 | * checking that all required options are set.
143 | *
144 | * @since 0.1.0
145 | *
146 | * @param array $config Configuration settings to resolve.
147 | *
148 | * @return array Resolved configuration settings.
149 | * @throws FailedToResolveConfigException If there are errors while resolving the options.
150 | */
151 | protected function resolveOptions($config)
152 | {
153 | if (! $this->schema) {
154 | return $config;
155 | }
156 |
157 | try {
158 | $resolver = new OptionsResolver();
159 | if ($this->configureOptions($resolver)) {
160 | $config = $resolver->resolve($config);
161 | }
162 | } catch (Exception $exception) {
163 | throw new FailedToResolveConfigException(
164 | sprintf(
165 | _('Error while resolving config options: %1$s'),
166 | $exception->getMessage()
167 | )
168 | );
169 | }
170 |
171 | return $config;
172 | }
173 |
174 | /**
175 | * Configure the possible and required options for the Config.
176 | *
177 | * This should return a bool to let the resolve_options() know whether the
178 | * actual resolving needs to be done or not.
179 | *
180 | * @since 0.1.0
181 | *
182 | * @param OptionsResolver $resolver Reference to the OptionsResolver
183 | * instance.
184 | *
185 | * @return bool Whether to do the resolving.
186 | * @throws FailedToResolveConfigException If there are errors while processing.
187 | */
188 | protected function configureOptions(OptionsResolver $resolver)
189 | {
190 | $defined = $this->schema->getDefinedOptions();
191 | $defaults = $this->schema->getDefaultOptions();
192 | $required = $this->schema->getRequiredOptions();
193 |
194 | if (! $defined && ! $defaults && ! $required) {
195 | return false;
196 | }
197 |
198 | try {
199 | if ($defined) {
200 | $resolver->setDefined($defined);
201 | }
202 | if ($defaults) {
203 | $resolver->setDefaults($defaults);
204 | }
205 | if ($required) {
206 | $resolver->setRequired($required);
207 | }
208 | } catch (Exception $exception) {
209 | throw new FailedToResolveConfigException(
210 | sprintf(
211 | _('Error while processing config options: %1$s'),
212 | $exception->getMessage()
213 | )
214 | );
215 | }
216 |
217 | return true;
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/src/ConfigFactory.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016-2017 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config;
13 |
14 | use Exception;
15 |
16 | /**
17 | * Create new object instances that implement ConfigInterface.
18 | *
19 | * @since 0.3.0
20 | *
21 | * @package BrightNucleus\Config
22 | * @author Alain Schlesser
23 | */
24 | class ConfigFactory
25 | {
26 |
27 | /**
28 | * Cached contents of the config files.
29 | *
30 | * @since 0.4.3
31 | *
32 | * @var array
33 | */
34 | protected static $configFilesCache = [];
35 |
36 | /**
37 | * Create a new ConfigInterface object from a file.
38 | *
39 | * If a comma-separated list of files is provided, they are checked in sequence until the first one could be loaded
40 | * successfully.
41 | *
42 | * @since 0.3.0
43 | *
44 | * @param string|array $_ List of files.
45 | *
46 | * @return ConfigInterface Instance of a ConfigInterface implementation.
47 | */
48 | public static function createFromFile($_)
49 | {
50 | $files = array_reverse(func_get_args());
51 |
52 | if (is_array($files[0])) {
53 | $files = $files[0];
54 | }
55 |
56 | while (count($files) > 0) {
57 | try {
58 | $file = array_pop($files);
59 |
60 | if (! is_string($file)) {
61 | continue;
62 | }
63 |
64 | if (! is_readable($file)) {
65 | continue;
66 | }
67 |
68 | $config = static::createFromArray(
69 | static::getFromCache($file, function ($file) {
70 | return Loader::load($file);
71 | })
72 | );
73 |
74 | if (null === $config) {
75 | continue;
76 | }
77 |
78 | return $config;
79 | } catch (Exception $exception) {
80 | // Fail silently and try next file.
81 | }
82 | }
83 |
84 | return static::createFromArray([]);
85 | }
86 |
87 | /**
88 | * Create a new ConfigInterface object from an array.
89 | *
90 | * @since 0.3.0
91 | *
92 | * @param array $array Array with configuration values.
93 | *
94 | * @return ConfigInterface Instance of a ConfigInterface implementation.
95 | */
96 | public static function createFromArray(array $array)
97 | {
98 | try {
99 | return new Config($array);
100 | } catch (Exception $exception) {
101 | // Fail silently and try next file.
102 | }
103 |
104 | return null;
105 | }
106 |
107 | /**
108 | * Create a new ConfigInterface object.
109 | *
110 | * Tries to deduce the correct creation method by inspecting the provided arguments.
111 | *
112 | * @since 0.3.0
113 | *
114 | * @param mixed $_ Array with configuration values.
115 | *
116 | * @return ConfigInterface Instance of a ConfigInterface implementation.
117 | */
118 | public static function create($_)
119 | {
120 | if (func_num_args() < 1) {
121 | return static::createFromArray([]);
122 | }
123 |
124 | $arguments = func_get_args();
125 |
126 | if (is_array($arguments[0]) && func_num_args() === 1) {
127 | return static::createFromArray($arguments[0]);
128 | }
129 |
130 | return static::createFromFile($arguments);
131 | }
132 |
133 | /**
134 | * Create a new ConfigInterface object, by merging several files together.
135 | *
136 | * Duplicate keys in later files will override those in earlier files.
137 | *
138 | * @since 0.4.6
139 | *
140 | * @param mixed $_ Array with configuration values.
141 | *
142 | * @return ConfigInterface Instance of a ConfigInterface implementation.
143 | */
144 | public static function merge($_)
145 | {
146 | if (func_num_args() < 1) {
147 | return static::createFromArray([]);
148 | }
149 |
150 | $arguments = func_get_args();
151 |
152 | if (is_array($arguments[0]) && func_num_args() === 1) {
153 | return static::createFromArray($arguments[0]);
154 | }
155 |
156 | return static::mergeFromFiles($arguments);
157 | }
158 |
159 | /**
160 | * Create a new ConfigInterface object by merging data from several files.
161 | *
162 | * If a comma-separated list of files is provided, they are loaded in sequence and later files override settings in
163 | * earlier files.
164 | *
165 | * @since 0.4.6
166 | *
167 | * @param string|array $_ List of files.
168 | *
169 | * @return ConfigInterface Instance of a ConfigInterface implementation.
170 | */
171 | public static function mergeFromFiles($_)
172 | {
173 | $files = array_reverse(func_get_args());
174 | $data = [];
175 |
176 | if (is_array($files[0])) {
177 | $files = array_reverse($files[0]);
178 | }
179 |
180 | while (count($files) > 0) {
181 | try {
182 | $file = array_pop($files);
183 |
184 | if (! is_readable($file)) {
185 | continue;
186 | }
187 |
188 | $new_data = static::getFromCache($file, function ($file) {
189 | return Loader::load($file);
190 | });
191 |
192 | if (null === $data) {
193 | continue;
194 | }
195 |
196 | $data = array_replace_recursive($data, $new_data);
197 | } catch (Exception $exception) {
198 | // Fail silently and try next file.
199 | }
200 | }
201 |
202 | return static::createFromArray($data);
203 | }
204 |
205 | /**
206 | * Create a new ConfigInterface object from a file and return a sub-portion of it.
207 | *
208 | * The first argument needs to be the file name to load, and the subsequent arguments will be passed on to
209 | * `Config::getSubConfig()`.
210 | *
211 | * @since 0.4.5
212 | *
213 | * @param mixed $_ File name of the config to load as a string, followed by an array of keys to pass to
214 | * `Config::getSubConfig()`.
215 | *
216 | * @return ConfigInterface Instance of a ConfigInterface implementation.
217 | */
218 | public static function createSubConfig($_)
219 | {
220 | if (func_num_args() < 2) {
221 | return static::createFromArray([]);
222 | }
223 |
224 | $arguments = func_get_args();
225 | $file = array_shift($arguments);
226 |
227 | $config = static::createFromFile($file);
228 |
229 | return $config->getSubConfig($arguments);
230 | }
231 |
232 | /**
233 | * Get a config file from the config file cache.
234 | *
235 | * @since 0.4.4
236 | *
237 | * @param string $identifier Identifier to look for in the cache.
238 | * @param mixed $fallback Fallback to use to fill the cache. If $fallback is a callable, it will be executed
239 | * with $identifier as an argument.
240 | *
241 | * @return mixed The latest content of the cache for the given identifier.
242 | */
243 | protected static function getFromCache($identifier, $fallback)
244 | {
245 | if (! array_key_exists($identifier, static::$configFilesCache)) {
246 | static::$configFilesCache[$identifier] = is_callable($fallback)
247 | ? $fallback($identifier)
248 | : $fallback;
249 | }
250 |
251 | return static::$configFilesCache[$identifier];
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## [0.4.12] - 2019-10-16
6 | ### Fixed
7 | - Correct invalid Composer configuration.
8 | - Add Composer lock file to .gitignore.
9 |
10 | ## [0.4.11] - 2019-10-16
11 | ### Added
12 | - Added JSON loader. Props [@pascalknecht](https://github.com/pascalknecht)
13 | - Fixed docblocks for PHP & JSON loader `canLoad()` methods.
14 | - Adapted docblock for `LoaderInterface::load()` method.
15 |
16 | ## [0.4.10] - 2017-02-16
17 | ### Fixed
18 | - Fix Coveralls integration.
19 |
20 | ## [0.4.9] - 2017-02-16
21 | ### Added
22 | - Added several checks that can be run through Composer scripts.
23 | - Added Travis CI configuration.
24 |
25 | ## [0.4.8] - 2016-08-06
26 | ### Added
27 | - Added `ConfigTrait::getConfigCallable()` to get a callable and immmediately execute it to get the resultant value.
28 | - Added corresponding unit test.
29 |
30 | ## [0.4.7] - 2016-07-22
31 | ### Fixed
32 | - Fixed the way arrays were merged recursively.
33 | - Added regression test.
34 |
35 | ## [0.4.6] - 2016-07-22
36 | ### Added
37 | - Added `ConfigFactory::merge()` to merge several Config files into one.
38 | - Added corresponding unit test.
39 |
40 | ## [0.4.5] - 2016-07-05
41 | ### Added
42 | - Added `ConfigFactory::createSubConfig()` to quickly create a new config at a sublevel.
43 | - Added corresponding unit test.
44 |
45 | ## [0.4.4] - 2016-07-05
46 | ### Changed
47 | - Extracted the cache retrieval in `ConfigFactory` into its own method.
48 |
49 | ## [0.4.3] - 2016-07-05
50 | ### Added
51 | - Added file caching to CreateFactory.
52 | - Added unit tests to make sure the caching works.
53 |
54 | ## [0.4.2] - 2016-06-09
55 | ### Added
56 | - Added trait functionality to load a default config file.
57 | - Added corresponding entry in the README.md file.
58 |
59 | ## [0.4.1] - 2016-06-08
60 | ### Removed
61 | - Removed `beberlei/assert` and all assert checks for now, until a better replacement has been found.
62 |
63 | ## [0.4.0] - 2016-04-28
64 | ### Added
65 | - Added extensible loader framework that includes `PHPLoader` and can be extended by other packages.
66 |
67 | ### Changed
68 | - Changed the extensions that are being thrown to more specific ones. They types are extensions of the ones that were previously used, but some exception messages have changed.
69 | - Generic `Config` class now uses the loader framework instead of reading the data on its own.
70 |
71 | ## [0.3.1] - 2016-04-05
72 | ### Changed
73 | - Update Composer dependencies.
74 |
75 | ## [0.3.0] - 2016-04-04
76 | ### Added
77 | - Added `ConfigFactory`.
78 |
79 | ### Changed
80 | - Changed licensing from GPL2 to MIT.
81 |
82 | ## [0.2.8] - 2016-03-28
83 | ### Changed
84 | - Bumped [PHP Composter PHPCS PSR-2](https://github.com/php-composter/php-composter-phpcs-psr2) version.
85 |
86 | ## [0.2.7] - 2016-03-28
87 | ### Changed
88 | - Switched from a custom `pre-commit` script to the [PHP Composter PHPCS PSR-2](https://github.com/php-composter/php-composter-phpcs-psr2) package.
89 |
90 | ## [0.2.6] - 2016-03-22
91 | ### Fixed
92 | - Switch `beberlei/assert` back to official branch. Issue [#138](https://github.com/beberlei/assert/issues/138) has been fixed with v2.5.
93 |
94 | ## [0.2.5] - 2016-03-04
95 | ### Fixed
96 | - Switch `beberlei/assert` to own fork until [#138](https://github.com/beberlei/assert/issues/138) has been fixed.
97 |
98 | ## [0.2.4] - 2016-02-26
99 | ### Added
100 | - Better documentation in `README.md`.
101 |
102 | ### Fixed
103 | - Corrected type hints for variadic methods.
104 |
105 | ## [0.2.3] - 2016-02-19
106 | ### Fixed
107 | - Remove test cases that were not needed anymore due to the addition of the `$_` argument in v0.2.2.
108 | - Remove const array for truthy values and replace by local variable, to avoid PHP5.6+ requirement.
109 |
110 | ## [0.2.2] - 2016-02-18
111 | ### Fixed
112 | - Add dummy variables in methods with a variable number of arguments to fix PHPStorm inspections.
113 | - Fix case in `reduceToSubKey()` method.
114 |
115 | ## [0.2.1] - 2016-02-18
116 | ### Fixed
117 | - Bumped version requirement for `brightnucleus/exceptions` to v0.2+.
118 |
119 | ## [0.2.0] - 2016-02-17
120 | ### Added
121 | - Added `getSubConfig()` to extract the subtree at a specific level & key.
122 | - Added corresponding tests.
123 |
124 | ## [0.1.12] - 2016-02-17
125 | ### Fixed
126 | - Updated `brightnucleus/exceptions` dependency.
127 |
128 | ## [0.1.11] - 2016-02-17
129 | ### Fixed
130 | - Lowered version requirement for `symfony/options-resolver`.
131 |
132 | ## [0.1.10] - 2016-02-16
133 | ### Added
134 | - Added `brightnucleus/exceptions` to have coherentexceptions across all Bright Nucleus packages.
135 |
136 | ## [0.1.9] - 2016-02-16
137 | ### Added
138 | - The `beberlei/assert` package has been added as a development dependency.
139 | - Several assertions have been added to check the arguments passed in to the methods.
140 | - A `pre-commit` hook has been added to run unit tests and validate code standards.
141 |
142 | ### Fixed
143 | - Methods have been rearranged.
144 | - A few code style tweaks have been made to adhere to PHPCS PSR-2.
145 |
146 | ## [0.1.8] - 2016-02-11
147 | ### Added
148 | - The `ConfigTrait::processConfig()` method now accepts one or more additional parameters (can be delimited strings) to start with a Config at a specific level. Useful to include different `vendor\package` levels in a single merged Config file.
149 |
150 | ## [0.1.7] - 2016-02-11
151 | ### Fixed
152 | - The `hasKey()` method doesn't throw an exception, returns `false` instead.
153 |
154 | ## [0.1.6] - 2016-02-11
155 | ### Added
156 | - The `has*` & `get*` methods now support keys with delimiters. The delimiters are set via the Config constructor.
157 | - Tests for the above.
158 |
159 | ## [0.1.5] - 2016-02-11
160 | ### Added
161 | - `ConfigTrait::hasConfigKey()` and `ConfigTrait::getConfigKey()` now support a list of strings to fetch a value from several levels deep.
162 | - Tests for the above.
163 |
164 | ## [0.1.4] - 2016-02-11
165 | ### Added
166 | - `AbstractConfig:getAll()` and `ConfigTrait::getConfigArray()`.
167 | - `hasKey()` and `getKey()` now support a list of strings to fetch a value from several levels deep.
168 | - Tests for the above.
169 |
170 | ### Fixed
171 | - PHP requirement for unit tests was lowered from 5.6 to 5.4.
172 |
173 | ## [0.1.3] - 2016-02-10
174 | ### Added
175 | - Badges in README.md
176 |
177 | ### Fixed
178 | - Update Composer to use PHPUnit 4 to reduce PHP version requirements.
179 | - Fix several minor code quality issues.
180 |
181 | ## [0.1.2] - 2016-02-01
182 | ### Added
183 | - ConfigTrait.
184 | - Tests for ConfigTrait.
185 |
186 | ## [0.1.1] - 2016-01-29
187 | ### Added
188 | - Tests for schema requirements.
189 |
190 | ### Fixed
191 | - Don't instantiate `OptionsResolver` if not needed.
192 | - Formatting tweaks
193 |
194 | ## [0.1.0] - 2016-01-29
195 | ### Added
196 | - Initial release to GitHub.
197 |
198 | [0.4.12]: https://github.com/brightnucleus/config/compare/v0.4.11...v0.4.12
199 | [0.4.11]: https://github.com/brightnucleus/config/compare/v0.4.10...v0.4.11
200 | [0.4.10]: https://github.com/brightnucleus/config/compare/v0.4.9...v0.4.10
201 | [0.4.9]: https://github.com/brightnucleus/config/compare/v0.4.8...v0.4.9
202 | [0.4.8]: https://github.com/brightnucleus/config/compare/v0.4.7...v0.4.8
203 | [0.4.7]: https://github.com/brightnucleus/config/compare/v0.4.6...v0.4.7
204 | [0.4.6]: https://github.com/brightnucleus/config/compare/v0.4.5...v0.4.6
205 | [0.4.5]: https://github.com/brightnucleus/config/compare/v0.4.4...v0.4.5
206 | [0.4.4]: https://github.com/brightnucleus/config/compare/v0.4.3...v0.4.4
207 | [0.4.3]: https://github.com/brightnucleus/config/compare/v0.4.2...v0.4.3
208 | [0.4.2]: https://github.com/brightnucleus/config/compare/v0.4.1...v0.4.2
209 | [0.4.1]: https://github.com/brightnucleus/config/compare/v0.4.0...v0.4.1
210 | [0.4.0]: https://github.com/brightnucleus/config/compare/v0.3.1...v0.4.0
211 | [0.3.1]: https://github.com/brightnucleus/config/compare/v0.3.0...v0.3.1
212 | [0.3.0]: https://github.com/brightnucleus/config/compare/v0.2.8...v0.3.0
213 | [0.2.8]: https://github.com/brightnucleus/config/compare/v0.2.7...v0.2.8
214 | [0.2.7]: https://github.com/brightnucleus/config/compare/v0.2.6...v0.2.7
215 | [0.2.6]: https://github.com/brightnucleus/config/compare/v0.2.5...v0.2.6
216 | [0.2.5]: https://github.com/brightnucleus/config/compare/v0.2.4...v0.2.5
217 | [0.2.4]: https://github.com/brightnucleus/config/compare/v0.2.3...v0.2.4
218 | [0.2.3]: https://github.com/brightnucleus/config/compare/v0.2.2...v0.2.3
219 | [0.2.2]: https://github.com/brightnucleus/config/compare/v0.2.1...v0.2.2
220 | [0.2.1]: https://github.com/brightnucleus/config/compare/v0.2.0...v0.2.1
221 | [0.2.0]: https://github.com/brightnucleus/config/compare/v0.1.12...v0.2.0
222 | [0.1.12]: https://github.com/brightnucleus/config/compare/v0.1.11...v0.1.12
223 | [0.1.11]: https://github.com/brightnucleus/config/compare/v0.1.10...v0.1.11
224 | [0.1.10]: https://github.com/brightnucleus/config/compare/v0.1.9...v0.1.10
225 | [0.1.9]: https://github.com/brightnucleus/config/compare/v0.1.8...v0.1.9
226 | [0.1.8]: https://github.com/brightnucleus/config/compare/v0.1.7...v0.1.8
227 | [0.1.7]: https://github.com/brightnucleus/config/compare/v0.1.6...v0.1.7
228 | [0.1.6]: https://github.com/brightnucleus/config/compare/v0.1.5...v0.1.6
229 | [0.1.5]: https://github.com/brightnucleus/config/compare/v0.1.4...v0.1.5
230 | [0.1.4]: https://github.com/brightnucleus/config/compare/v0.1.3...v0.1.4
231 | [0.1.3]: https://github.com/brightnucleus/config/compare/v0.1.2...v0.1.3
232 | [0.1.2]: https://github.com/brightnucleus/config/compare/v0.1.1...v0.1.2
233 | [0.1.1]: https://github.com/brightnucleus/config/compare/v0.1.0...v0.1.1
234 | [0.1.0]: https://github.com/brightnucleus/config/compare/v0.0.0...v0.1.0
235 |
--------------------------------------------------------------------------------
/tests/ConfigFactoryTest.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Tests;
13 |
14 | use BrightNucleus\Config\ConfigFactory;
15 | use org\bovigo\vfs\vfsStream;
16 |
17 | /**
18 | * Class ConfigFactoryTest.
19 | *
20 | * @since 0.3.0
21 | *
22 | * @package BrightNucleus\Config
23 | * @author Alain Schlesser
24 | */
25 | class ConfigFactoryTest extends TestCase
26 | {
27 |
28 | /*
29 | * TODO: There's still lots of work to do to render these tests useful.
30 | */
31 |
32 | /*
33 | * Don't use an array const to avoid bumping PHP requirement to 5.6.
34 | */
35 | protected static $test_array = [
36 | 'random_string' => 'test_value',
37 | 'positive_integer' => 42,
38 | 'negative_integer' => -256,
39 | 'positive_boolean' => true,
40 | 'negative_boolean' => false,
41 | ];
42 |
43 | protected static $test_multi_array = [
44 | 'level1' => [
45 | 'level2' => [
46 | 'level3' => [
47 | 'level4_key' => 'level4_value',
48 | ],
49 | ],
50 | ],
51 | ];
52 |
53 | /**
54 | * Test creation from file.
55 | *
56 | * @covers \BrightNucleus\Config\ConfigFactory::createFromFile
57 | *
58 | * @since 0.3.0
59 | */
60 | public function testCreateFromFile()
61 | {
62 | $config = ConfigFactory::createFromFile(__DIR__ . '/fixtures/config_file.php');
63 |
64 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
65 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
66 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
67 | $this->assertTrue($config->hasKey('random_string'));
68 |
69 | $config2 = ConfigFactory::createFromFile(
70 | 'nonsense_file.php',
71 | 'still_nonsense.txt',
72 | __DIR__ . '/fixtures/config_file.php'
73 | );
74 |
75 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config2);
76 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config2);
77 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config2);
78 | $this->assertTrue($config2->hasKey('random_string'));
79 | }
80 |
81 | /**
82 | * Test creation from array.
83 | *
84 | * @covers \BrightNucleus\Config\ConfigFactory::createFromArray
85 | *
86 | * @since 0.3.0
87 | */
88 | public function testCreateFromArray()
89 | {
90 | $config = ConfigFactory::createFromArray(['some_key' => 'some_value']);
91 |
92 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
93 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
94 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
95 | $this->assertTrue($config->hasKey('some_key'));
96 | $this->assertEquals('some_value', $config->getKey('some_key'));
97 | }
98 |
99 | /**
100 | * Test creation from best guess using one file.
101 | *
102 | * @covers \BrightNucleus\Config\ConfigFactory::create
103 | *
104 | * @since 0.3.0
105 | */
106 | public function testCreateFromBestGuessUsingOneFile()
107 | {
108 | $config = ConfigFactory::create(__DIR__ . '/fixtures/config_file.php');
109 |
110 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
111 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
112 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
113 | $this->assertTrue($config->hasKey('random_string'));
114 | }
115 |
116 | /**
117 | * Test creation from best guess using several files.
118 | *
119 | * @covers \BrightNucleus\Config\ConfigFactory::create
120 | *
121 | * @since 0.3.0
122 | */
123 | public function testCreateFromBestGuessUsingSeveralFiles()
124 | {
125 | $config = ConfigFactory::create(
126 | 'nonsense_file.php',
127 | 'still_nonsense.txt',
128 | __DIR__ . '/fixtures/config_file.php'
129 | );
130 |
131 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
132 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
133 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
134 | $this->assertTrue($config->hasKey('random_string'));
135 | }
136 |
137 | /**
138 | * Test creation from best guess using an array.
139 | *
140 | * @covers \BrightNucleus\Config\ConfigFactory::create
141 | *
142 | * @since 0.3.0
143 | */
144 | public function testCreateFromBestGuessUsingAnArray()
145 | {
146 | $config = ConfigFactory::create(['some_key' => 'some_value']);
147 |
148 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
149 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
150 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
151 | $this->assertTrue($config->hasKey('some_key'));
152 | $this->assertEquals('some_value', $config->getKey('some_key'));
153 | }
154 |
155 | /**
156 | * Test whether the caching system works when loading the same config file several times.
157 | *
158 | * @covers \BrightNucleus\Config\ConfigFactory::create
159 | *
160 | * @since 0.4.3
161 | */
162 | public function testWhetherCachingWorks()
163 | {
164 | $content = ' "test_value" ];';
165 | $empty_content = 'withContent($content);
169 | $filesystem->addChild($configFile);
170 | $this->assertTrue($filesystem->hasChild('test_config.php'));
171 | $this->assertEquals($content, $configFile->getContent());
172 |
173 | $configA = ConfigFactory::create($configFile->url());
174 | $this->assertTrue($configA->hasKey('test_key'));
175 |
176 | $configFile->setContent($empty_content);
177 | $this->assertEquals($empty_content, $configFile->getContent());
178 |
179 | $configB = ConfigFactory::create($configFile->url());
180 | $this->assertTrue($configB->hasKey('test_key'));
181 | }
182 |
183 | /**
184 | * Test whether a subconfig can be immediately created through the ConfigFactory.
185 | *
186 | * @covers \BrightNucleus\Config\ConfigFactory::createSubConfig
187 | *
188 | * @since 0.4.5
189 | */
190 | public function testCreateSubConfig()
191 | {
192 | $config = ConfigFactory::createSubConfig(__DIR__ . '/fixtures/deep_config_file.php', 'vendor', 'package');
193 |
194 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
195 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
196 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
197 | $this->assertTrue($config->hasKey('section_1', 'test_key_1'));
198 | }
199 |
200 | /**
201 | * Test merging using several files.
202 | *
203 | * @covers \BrightNucleus\Config\ConfigFactory::merge
204 | *
205 | * @since 0.3.0
206 | */
207 | public function testMergeUsingSeveralFiles()
208 | {
209 | $config = ConfigFactory::merge(
210 | __DIR__ . '/fixtures/config_file.php',
211 | __DIR__ . '/fixtures/override_config_file.php'
212 | );
213 |
214 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
215 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
216 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
217 | $this->assertTrue($config->hasKey('random_string'));
218 | $this->assertEquals('override_value', $config->getKey('random_string'));
219 | }
220 |
221 | /**
222 | * Test merging using several files.
223 | *
224 | * @covers \BrightNucleus\Config\ConfigFactory::merge
225 | *
226 | * @since 0.3.0
227 | */
228 | public function testMergeUsingHierarchicalData()
229 | {
230 | $config = ConfigFactory::merge(
231 | __DIR__ . '/fixtures/deep_config_file.php',
232 | __DIR__ . '/fixtures/override_deep_config_file.php'
233 | )->getSubConfig('vendor\package');
234 |
235 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
236 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
237 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
238 | $this->assertTrue($config->hasKey('section_1', 'test_key_1'));
239 | $this->assertTrue($config->hasKey('section_2', 'test_key_2'));
240 | $this->assertTrue($config->hasKey('section_1', 'test_key_3'));
241 | $this->assertTrue($config->hasKey('section_3', 'test_key_4'));
242 | $this->assertEquals('test_value_1', $config->getKey('section_1', 'test_key_1'));
243 | $this->assertEquals('override_value_2', $config->getKey('section_2', 'test_key_2'));
244 | $this->assertEquals('override_value_3', $config->getKey('section_1', 'test_key_3'));
245 | $this->assertEquals('override_value_4', $config->getKey('section_3', 'test_key_4'));
246 | }
247 |
248 | /**
249 | * Test merging using invalid files.
250 | *
251 | * @covers \BrightNucleus\Config\ConfigFactory::merge
252 | *
253 | * @since 0.3.0
254 | */
255 | public function testMergeUsingInvalidFiles()
256 | {
257 | $config = ConfigFactory::merge(
258 | 'nonsense_file.php',
259 | 'still_nonsense.txt',
260 | __DIR__ . '/fixtures/config_file.php'
261 | );
262 |
263 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
264 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
265 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
266 | $this->assertTrue($config->hasKey('random_string'));
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bright Nucleus Config Component
2 |
3 | [](https://packagist.org/packages/brightnucleus/config)
4 | [](https://scrutinizer-ci.com/g/brightnucleus/config/?branch=main)
5 | [](https://coveralls.io/github/brightnucleus/config?branch=main)
6 | [](https://github.com/brightnucleus/config/actions/workflows/testing.yml)
7 | [](https://app.codacy.com/gh/brightnucleus/config/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
8 | [](https://codeclimate.com/github/brightnucleus/config)
9 |
10 | [](https://packagist.org/packages/brightnucleus/config)
11 | [](https://packagist.org/packages/brightnucleus/config)
12 | [](https://packagist.org/packages/brightnucleus/config)
13 | [](https://packagist.org/packages/brightnucleus/config)
14 |
15 | This is a very lean Config component to help you write reusable code. It only offers basic functionality and is meant to be used in libraries and small projects. If you need a Config component for more complex projects, you should take a look at the [Symfony Config Component](http://symfony.com/doc/current/components/config/index.html).
16 |
17 | ## Table Of Contents
18 |
19 | * [Installation](#installation)
20 | * [Basic Usage](#basic-usage)
21 | * [Working With Config Data](#working-with-config-data)
22 | * [Checking The Existence Of A Key](#checking-the-existence-of-a-key)
23 | * [Getting The Value Of A Key](#getting-the-value-of-a-key)
24 | * [Nested Keys](#nested-keys)
25 | * [Example - Configuration File](#example---configuration-file)
26 | * [Example - Configurable Class](#example---configurable-class)
27 | * [Example - Getting The Config Into The Class](#example---getting-the-config-into-the-class)
28 | * [Example - Class That Loads Default Config Unless Config Was Injected](#example---class-that-loads-default-config-unless-config-was-injected)
29 | * [Example - Merging Several Configs Into One](#example---merging-several-configs-into-one)
30 | * [Config Formats](#config-formats)
31 | * [Advanced Usage](#advanced-usage)
32 | * [Configuration Schema](#configuration-schema)
33 | * [Configuration Validation](#configuration-validation)
34 | * [Custom Implementations](#custom-implementations)
35 | * [Contributing](#contributing)
36 |
37 | ## Installation
38 |
39 | The best way to use this component is through Composer:
40 |
41 | ```BASH
42 | composer require brightnucleus/config
43 | ```
44 |
45 | ## Basic Usage
46 |
47 | A class that wants to be configurable should accept a `ConfigInterface` in its constructor, so that the Config can be injected. The surrounding code then should inject an instance of an object (for example the generic `Config` that is provided with this component). This way, the class that accepts the Config can be written in a 100% reusable way, while all project-specific stuff will be injected through the Config.
48 |
49 | ### Working With Config Data
50 |
51 | #### Checking The Existence Of A Key
52 |
53 | To check whether the configuration has a certain key, you can use the `ConfigInterface::hasKey($key)` method, or, if you are using the `ConfigTrait` in your class, you can use the convenience method `$this->hasConfigKey($key)`.
54 |
55 | #### Getting The Value Of A Key
56 |
57 | To get the configuration value of a certain key, you can use the `ConfigInterface::getKey($key)` method, or, if you are using the `ConfigTrait` in your class, you can use the convenience method `$this->getConfigKey($key)`.
58 |
59 | If you use closures in your Config file, you can also use the convenience function `$this->getConfigCallable( $key, array $args )` provided by the `ConfigTrait`, which will immediately execute the closure by passing it the provided arguments, and return the resultant value instead.
60 |
61 | #### Nested Keys
62 |
63 | If your keys are nested, you can provide multiple levels of keys in one request. So, whenever you need to provide a key and want to use a nested one, you can either provide a comma-separated list of keys ( `$this->getConfigKey( 'level1', 'level2', 'level3' );` ) or a string that contains the list of keys separated by a delimiter ( `$this->getConfigKey( 'level1/level2/level3' );` ).
64 |
65 | You can freely mix-and-match these two approaches as you like.
66 |
67 | The default delimiters are: `/`, `\` and `.`. You can choose different delimiters by passing an array of delimiters as a fourth argument to the `Config`s constructor.
68 |
69 | ### Example - Configuration File
70 |
71 | The snippet below shows the basic structure of a config file.
72 |
73 | ```PHP
74 | 'test_value',
81 | ];
82 |
83 | return [
84 | 'BrightNucleus' => [
85 | 'Example' => $example,
86 | ],
87 | ];
88 | ```
89 |
90 | ### Example - Configurable Class
91 |
92 | Here is an example setup of how you could feed this configuration into a plugin.
93 |
94 | ```PHP
95 | processConfig( $config );
113 | }
114 |
115 | /**
116 | * Do something.
117 | */
118 | public function run() {
119 | $key = 'test_key';
120 |
121 | return sprintf(
122 | _( 'The value of the config key "$1%s" is "$2%s".'),
123 | $key,
124 | $this->getConfigKey( $key )
125 | );
126 | }
127 | }
128 | ```
129 |
130 | ### Example - Getting The Config Into The Class
131 |
132 | You can combine all of your configurations into 1 single file and only pass "Sub-Configurations" to the individual components using the `getSubConfig()` method. This way, you can avoid an additional file access and an additional validation pass for each component.
133 |
134 | To create a new instance of a `ConfigInterface`, you should use the `ConfigFactory`. The basic method `ConfigFactory::create()` can take either an array of values, or one or more file names (with absolute paths) as strings.
135 |
136 | If you provide a comma-separated list of file names, they are processed consecutively until the first one could be loaded successfully.
137 |
138 | There's a convenience function `ConfigFactory::createSubConfig()` to immediately fetch a sub-config from a loaded config file. This allows you to quickly bypass the vendor/package prefixes and only pass in the relevant data into the new object.
139 |
140 | Here's how you can pass the configuration file into the class:
141 |
142 | ```PHP
143 | run();
155 | }
156 | ```
157 |
158 | ### Example - Class That Loads Default Config Unless Config Was Injected
159 |
160 | The `ConfigTrait` provides some convenience functionality that lets you write classes that can receive an injected Config, but fall back to a default configuration file if non was injected.
161 |
162 | Here's you can code such a class:
163 |
164 | ```PHP
165 | processConfig( $config ?: $this->fetchDefaultConfig() );
188 | }
189 |
190 | /**
191 | * Get the default configuration file name.
192 | *
193 | * This is used to override the default location.
194 | *
195 | * @return string Path & filename to the default configuration file.
196 | */
197 | protected function getDefaultConfigFile() {
198 | return __DIR__ . '/../config/my_default_config.php';
199 | }
200 | }
201 | ```
202 |
203 | ### Example - Merging Several Configs Into One
204 |
205 | You can provide a comma-separated list of file names to the `ConfigFactory::merge()` method. They are loaded consecutively and merged into one coherent Config. For each duplicate Config key, the value in the later files will override the value in the earlier files.
206 |
207 | For our example, we'll define a new Config file called `override_settings.php`, that overrides a key that was already set in the default Config file.
208 |
209 | ```PHP
210 | 'override_value',
217 | ];
218 |
219 | return [
220 | 'BrightNucleus' => [
221 | 'Example' => $example,
222 | ],
223 | ];
224 | ```
225 |
226 | ```PHP
227 | run();
241 | }
242 | ```
243 |
244 | ## Config Formats
245 |
246 | The Bright Nucleus Config component can be extended to load a multitude of different file formats. The base package includes a very minimal `PHPLoader` class. It can load basic PHP files that just `return` an array.
247 |
248 | Additional packages that add other formats like JSON or YAML are planned and will be released soon.
249 |
250 | Custom loaders are lazily instantiated only when needed.
251 |
252 | ## Advanced Usage
253 |
254 | ### Configuration Schema
255 |
256 | > TODO
257 |
258 | ### Configuration Validation
259 |
260 | > TODO
261 |
262 | ### Custom Implementations
263 |
264 | > TODO
265 |
266 | ## Contributing
267 |
268 | All feedback / bug reports / pull requests are welcome.
269 |
270 | ## License
271 |
272 | This code is released under the MIT license.
273 |
274 | For the full copyright and license information, please view the [`LICENSE`](LICENSE) file distributed with this source code.
275 |
--------------------------------------------------------------------------------
/tests/ConfigTraitTest.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Tests;
13 |
14 | use BrightNucleus\Config\Config;
15 | use BrightNucleus\Config\ConfigTrait;
16 |
17 | class ConfigTraitTest extends TestCase
18 | {
19 |
20 | use ConfigTrait;
21 |
22 | /**
23 | * @covers \BrightNucleus\Config\ConfigTrait::processConfig
24 | */
25 | public function testProcessConfig()
26 | {
27 | $this->assertNull($this->config);
28 | $this->processConfig(new Config([]));
29 | $this->assertNotNull($this->config);
30 | $this->assertInstanceOf(
31 | 'BrightNucleus\Config\ConfigInterface',
32 | $this->config
33 | );
34 | unset($this->config);
35 | }
36 |
37 | /**
38 | * @covers \BrightNucleus\Config\ConfigTrait::hasConfigKey
39 | */
40 | public function testHasConfigKey()
41 | {
42 | $this->processConfig(
43 | new Config(
44 | [
45 | 'testkey1' => 'testvalue1',
46 | 'testkey2' => 'testvalue2',
47 | ]
48 | )
49 | );
50 | $this->assertTrue($this->hasConfigKey('testkey1'));
51 | $this->assertTrue($this->hasConfigKey('testkey2'));
52 | $this->assertFalse($this->hasConfigKey('testkey3'));
53 | }
54 |
55 | /**
56 | * @covers \BrightNucleus\Config\ConfigTrait::hasConfigKey
57 | */
58 | public function testHasConfigKeyWithMultipleLevels()
59 | {
60 | $this->processConfig(
61 | new Config(
62 | [
63 | 'level1' => ['level2' => ['level3' => ['level4_key' => 'level4_value'],],],
64 | ]
65 | )
66 | );
67 | $this->assertTrue($this->hasConfigKey('level1'));
68 | $this->assertTrue($this->hasConfigKey('level1', 'level2'));
69 | $this->assertTrue($this->hasConfigKey('level1', 'level2', 'level3'));
70 | $this->assertTrue($this->hasConfigKey('level1', 'level2', 'level3', 'level4_key'));
71 | $this->assertTrue($this->hasConfigKey('level1\level2', 'level3', 'level4_key'));
72 | $this->assertTrue($this->hasConfigKey('level1', 'level2/level3', 'level4_key'));
73 | $this->assertTrue($this->hasConfigKey('level1', 'level2', 'level3.level4_key'));
74 | $this->assertTrue($this->hasConfigKey('level1\level2\level3\level4_key'));
75 | $this->assertTrue($this->hasConfigKey('level1/level2/level3/level4_key'));
76 | $this->assertTrue($this->hasConfigKey('level1.level2.level3.level4_key'));
77 | $this->assertTrue($this->hasConfigKey('level1\level2/level3.level4_key'));
78 | $this->assertFalse($this->hasConfigKey('level1', 'level2', 'level4_key'));
79 | $this->assertFalse($this->hasConfigKey('level1', 'level3'));
80 | $this->assertFalse($this->hasConfigKey('level2'));
81 | $this->assertFalse($this->hasConfigKey('some_other_key'));
82 | }
83 |
84 | /**
85 | * @covers \BrightNucleus\Config\ConfigTrait::getConfigKey
86 | */
87 | public function testGetConfigKey()
88 | {
89 | $this->processConfig(
90 | new Config(
91 | [
92 | 'testkey1' => 'testvalue1',
93 | 'testkey2' => 'testvalue2',
94 | ]
95 | )
96 | );
97 | $this->assertEquals('testvalue1', $this->getConfigKey('testkey1'));
98 | $this->assertEquals('testvalue2', $this->getConfigKey('testkey2'));
99 | $this->expectException('OutOfRangeException');
100 | $this->getConfigKey('testkey3');
101 | }
102 |
103 | /**
104 | * @covers \BrightNucleus\Config\ConfigTrait::getConfigKey
105 | */
106 | public function testGetConfigKeyWithMultipleLevels()
107 | {
108 | $this->processConfig(
109 | new Config(
110 | [
111 | 'level1' => ['level2' => ['level3' => ['level4_key' => 'level4_value'],],],
112 | ]
113 | )
114 | );
115 | $this->assertEquals('level4_value', $this->getConfigKey('level1', 'level2', 'level3', 'level4_key'));
116 | $this->assertEquals('level4_value', $this->getConfigKey('level1\level2', 'level3', 'level4_key'));
117 | $this->assertEquals('level4_value', $this->getConfigKey('level1', 'level2/level3', 'level4_key'));
118 | $this->assertEquals('level4_value', $this->getConfigKey('level1', 'level2', 'level3.level4_key'));
119 | $this->assertEquals('level4_value', $this->getConfigKey('level1\level2\level3\level4_key'));
120 | $this->assertEquals('level4_value', $this->getConfigKey('level1/level2/level3/level4_key'));
121 | $this->assertEquals('level4_value', $this->getConfigKey('level1.level2.level3.level4_key'));
122 | $this->assertEquals('level4_value', $this->getConfigKey('level1\level2/level3.level4_key'));
123 | $this->expectException('BrightNucleus\Config\Exception\KeyNotFoundException');
124 | $this->expectExceptionMessage('The configuration key level1->level2->level4_key does not exist.');
125 | $this->getConfigKey('level1', 'level2', 'level4_key');
126 | }
127 |
128 | /**
129 | * @covers \BrightNucleus\Config\ConfigTrait::getConfigArray
130 | */
131 | public function testGetConfigArray()
132 | {
133 | $this->processConfig(
134 | new Config(
135 | [
136 | 'testkey1' => 'testvalue1',
137 | 'testkey2' => 'testvalue2',
138 | ]
139 | )
140 | );
141 | $this->assertEquals(
142 | ['testkey1' => 'testvalue1', 'testkey2' => 'testvalue2'],
143 | $this->getConfigArray()
144 | );
145 | }
146 |
147 | /**
148 | * @covers \BrightNucleus\Config\ConfigTrait::getConfigKeys
149 | */
150 | public function testGetConfigKeys()
151 | {
152 | $this->processConfig(
153 | new Config(
154 | [
155 | 'testkey1' => 'testvalue1',
156 | 'testkey2' => 'testvalue2',
157 | ]
158 | )
159 | );
160 | $this->assertEquals(['testkey1', 'testkey2'], $this->getConfigKeys());
161 | }
162 |
163 | /**
164 | * @covers \BrightNucleus\Config\ConfigTrait::processConfig
165 | */
166 | public function testProcessConfigAllowsPreKeying()
167 | {
168 | $this->processConfig(
169 | new Config(
170 | [
171 | 'vendor' => [
172 | 'package' => [
173 | 'testkey1' => 'testvalue1',
174 | 'testkey2' => 'testvalue2',
175 | ],
176 | ],
177 | ]
178 | ),
179 | 'vendor\package'
180 | );
181 | $this->assertEquals(
182 | ['testkey1' => 'testvalue1', 'testkey2' => 'testvalue2'],
183 | $this->getConfigArray()
184 | );
185 | }
186 |
187 | /**
188 | * @covers \BrightNucleus\Config\ConfigTrait::processConfig
189 | */
190 | public function testProcessConfigThrowsException()
191 | {
192 | $this->expectException('BrightNucleus\Config\Exception\FailedToProcessConfigException');
193 | $this->expectExceptionMessage('Could not process the config with the arguments');
194 | $this->processConfig(
195 | new Config(
196 | [
197 | 'testkey1' => 'testvalue1',
198 | 'testkey2' => 'testvalue2',
199 | ]
200 | ),
201 | 'vendor\package'
202 | );
203 | }
204 |
205 | /**
206 | * @covers \BrightNucleus\Config\ConfigTrait::fetchConfig
207 | */
208 | public function testFetchConfigWithExistingFile()
209 | {
210 | $config = $this->fetchConfig(__DIR__ . '/fixtures/config_file.php');
211 | $this->assertNotNull($config);
212 | $this->assertInstanceOf(
213 | 'BrightNucleus\Config\ConfigInterface',
214 | $config
215 | );
216 | $this->assertTrue($config->hasKey('random_string'));
217 | $this->assertTrue($config->hasKey('positive_integer'));
218 | $this->assertTrue($config->hasKey('negative_integer'));
219 | $this->assertTrue($config->hasKey('positive_boolean'));
220 | $this->assertTrue($config->hasKey('negative_boolean'));
221 | $this->assertFalse($config->hasKey('some_other_key'));
222 | }
223 |
224 | /**
225 | * @covers \BrightNucleus\Config\ConfigTrait::fetchConfig
226 | */
227 | public function testFetchConfigWithNonExistingFile()
228 | {
229 | $config = $this->fetchConfig(__DIR__ . '/fixtures/file_does_not_exist.php');
230 | $this->assertNotNull($config);
231 | $this->assertInstanceOf(
232 | 'BrightNucleus\Config\ConfigInterface',
233 | $config
234 | );
235 | $this->assertEquals([], $config->getArrayCopy());
236 | }
237 |
238 | /**
239 | * @covers \BrightNucleus\Config\ConfigTrait::fetchDefaultConfig
240 | */
241 | public function testFetchDefaultConfig()
242 | {
243 | $config = $this->fetchDefaultConfig();
244 | $this->assertNotNull($config);
245 | $this->assertInstanceOf(
246 | 'BrightNucleus\Config\ConfigInterface',
247 | $config
248 | );
249 | $this->assertTrue($config->hasKey('random_string'));
250 | $this->assertTrue($config->hasKey('positive_integer'));
251 | $this->assertTrue($config->hasKey('negative_integer'));
252 | $this->assertTrue($config->hasKey('positive_boolean'));
253 | $this->assertTrue($config->hasKey('negative_boolean'));
254 | $this->assertFalse($config->hasKey('some_other_key'));
255 | }
256 |
257 | // Used to provide a file name for fetchDefaultConfig().
258 | protected function getDefaultConfigFile()
259 | {
260 | return __DIR__ . '/fixtures/config_file.php';
261 | }
262 |
263 | /**
264 | * @covers \BrightNucleus\Config\ConfigTrait::getConfigCallable
265 | */
266 | public function testGetConfigCallable()
267 | {
268 | $this->processConfig(
269 | new Config(
270 | [
271 | 'testkey1' => function ($a, $b, $c) {
272 | return "{$c}-{$b}-{$a}";
273 | },
274 | 'testkey2' => 'testvalue2',
275 | 'nestedlevel0' => [
276 | 'nestedlevel1' => [
277 | 'nestedlevel2' => [
278 | 'testkey3' => function ($a, $b, $c) {
279 | return "{$c}.{$b}.{$a}";
280 | },
281 | ],
282 | ],
283 | ],
284 | 'testkey4' => function ($a = null, $b = null, $c = null) {
285 | return "{$c}-{$b}-{$a}";
286 | },
287 | ]
288 | )
289 | );
290 |
291 | $this->assertEquals('3-2-1', $this->getConfigCallable('testkey1', [1, 2, 3]));
292 | $this->assertEquals('testvalue2', $this->getConfigCallable('testkey2', [1, 2, 3]));
293 | $this->assertEquals(
294 | '3.2.1',
295 | $this->getConfigCallable(
296 | 'nestedlevel0/nestedlevel1\nestedlevel2.testkey3',
297 | [1, 2, 3]
298 | )
299 | );
300 | $this->assertEquals(
301 | '3.2.1',
302 | $this->getConfigCallable(
303 | ['nestedlevel0', 'nestedlevel1', 'nestedlevel2\testkey3'],
304 | [1, 2, 3]
305 | )
306 | );
307 | $this->assertEquals('--', $this->getConfigCallable('testkey4', []));
308 | $this->assertEquals('--', $this->getConfigCallable('testkey4'));
309 | }
310 | }
311 |
--------------------------------------------------------------------------------
/tests/ConfigTest.php:
--------------------------------------------------------------------------------
1 |
7 | * @license MIT
8 | * @link http://www.brightnucleus.com/
9 | * @copyright 2016 Alain Schlesser, Bright Nucleus
10 | */
11 |
12 | namespace BrightNucleus\Config\Tests;
13 |
14 | use BrightNucleus\Config\Config;
15 | use BrightNucleus\Config\ConfigSchema;
16 |
17 | /**
18 | * Class ConfigTest
19 | *
20 | * @since 0.1.0
21 | *
22 | * @package BrightNucleus\Config
23 | * @author Alain Schlesser
24 | */
25 | class ConfigTest extends TestCase
26 | {
27 |
28 | /*
29 | * TODO: There's still lots of work to do to render these tests useful.
30 | */
31 |
32 | /*
33 | * Don't use an array const to avoid bumping PHP requirement to 5.6.
34 | */
35 | protected static $test_array = [
36 | 'random_string' => 'test_value',
37 | 'positive_integer' => 42,
38 | 'negative_integer' => -256,
39 | 'positive_boolean' => true,
40 | 'negative_boolean' => false,
41 | ];
42 |
43 | protected static $test_multi_array = [
44 | 'level1' => [
45 | 'level2' => [
46 | 'level3' => [
47 | 'level4_key' => 'level4_value',
48 | ],
49 | ],
50 | ],
51 | ];
52 |
53 | /**
54 | * Test creation and value retrieval.
55 | *
56 | * @covers \BrightNucleus\Config\AbstractConfig::__construct
57 | * @covers \BrightNucleus\Config\Config::__construct
58 | *
59 | * @since 1.0.0
60 | */
61 | public function testConfigFileCreation()
62 | {
63 | $config = new Config(ConfigTest::$test_array);
64 |
65 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
66 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
67 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
68 | }
69 |
70 | /**
71 | * Test the different error conditions that can throw exceptions in
72 | * __construct().
73 | *
74 | * @covers BrightNucleus\Config\AbstractConfig::__construct
75 | * @covers BrightNucleus\Config\Config::__construct
76 | *
77 | * @dataProvider configExceptionsDataProvider
78 | *
79 | * @since 1.0.0
80 | *
81 | * @param string $exception Exception class to expect.
82 | * @param string $message Exception message to expect.
83 | * @param mixed $config Configuration source.
84 | * @param mixed $defaults Default values.
85 | * @param mixed $validator Validator object.
86 | */
87 | public function testConfigExceptions(
88 | $exception,
89 | $message,
90 | $config,
91 | $defaults = null,
92 | $validator = null
93 | ) {
94 | $this->expectException($exception);
95 | $this->expectExceptionMessage($message);
96 | new Config($config, $defaults, $validator);
97 | }
98 |
99 | /**
100 | * Provide testable data to the testFeatureSupport() method.
101 | *
102 | * @since 0.1.0
103 | *
104 | * @return array
105 | */
106 | public function configExceptionsDataProvider()
107 | {
108 | return [
109 | // $exception, $message, $config, $defaults, $validator
110 | [
111 | 'BrightNucleus\Config\Exception\InvalidConfigurationSourceException',
112 | 'Invalid configuration source',
113 | null,
114 | ],
115 | [
116 | 'BrightNucleus\Config\Exception\FailedToLoadConfigException',
117 | 'Could not load resource located at "/folder/missing_file.php". Reason: '
118 | . '"The requested PHP config file "/folder/missing_file.php" does not exist or is not readable.".',
119 | '/folder/missing_file.php',
120 | ],
121 | [
122 | 'BrightNucleus\Config\Exception\FailedToLoadConfigException',
123 | 'Could not find a suitable loader for URI',
124 | __DIR__ . '/fixtures/dummy_file.txt',
125 | ],
126 | ];
127 | }
128 |
129 | /**
130 | * @covers \BrightNucleus\Config\Config::__construct
131 | * @covers \BrightNucleus\Config\Config::isValid
132 | */
133 | public function testValidation()
134 | {
135 | $unvalidated_config = new Config(ConfigTest::$test_array, null, null);
136 | $this->assertTrue($unvalidated_config->isValid());
137 |
138 | $true_validator = $this->getMockBuilder('\BrightNucleus\Config\ConfigValidatorInterface')
139 | ->getMock();
140 | $true_validator->method('isValid')
141 | ->willReturn(true);
142 | $valid_config = new Config(ConfigTest::$test_array, null, $true_validator);
143 | $this->assertTrue($valid_config->isValid());
144 |
145 | $false_validator = $this->getMockBuilder('\BrightNucleus\Config\ConfigValidatorInterface')
146 | ->getMock();
147 | $false_validator->method('isValid')
148 | ->willReturn(false);
149 | $this->expectException('BrightNucleus\Config\Exception\InvalidConfigException');
150 | $this->expectExceptionMessage('ConfigInterface file is not valid');
151 | new Config(ConfigTest::$test_array, null, $false_validator);
152 | }
153 |
154 | /**
155 | * @covers \BrightNucleus\Config\AbstractConfig::hasKey
156 | */
157 | public function testHasKey()
158 | {
159 | $config = new Config(ConfigTest::$test_array);
160 | $this->assertTrue($config->hasKey('random_string'));
161 | $this->assertTrue($config->hasKey('positive_integer'));
162 | $this->assertTrue($config->hasKey('negative_integer'));
163 | $this->assertTrue($config->hasKey('positive_boolean'));
164 | $this->assertTrue($config->hasKey('negative_boolean'));
165 | $this->assertFalse($config->hasKey('some_other_key'));
166 | }
167 |
168 | /**
169 | * @covers \BrightNucleus\Config\AbstractConfig::__construct
170 | * @covers \BrightNucleus\Config\AbstractConfig::hasKey
171 | */
172 | public function testHasKeyWithMultipleLevels()
173 | {
174 | $config = new Config(ConfigTest::$test_multi_array);
175 | $this->assertTrue($config->hasKey('level1'));
176 | $this->assertTrue($config->hasKey('level1', 'level2'));
177 | $this->assertTrue($config->hasKey('level1', 'level2', 'level3'));
178 | $this->assertTrue($config->hasKey('level1', 'level2', 'level3', 'level4_key'));
179 | $this->assertTrue($config->hasKey(['level1', 'level2', 'level3', 'level4_key']));
180 | $this->assertTrue($config->hasKey('level1\level2', 'level3', 'level4_key'));
181 | $this->assertTrue($config->hasKey('level1\level2', ['level3', 'level4_key']));
182 | $this->assertTrue($config->hasKey('level1', 'level2/level3', 'level4_key'));
183 | $this->assertTrue($config->hasKey('level1', 'level2', 'level3.level4_key'));
184 | $this->assertTrue($config->hasKey('level1\level2\level3\level4_key'));
185 | $this->assertTrue($config->hasKey('level1/level2/level3/level4_key'));
186 | $this->assertTrue($config->hasKey('level1.level2.level3.level4_key'));
187 | $this->assertTrue($config->hasKey('level1\level2/level3.level4_key'));
188 | $this->assertTrue($config->hasKey(['level1\level2'], ['level3.level4_key']));
189 | $this->assertTrue($config->hasKey(['level1\level2/level3.level4_key']));
190 | $this->assertFalse($config->hasKey('level2'));
191 | $this->assertFalse($config->hasKey('level1', 'level3'));
192 | $this->assertFalse($config->hasKey('level1', 'level2', 'level4_key'));
193 | $this->assertFalse($config->hasKey('level0', 'level1', 'level2', 'level3', 'level4_key'));
194 | $this->assertFalse($config->hasKey('level1.level3'));
195 | $this->assertFalse($config->hasKey('level1.level2.level4_key'));
196 | $this->assertFalse($config->hasKey('level0.level1.level2.level3.level4_key'));
197 |
198 | $config = new Config(ConfigTest::$test_multi_array, null, null, ['@', ':', ';']);
199 | $this->assertTrue($config->hasKey('level1'));
200 | $this->assertTrue($config->hasKey('level1', 'level2'));
201 | $this->assertTrue($config->hasKey('level1', 'level2', 'level3'));
202 | $this->assertTrue($config->hasKey('level1', 'level2', 'level3', 'level4_key'));
203 | $this->assertTrue($config->hasKey('level1@level2', 'level3', 'level4_key'));
204 | $this->assertTrue($config->hasKey('level1', 'level2:level3', 'level4_key'));
205 | $this->assertTrue($config->hasKey('level1', 'level2', 'level3;level4_key'));
206 | $this->assertTrue($config->hasKey('level1@level2@level3@level4_key'));
207 | $this->assertTrue($config->hasKey('level1:level2:level3:level4_key'));
208 | $this->assertTrue($config->hasKey('level1;level2;level3;level4_key'));
209 | $this->assertTrue($config->hasKey('level1@level2:level3;level4_key'));
210 | }
211 |
212 | /**
213 | * @covers \BrightNucleus\Config\AbstractConfig::getKeys
214 | */
215 | public function testGetKeys()
216 | {
217 | $config = new Config(ConfigTest::$test_array);
218 | $this->assertEquals(array_keys(ConfigTest::$test_array), $config->getKeys());
219 | }
220 |
221 | /**
222 | * @covers \BrightNucleus\Config\AbstractConfig::getKey
223 | * @covers \BrightNucleus\Config\AbstractConfig::getKeyArguments
224 | */
225 | public function testGetKey()
226 | {
227 | $config = new Config(ConfigTest::$test_array);
228 | $this->assertEquals('test_value', $config->getKey('random_string'));
229 | $this->assertEquals(42, $config->getKey('positive_integer'));
230 | $this->assertEquals(-256, $config->getKey('negative_integer'));
231 | $this->assertTrue($config->getKey('positive_boolean'));
232 | $this->assertFalse($config->getKey('negative_boolean'));
233 | }
234 |
235 | /**
236 | * @covers \BrightNucleus\Config\AbstractConfig::getKeyArguments
237 | */
238 | public function testGetKeyThrowsExceptionOnWrongKey()
239 | {
240 | $config = new Config(ConfigTest::$test_array);
241 | $this->expectException('BrightNucleus\Config\Exception\KeyNotFoundException');
242 | $this->expectExceptionMessage('The configuration key some_other_key does not exist.');
243 | $config->getKey('some_other_key');
244 | }
245 |
246 | /**
247 | * @covers \BrightNucleus\Config\AbstractConfig::getKey
248 | * @covers \BrightNucleus\Config\AbstractConfig::getKeyArguments
249 | * @covers \BrightNucleus\Config\AbstractConfig::parseKeysString
250 | */
251 | public function testGetKeyWithMultipleLevels()
252 | {
253 | $config = new Config(ConfigTest::$test_multi_array);
254 | $this->assertEquals(['level2' => ['level3' => ['level4_key' => 'level4_value']]], $config->getKey('level1'));
255 | $this->assertEquals(['level3' => ['level4_key' => 'level4_value']], $config->getKey('level1', 'level2'));
256 | $this->assertEquals(['level4_key' => 'level4_value'], $config->getKey('level1', 'level2', 'level3'));
257 | $this->assertEquals('level4_value', $config->getKey('level1', 'level2', 'level3', 'level4_key'));
258 | $this->assertEquals('level4_value', $config->getKey('level1\level2', 'level3', 'level4_key'));
259 | $this->assertEquals('level4_value', $config->getKey('level1', 'level2/level3', 'level4_key'));
260 | $this->assertEquals('level4_value', $config->getKey('level1', 'level2', 'level3.level4_key'));
261 | $this->assertEquals('level4_value', $config->getKey('level1\level2\level3\level4_key'));
262 | $this->assertEquals('level4_value', $config->getKey('level1/level2/level3/level4_key'));
263 | $this->assertEquals('level4_value', $config->getKey('level1.level2.level3.level4_key'));
264 | $this->assertEquals('level4_value', $config->getKey('level1\level2/level3.level4_key'));
265 | $this->expectException('BrightNucleus\Config\Exception\KeyNotFoundException');
266 | $this->expectExceptionMessage('The configuration key level1->level2->level4_key does not exist.');
267 | $config->getKey('level1', 'level2', 'level4_key');
268 | }
269 |
270 | /**
271 | * @covers \BrightNucleus\Config\AbstractConfig::getAll
272 | */
273 | public function testGetAll()
274 | {
275 | $config = new Config(ConfigTest::$test_array);
276 | $this->assertEquals(ConfigTest::$test_array, $config->getAll());
277 | }
278 |
279 | /**
280 | * @covers \BrightNucleus\Config\Config::__construct
281 | * @covers \BrightNucleus\Config\Config::resolveOptions
282 | * @covers \BrightNucleus\Config\Config::configureOptions
283 | */
284 | public function testConfigFileWithoutDefaults()
285 | {
286 | $config = new Config(__DIR__ . '/fixtures/config_file.php');
287 | $this->assertTrue($config->hasKey('random_string'));
288 | $this->assertTrue($config->hasKey('positive_integer'));
289 | $this->assertTrue($config->hasKey('negative_integer'));
290 | $this->assertTrue($config->hasKey('positive_boolean'));
291 | $this->assertTrue($config->hasKey('negative_boolean'));
292 | $this->assertFalse($config->hasKey('some_other_key'));
293 | $this->assertEquals('test_value', $config->getKey('random_string'));
294 | $this->assertEquals(42, $config->getKey('positive_integer'));
295 | $this->assertEquals(-256, $config->getKey('negative_integer'));
296 | $this->assertTrue($config->getKey('positive_boolean'));
297 | $this->assertFalse($config->getKey('negative_boolean'));
298 | $this->expectException('BrightNucleus\Config\Exception\KeyNotFoundException');
299 | $this->expectExceptionMessage('The configuration key some_other_key does not exist.');
300 | $this->assertFalse($config->getKey('some_other_key'));
301 | }
302 |
303 | /**
304 | * @covers \BrightNucleus\Config\Config::__construct
305 | * @covers \BrightNucleus\Config\Config::resolveOptions
306 | * @covers \BrightNucleus\Config\Config::configureOptions
307 | */
308 | public function testConfigFileWithMissingKeys()
309 | {
310 | $schema = new ConfigSchema(new Config(__DIR__ . '/fixtures/schema_config_file.php'));
311 | $this->expectException('BrightNucleus\Config\Exception\FailedToResolveConfigException');
312 | $this->expectExceptionMessage(
313 | 'Error while resolving config options: The required option "negative_integer" is missing.'
314 | );
315 | new Config([], $schema);
316 | }
317 |
318 | /**
319 | * @covers \BrightNucleus\Config\Config::__construct
320 | * @covers \BrightNucleus\Config\Config::resolveOptions
321 | * @covers \BrightNucleus\Config\Config::configureOptions
322 | */
323 | public function testConfigFileWithDefaults()
324 | {
325 | $schema = new ConfigSchema(new Config(__DIR__ . '/fixtures/schema_config_file.php'));
326 | $config = new Config(['negative_integer' => -333], $schema);
327 | $this->assertTrue($config->hasKey('random_string'));
328 | $this->assertTrue($config->hasKey('positive_integer'));
329 | $this->assertTrue($config->hasKey('negative_integer'));
330 | $this->assertTrue($config->hasKey('positive_boolean'));
331 | $this->assertFalse($config->hasKey('negative_boolean'));
332 | $this->assertFalse($config->hasKey('some_other_key'));
333 | $this->assertEquals('default_test_value', $config->getKey('random_string'));
334 | $this->assertEquals(99, $config->getKey('positive_integer'));
335 | $this->assertEquals(-333, $config->getKey('negative_integer'));
336 | $this->assertTrue($config->getKey('positive_boolean'));
337 | $this->expectException('BrightNucleus\Config\Exception\KeyNotFoundException');
338 | $this->expectExceptionMessage('The configuration key some_other_key does not exist.');
339 | $this->assertFalse($config->getKey('some_other_key'));
340 | }
341 |
342 | /**
343 | * @covers \BrightNucleus\Config\AbstractConfig::getSubConfig
344 | */
345 | public function testGetSubConfig()
346 | {
347 | $config = new Config(__DIR__ . '/fixtures/deep_config_file.php');
348 | $subconfig = $config->getSubConfig('vendor/package');
349 | $subsection1 = $config->getSubConfig('vendor', 'package', 'section_1');
350 | $subsection2 = $subconfig->getSubConfig('section_2');
351 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $config);
352 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $config);
353 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $config);
354 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $subconfig);
355 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $subconfig);
356 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $subconfig);
357 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $subsection1);
358 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $subsection1);
359 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $subsection1);
360 | $this->assertInstanceOf('\BrightNucleus\Config\ConfigInterface', $subsection2);
361 | $this->assertInstanceOf('\BrightNucleus\Config\AbstractConfig', $subsection2);
362 | $this->assertInstanceOf('\BrightNucleus\Config\Config', $subsection2);
363 | $this->assertTrue($config->hasKey('vendor/package'));
364 | $this->assertTrue($config->hasKey('vendor/package/section_1/test_key_1'));
365 | $this->assertTrue($config->hasKey('vendor/package/section_2/test_key_2'));
366 | $this->assertTrue($subconfig->hasKey('section_1/test_key_1'));
367 | $this->assertTrue($subconfig->hasKey('section_2/test_key_2'));
368 | $this->assertTrue($subsection1->hasKey('test_key_1'));
369 | $this->assertTrue($subsection2->hasKey('test_key_2'));
370 | $this->expectException('BrightNucleus\Config\Exception\KeyNotFoundException');
371 | $this->expectExceptionMessage('The configuration key some_other_key does not exist.');
372 | $this->assertFalse($config->getSubConfig('some_other_key'));
373 | }
374 | }
375 |
--------------------------------------------------------------------------------