From 642aba8bb3c85e154c2001b41c7d73188bb14e62 Mon Sep 17 00:00:00 2001 From: Tom Oram Date: Wed, 23 Sep 2015 22:38:27 +0100 Subject: [PATCH] Add sub-providers --- CHANGELOG.md | 8 + README.md | 38 ++--- phpunit.xml | 4 +- src/Config.php | 24 --- src/ConfigServiceProvider.php | 100 +++++++++++- src/ConfigurableServiceProvider.php | 13 ++ src/InflectorConfigServiceProvider.php | 11 +- tests/ConfigServiceProviderTest.php | 152 ++++++++++++++++++ tests/ConfigTest.php | 42 ----- tests/InflectorConfigServiceProviderTest.php | 28 ++++ .../BootableConfigurableServiceProvider.php | 12 ++ 11 files changed, 333 insertions(+), 99 deletions(-) delete mode 100644 src/Config.php create mode 100644 src/ConfigurableServiceProvider.php delete mode 100644 tests/ConfigTest.php create mode 100644 tests/mocks/BootableConfigurableServiceProvider.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d6ce44d..6e27514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### 0.3.0 (2015-09-23) + + * Added: `ConfigServiceProvider::fromConfig()` factory method + * Added: Sub providers + * Updated: `TomPHP\ConfigServiceProvider\InflectorConfigServiceProvider` is + now a sub provider + * Removed: `TomPHP\ConfigServiceProvider\Config` static factory + ### 0.2.1 (2015-09-21) * Added: Support to set up inflectors via configuration diff --git a/README.md b/README.md index fc4754f..e951b15 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ $ composer require tomphp/config-service-provider use League\Container\Container; use League\Container\ServiceProvider\AbstractServiceProvider; -use TomPHP\ConfigServiceProvider\Config; +use TomPHP\ConfigServiceProvider\ConfigServiceProvider; class DatabaseConnectionProvider extends AbstractServiceProvider { @@ -55,7 +55,7 @@ $appConfig = [ $container = new Container(); -Config::addToContainer($container, $appConfig); +$container->addServiceProvider(ConfigServiceProvider::fromConfig($appConfig)); $container->addServiceProvider(new DatabaseConnectionProvider()); $db = $container->get('database_connection'); @@ -113,31 +113,23 @@ $appConfig = [ ]; ``` -## Advanced Usage +### Extra Settings -`Config::addToContainer` makes some assumptions about how your config is -arranged. If you need to customise this then you can create the service -providers directly. +You can provide an array of extra settings as a second parameter to +`TomPHP\ConfigServiceProvider\ConfigServiceProvider::fromConfig()`. -### The Config Service Provider +Current valid keys are: -You can change the config root name and the separator by creating an instance -of `TomPHP\ConfigServiceProvider\ConfigServiceProvider` directly. +| Name | Effect | +|-------------|-----------------------------------------------| +| `prefix` | Changes `config` prefix given to config keys. | +| `separator` | Changes `.` separator in config keys. | -```php -ConfigServiceProvider::__construct(array $config, $prefix = 'config', $separator = '.') -``` - -### Inflector Config Service Provider - -The configuring of inflectors is done using a separate service provider: +Example: ```php -$inflectorConfig = [ - LoggerAwareInterface::class => [ - 'setLogger' => ['Some\Logger'] - ] -]; - -$container->addServiceProvider(new InflectorConfigServiceProvider($inflectorConfig)); +$provider = ConfigServiceProvider::fromConfig($appConfig, [ + 'prefix' => 'settings', + 'separator' => '/' +]); ``` diff --git a/phpunit.xml b/phpunit.xml index e822508..2a2fde7 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,7 +1,7 @@ - - tests/ + + tests diff --git a/src/Config.php b/src/Config.php deleted file mode 100644 index 4308b77..0000000 --- a/src/Config.php +++ /dev/null @@ -1,24 +0,0 @@ -addServiceProvider(new ConfigServiceProvider($config)); - - if (array_key_exists(self::INFLECTORS_CONFIG_KEY, $config)) { - $container->addServiceProvider( - new InflectorConfigServiceProvider($config[self::INFLECTORS_CONFIG_KEY]) - ); - } - } -} diff --git a/src/ConfigServiceProvider.php b/src/ConfigServiceProvider.php index 295fbc0..9e0d7ce 100644 --- a/src/ConfigServiceProvider.php +++ b/src/ConfigServiceProvider.php @@ -3,9 +3,19 @@ namespace TomPHP\ConfigServiceProvider; use League\Container\ServiceProvider\AbstractServiceProvider; +use League\Container\ServiceProvider\BootableServiceProviderInterface; +use TomPHP\ConfigServiceProvider\InflectorConfigServiceProvider; -class ConfigServiceProvider extends AbstractServiceProvider +class ConfigServiceProvider extends AbstractServiceProvider implements + BootableServiceProviderInterface { + const DEFAULT_PREFIX = 'config'; + const DEFAULT_SEPARATOR = '.'; + const DEFAULT_INFLECTORS_KEY = 'inflectors'; + + const SETTING_PREFIX = 'prefix'; + const SETTING_SEPARATOR = 'separator'; + /** * @var array */ @@ -21,23 +31,56 @@ class ConfigServiceProvider extends AbstractServiceProvider */ private $separator; + /** + * @var ConfigurableServiceProvider[] + */ + private $subProviders; + /** * @api * - * @param array $config - * @param string $prefix - * @param string $separator + * @param array $config + * @param array $settings + * + * @return ConfigServiceProvider */ - public function __construct(array $config, $prefix = 'config', $separator = '.') + public static function fromConfig(array $config, array $settings = []) { - $this->prefix = $prefix; - $this->separator = $separator; + return new self( + $config, + self::getSettingOrDefault(self::SETTING_PREFIX, $settings, self::DEFAULT_PREFIX), + self::getSettingOrDefault(self::SETTING_SEPARATOR, $settings, self::DEFAULT_SEPARATOR), + [self::DEFAULT_INFLECTORS_KEY => new InflectorConfigServiceProvider([])] + ); + } + + /** + * @api + * + * @param array $config + * @param string $prefix + * @param string $separator + * @param ConfigurableServiceProvider[] $subProviders + */ + public function __construct( + array $config, + $prefix = self::DEFAULT_PREFIX, + $separator = self::DEFAULT_SEPARATOR, + array $subProviders = [] + ) { + $this->prefix = $prefix; + $this->separator = $separator; + $this->subProviders = $subProviders; $config = $this->expandSubGroups($config); $this->provides = $this->getKeys($config); $this->config = array_combine($this->provides, array_values($config)); + + foreach ($this->subProviders as $key => $provider) { + $this->configureSubProvider($key, $config, $provider); + } } public function register() @@ -45,6 +88,23 @@ public function register() foreach ($this->config as $key => $value) { $this->getContainer()->add($key, $value); } + + foreach ($this->subProviders as $provider) { + $provider->setContainer($this->getContainer()); + $provider->register(); + } + } + + public function boot() + { + foreach ($this->subProviders as $provider) { + if (!$provider instanceof BootableServiceProviderInterface) { + continue; + } + + $provider->setContainer($this->getContainer()); + $provider->boot(); + } } /** @@ -113,4 +173,30 @@ function ($key) { $keys ); } + + /** + * @param string $key + */ + private function configureSubProvider($key, $config, ConfigurableServiceProvider $provider) + { + if (!array_key_exists($key, $config)) { + return; + } + + $provider->configure($config[$key]); + + $this->provides = array_merge($this->provides, $provider->provides()); + } + + /** + * @param string $name + * @param array $settings + * @param mixed $default + * + * @return mixed + */ + private static function getSettingOrDefault($name, array $settings, $default) + { + return isset($settings[$name]) ? $settings[$name] : $default; + } } diff --git a/src/ConfigurableServiceProvider.php b/src/ConfigurableServiceProvider.php new file mode 100644 index 0000000..0f9abc0 --- /dev/null +++ b/src/ConfigurableServiceProvider.php @@ -0,0 +1,13 @@ +config = $config; } + /** + * @param array $config + */ + public function configure(array $config) + { + $this->config = $config; + } + public function register() { } diff --git a/tests/ConfigServiceProviderTest.php b/tests/ConfigServiceProviderTest.php index f21f01d..8ba4331 100644 --- a/tests/ConfigServiceProviderTest.php +++ b/tests/ConfigServiceProviderTest.php @@ -5,6 +5,7 @@ use League\Container\Container; use PHPUnit_Framework_TestCase; use TomPHP\ConfigServiceProvider\ConfigServiceProvider; +use Prophecy\Argument; class ConfigServiceProviderTest extends PHPUnit_Framework_TestCase { @@ -16,6 +17,13 @@ class ConfigServiceProviderTest extends PHPUnit_Framework_TestCase protected function setUp() { $this->container = new Container(); + + $this->subProvider = $this->prophesize('TomPHP\ConfigServiceProvider\ConfigurableServiceProvider'); + + $this->subProvider->configure(Argument::any())->willReturn(); + $this->subProvider->provides()->willReturn([]); + $this->subProvider->setContainer(Argument::any())->willReturn(); + $this->subProvider->register()->willReturn(); } public function testItProvidesConfigValuesViaTheDI() @@ -111,4 +119,148 @@ public function testItCanUseACustomSeparator() $this->container->get('config/test_group/test_setting') ); } + + /** + * @group sub_providers + */ + public function testItConfiguresASubProvider() + { + $config = [ + 'sub_provider' => ['key' => 'config'], + ]; + + new ConfigServiceProvider($config, 'config', '.', [ + 'sub_provider' => $this->subProvider->reveal(), + ]); + + $this->subProvider->configure(['key' => 'config'])->shouldHaveBeenCalled(); + } + + /** + * @group sub_providers + */ + public function testItSkipsConfiguringASubProvderWithNoConfig() + { + new ConfigServiceProvider([], 'config', '.', [ + 'sub_provider' => $this->subProvider->reveal(), + ]); + + $this->subProvider->configure(Argument::any())->shouldNotHaveBeenCalled(); + } + + /** + * @group sub_providers + */ + public function testItMergesTheSubProvidersServiceList() + { + $this->subProvider->provides()->willReturn(['b']); + + $provider = new ConfigServiceProvider( + ['sub_provider' => [], 'a' => 1], + 'config', + '.', + [ 'sub_provider' => $this->subProvider->reveal() ] + ); + + $this->assertEquals(['config.sub_provider', 'config.a', 'b'], $provider->provides()); + } + + /** + * @group sub_providers + */ + public function testItRegistersSubProviders() + { + $this->container->addServiceProvider(new ConfigServiceProvider( + ['sub_provider' => []], + 'config', + '.', + [ 'sub_provider' => $this->subProvider->reveal() ] + )); + + $this->container->get('config.sub_provider'); + + $this->subProvider->setContainer($this->container)->shouldHaveBeenCalled(); + $this->subProvider->register()->shouldHaveBeenCalled(); + } + + /** + * @group sub_providers + */ + public function testBootableSubProvidersAreBooted() + { + $this->subProvider = $this->prophesize('tests\mocks\BootableConfigurableServiceProvider'); + + $this->subProvider->configure(Argument::any())->willReturn(); + $this->subProvider->provides()->willReturn([]); + $this->subProvider->setContainer(Argument::any())->willReturn(); + $this->subProvider->register()->willReturn(); + $this->subProvider->boot()->willReturn(); + + $this->container->addServiceProvider(new ConfigServiceProvider( + ['sub_provider' => []], + 'config', + '.', + [ 'sub_provider' => $this->subProvider->reveal() ] + )); + + $this->container->get('config.sub_provider'); + + $this->subProvider->setContainer($this->container)->shouldHaveBeenCalled(); + $this->subProvider->boot()->shouldHaveBeenCalled(); + } + + /** + * @group from_config_factory + */ + public function testItCreatesFromConfigWithDefaultSettings() + { + $config = [ + 'test_key' => 'test value', + + 'inflectors' => [ + 'tests\mocks\ExampleInterface' => [ + 'setValue' => ['config.test_key'] + ] + ] + ]; + + $this->container->addServiceProvider(ConfigServiceProvider::fromConfig($config)); + + $this->container->add('example', 'tests\mocks\ExampleClass'); + + $this->assertEquals( + 'test value', + $this->container->get('example')->getValue() + ); + } + + /** + * @group from_config_factory + */ + public function testItCanOverrideDefaultSettings() + { + $config = [ + 'test_key' => 'test value', + + 'inflectors' => [ + 'tests\mocks\ExampleInterface' => [ + 'setValue' => ['settings/test_key'] + ] + ] + ]; + + $this->container->addServiceProvider( + ConfigServiceProvider::fromConfig($config, [ + 'prefix' => 'settings', + 'separator' => '/' + ]) + ); + + $this->container->add('example', 'tests\mocks\ExampleClass'); + + $this->assertEquals( + 'test value', + $this->container->get('example')->getValue() + ); + } } diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php deleted file mode 100644 index 65daa8e..0000000 --- a/tests/ConfigTest.php +++ /dev/null @@ -1,42 +0,0 @@ -container = new Container(); - - $config = [ - 'test_key' => 'test value', - - 'inflectors' => [ - 'tests\mocks\ExampleInterface' => [ - 'setValue' => ['config.test_key'] - ] - ] - ]; - - Config::addToContainer($this->container, $config); - - $this->container->add('example', 'tests\mocks\ExampleClass'); - } - - public function testItCanAUseCustomPrefix() - { - $this->assertEquals( - 'test value', - $this->container->get('example')->getValue() - ); - } -} diff --git a/tests/InflectorConfigServiceProviderTest.php b/tests/InflectorConfigServiceProviderTest.php index 03ce650..0095c47 100644 --- a/tests/InflectorConfigServiceProviderTest.php +++ b/tests/InflectorConfigServiceProviderTest.php @@ -18,6 +18,14 @@ protected function setUp() $this->container = new Container(); } + public function testItIsAConfigurableServiceProvider() + { + $this->assertInstanceOf( + 'TomPHP\ConfigServiceProvider\ConfigurableServiceProvider', + new InflectorConfigServiceProvider([]) + ); + } + public function testSetsUpAnInflector() { $config = [ @@ -34,4 +42,24 @@ public function testSetsUpAnInflector() $this->container->get('example')->getValue() ); } + + public function testCanBeReconfigured() + { + $config = [ + 'tests\mocks\ExampleInterface' => [ + 'setValue' => ['test_value'] + ] + ]; + + $provider = new InflectorConfigServiceProvider([]); + $provider->configure($config); + + $this->container->addServiceProvider($provider); + $this->container->add('example', 'tests\mocks\ExampleClass'); + + $this->assertEquals( + 'test_value', + $this->container->get('example')->getValue() + ); + } } diff --git a/tests/mocks/BootableConfigurableServiceProvider.php b/tests/mocks/BootableConfigurableServiceProvider.php new file mode 100644 index 0000000..e21b60b --- /dev/null +++ b/tests/mocks/BootableConfigurableServiceProvider.php @@ -0,0 +1,12 @@ +