Skip to content

Commit

Permalink
Merge pull request #18 from tomphp/feature/di-config
Browse files Browse the repository at this point in the history
Add feature to configure DI via the config
  • Loading branch information
tomphp committed Oct 10, 2015
2 parents e4ddbf9 + 7c38197 commit ec30b21
Show file tree
Hide file tree
Showing 13 changed files with 382 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 0.3.3 (2015-10-10)

* Added: Configuring DI via the config

### 0.3.2 (2015-09-24)

* Added: Reading JSON config files via the `fromFiles` constructor
Expand Down
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,33 @@ class DatabaseConnectionProvider extends AbstractServiceProvider
}
```

### Configuring DI

Another feature is the ability to add services to your container via the config.
This is done by adding a `di` key to the config and using the following format:

```php
$appConfig = [
'di' => [
'logger' => [
'class' => Logger::class,
'singleton' => true,
'arguments' => [
StdoutLogger::class
],
'methods' => [
'setMinLogLevel' => [ 'info' ]
],
],

StdoutLogger::class => [
'class' => StdoutLogger::class
]
]
];

```

### Configuring Inflectors

It is also possible to set up
Expand Down
12 changes: 8 additions & 4 deletions src/ConfigServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ final class ConfigServiceProvider extends AbstractServiceProvider implements
const DEFAULT_PREFIX = 'config';
const DEFAULT_SEPARATOR = '.';
const DEFAULT_INFLECTORS_KEY = 'inflectors';
const DEFAULT_DI_KEY = 'di';

const SETTING_PREFIX = 'prefix';
const SETTING_SEPARATOR = 'separator';
Expand Down Expand Up @@ -49,7 +50,10 @@ public static function fromConfig(array $config, array $settings = [])
$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([])]
[
self::DEFAULT_INFLECTORS_KEY => new InflectorConfigServiceProvider([]),
self::DEFAULT_DI_KEY => new DIConfigServiceProvider([]),
]
);
}

Expand All @@ -64,11 +68,11 @@ public static function fromConfig(array $config, array $settings = [])
public static function fromFiles(array $patterns, array $settings = [])
{
$locator = new FileLocator();
$files = $locator->locate($patterns);
$files = $locator->locate($patterns);

$factory = new ReaderFactory([
'.json' => 'TomPHP\ConfigServiceProvider\JSONFileReader',
'.php' => 'TomPHP\ConfigServiceProvider\PHPFileReader',
'.php' => 'TomPHP\ConfigServiceProvider\PHPFileReader',
]);

$configs = array_map(
Expand Down Expand Up @@ -167,7 +171,7 @@ private function expandSubGroup($key, $value)

foreach ($value as $subkey => $subvalue) {
$expanded += $this->expandSubGroup(
$key. $this->separator . $subkey,
$key . $this->separator . $subkey,
$subvalue
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/ConfigurableServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface ConfigurableServiceProvider extends ServiceProviderInterface
{
/**
* @param array $config
*
* @return void
*/
public function configure(array $config);
}
95 changes: 95 additions & 0 deletions src/DIConfigServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace TomPHP\ConfigServiceProvider;

use League\Container\Definition\ClassDefinition;
use League\Container\ServiceProvider\AbstractServiceProvider;
use League\Container\ServiceProvider\BootableServiceProviderInterface;
use TomPHP\ConfigServiceProvider\Exception\NotClassDefinitionException;

final class DIConfigServiceProvider extends AbstractServiceProvider implements
BootableServiceProviderInterface,
ConfigurableServiceProvider
{
/**
* @var array
*/
private $config;

/**
* @api
*
* @param array $config
*/
public function __construct(array $config)
{
$this->configure($config);
}

/**
* @param array $config
*/
public function configure(array $config)
{
$this->provides = array_keys($config);
$this->config = $config;
}

public function register()
{
foreach ($this->config as $name => $config) {
$this->registerService($name, $config);
}
}

public function boot()
{
}

/**
* @param string $name
* @param array $config
*/
private function registerService($name, array $config)
{
$singleton = array_key_exists('singleton', $config) && $config['singleton'];

$service = $this->getContainer()->add($name, $config['class'], $singleton);

if (!$service instanceof ClassDefinition) {
throw new NotClassDefinitionException(sprintf(
'DI config for %s does not create a class definition',
$name
));
}

$this->addConstuctorArguments($service, $config);
$this->addMethodCalls($service, $config);
}

/**
* @param array $config
*/
private function addConstuctorArguments(ClassDefinition $service, array $config)
{
if (!isset($config['arguments']) || !is_array($config['arguments'])) {
return;
}

$service->withArguments($config['arguments']);
}

/**
* @param array $config
*/
private function addMethodCalls(ClassDefinition $service, array $config)
{
if (!isset($config['methods']) || !is_array($config['methods'])) {
return;
}

foreach ($config['methods'] as $method => $args) {
$service->withMethodCall($method, $args);
}
}
}
7 changes: 7 additions & 0 deletions src/Exception/NotClassDefinitionException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace TomPHP\ConfigServiceProvider\Exception;

final class NotClassDefinitionException extends RuntimeException
{
}
4 changes: 2 additions & 2 deletions src/JSONFileReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function read($filename)

if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidConfigException(
"Invalid JSON in $filename: " . $this->getJsonError()
sprintf('Invalid JSON in %s: %s', $filename, $this->getJsonError())
);
}

Expand All @@ -29,7 +29,7 @@ public function read($filename)
private function assertFileExists()
{
if (!file_exists($this->filename)) {
throw new FileNotFoundException("{$this->filename} does not exist");
throw new FileNotFoundException(sprintf('%s does not exist', $this->filename));
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/PHPFileReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,14 @@ public function read($filename)
private function assertFileExists()
{
if (!file_exists($this->filename)) {
throw new FileNotFoundException("{$this->filename} does not exist");
throw new FileNotFoundException($this->filename . ' does not exist');
}
}

private function assertConfigIsValid($config)
{
if (!is_array($config)) {
throw new InvalidConfigException(
"{$this->filename} does not return a PHP array"
);
throw new InvalidConfigException($this->filename . ' does not return a PHP array');
}
}
}
17 changes: 9 additions & 8 deletions src/ReaderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,21 @@ public function create($filename)
*/
private function getReaderClass($filename)
{
$found = false;
$readerClass = null;

foreach ($this->config as $extension => $readerClass) {
foreach ($this->config as $extension => $className) {
if ($this->endsWith($filename, $extension)) {
$found = true;
$readerClass = $className;
break;
}
}

if (!$found) {
throw new UnknownFileTypeException(
"Not reader class found for $filename; configured exceptions are "
. implode(', ', array_keys($this->config))
);
if ($readerClass === null) {
throw new UnknownFileTypeException(sprintf(
'No reader class found for %s; configured exceptions are %s',
$filename,
implode(', ', array_keys($this->config))
));
}

return $readerClass;
Expand Down
23 changes: 23 additions & 0 deletions tests/ConfigServiceProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,29 @@ public function testItCanOverrideFromConfigDefaults()
);
}

/**
* @group from_config_factory
*/
public function testItCanConfigureDI()
{
$config = [
'test_key' => 'test value',

'di' => [
'example_class' => [
'class' => 'tests\mocks\ExampleClass',
]
]
];

$this->container->addServiceProvider(ConfigServiceProvider::fromConfig($config));

$this->assertInstanceOf(
'tests\mocks\ExampleClass',
$this->container->get('example_class')
);
}

/**
* @group from_files_factory
*/
Expand Down
Loading

0 comments on commit ec30b21

Please sign in to comment.