Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,15 @@ class AppKernel extends Kernel

## Configuration

Configuration is handled by the SDK rather than by the bundle, and no validation
is performed at compile time. Full documentation of the configuration options
available can be read in the [SDK Guide](http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/configuration.html).
By default, configuration is handled by the SDK rather than by the bundle, and
no validation is performed at compile time. Full documentation of the
configuration options available can be read in the [SDK Guide](http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/configuration.html).

If AWS_MERGE_CONFIG environment variable is set to `true`, configuration
validation and merging are enabled. The bundle validates and merges known
configuration options, including for each service. Additional configuration
options can be included in a single configuration file, but merging will fail
if non-standard options are specified in more than once.

To use a service for any configuration value, use `@` followed by the service
name, such as `@a_service`. This syntax will be converted to a service during
Expand Down
97 changes: 95 additions & 2 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,105 @@ class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
// Maintain backwars compatibility, only merge when AWS_MERGE_CONFIG is set
$mergeConfig = getenv('AWS_MERGE_CONFIG') ?: false;
$treeType = 'variable';

if ($mergeConfig) {
$treeType = 'array';
}

// Most recent versions of TreeBuilder have a constructor
if (\method_exists(TreeBuilder::class, '__construct')) {
$treeBuilder = new TreeBuilder('aws', 'variable');
$treeBuilder = new TreeBuilder('aws', $treeType);
} else { // which is not the case for older versions
$treeBuilder = new TreeBuilder;
$treeBuilder->root('aws', 'variable');
$treeBuilder->root('aws', $treeType);
}

// If not AWS_MERGE_CONFIG, return empty, variable TreeBuilder
if (!$mergeConfig) {
return $treeBuilder;
}

$rootNode = $treeBuilder->root('aws');

// Define TreeBuilder to allow config validation and merging
$rootNode
->ignoreExtraKeys(false)
->children()
->variableNode('credentials')->end()
->variableNode('debug')->end()
->variableNode('stats')->end()
->scalarNode('endpoint')->end()
->variableNode('endpoint_discovery')->end()
->arrayNode('http')
->children()
->floatNode('connect_timeout')->end()
->booleanNode('debug')->end()
->booleanNode('decode_content')->end()
->integerNode('delay')->end()
->variableNode('expect')->end()
->variableNode('proxy')->end()
->scalarNode('sink')->end()
->booleanNode('synchronous')->end()
->booleanNode('stream')->end()
->floatNode('timeout')->end()
->scalarNode('verify')->end()
->end()
->end()
->scalarNode('profile')->end()
->scalarNode('region')->end()
->integerNode('retries')->end()
->scalarNode('scheme')->end()
->scalarNode('service')->end()
->scalarNode('signature_version')->end()
->variableNode('ua_append')->end()
->variableNode('validate')->end()
->scalarNode('version')->end()
->end()
;

//Setup config trees for each of the services
foreach (array_column(Aws\manifest(), 'namespace') as $awsService) {
$rootNode
->children()
->arrayNode($awsService)
->ignoreExtraKeys(false)
->children()
->variableNode('credentials')->end()
->variableNode('debug')->end()
->variableNode('stats')->end()
->scalarNode('endpoint')->end()
->variableNode('endpoint_discovery')->end()
->arrayNode('http')
->children()
->floatNode('connect_timeout')->end()
->booleanNode('debug')->end()
->booleanNode('decode_content')->end()
->integerNode('delay')->end()
->variableNode('expect')->end()
->variableNode('proxy')->end()
->scalarNode('sink')->end()
->booleanNode('synchronous')->end()
->booleanNode('stream')->end()
->floatNode('timeout')->end()
->scalarNode('verify')->end()
->end()
->end()
->scalarNode('profile')->end()
->scalarNode('region')->end()
->integerNode('retries')->end()
->scalarNode('scheme')->end()
->scalarNode('service')->end()
->scalarNode('signature_version')->end()
->variableNode('ua_append')->end()
->variableNode('validate')->end()
->scalarNode('version')->end()
->end()
->end()
->end()
;
}

return $treeBuilder;
Expand Down
116 changes: 116 additions & 0 deletions tests/DependencyInjection/AwsExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,120 @@ public function extension_should_expand_service_references()

$extension->load([$config], $container);
}

/**
* @test
*/
public function extension_should_validate_and_merge_configs()
{
putenv('AWS_MERGE_CONFIG=true');
$extension = new AwsExtension;
$config = [
'credentials' => false,
'debug' => [
'http' => true
],
'stats' => [
'http' => true
],
'retries' => 5,
'endpoint' => 'http://localhost:8000',
'endpoint_discovery' => [
'enabled' => true,
'cache_limit' => 1000
],
'http' => [
'connect_timeout' => 5.5,
'debug' => true,
'decode_content' => true,
'delay' => 1,
'expect' => true,
'proxy' => 'http://localhost:9000',
'sink' => '/path/to/sink',
'synchronous' => true,
'stream' => true,
'timeout' => 3.14,
'verify' => '/path/to/ca_cert_bundle'
],
'profile' => 'prod',
'region' => 'us-west-2',
'retries' => 5,
'scheme' => 'http',
'signature_version' => 'v4',
'ua_append' => [
'prod',
'foo'
],
'validate' => [
'required' => true
],
'version' => 'latest',
'S3' => [
'version' => '2006-03-01',
]
];
$configDev = [
'credentials' => '@aws_sdk',
'debug' => true,
'stats' => true,
'ua_append' => 'dev',
'validate' => true,
];
$container = $this->getMockBuilder(ContainerBuilder::class)
->setMethods(['getDefinition', 'replaceArgument'])
->getMock();
$container->expects($this->once())
->method('getDefinition')
->with('aws_sdk')
->willReturnSelf();
$container->expects($this->once())
->method('replaceArgument')
->with(0, $this->callback(function ($arg) {
return is_array($arg)
&& isset($arg['credentials'])
&& $arg['credentials'] instanceof Reference
&& (string) $arg['credentials'] === 'aws_sdk'
&& isset($arg['debug'])
&& (bool) $arg['debug'] === true
&& isset($arg['stats'])
&& (bool) $arg['stats'] === true
&& isset($arg['retries'])
&& (integer) $arg['retries'] === 5
&& isset($arg['endpoint'])
&& (string) $arg['endpoint'] === 'http://localhost:8000'
&& isset($arg['validate'])
&& (bool) $arg['validate'] === true
&& isset($arg['endpoint_discovery']['enabled'])
&& isset($arg['endpoint_discovery']['cache_limit'])
&& (bool) $arg['endpoint_discovery']['enabled'] === true
&& (integer) $arg['endpoint_discovery']['cache_limit'] === 1000
&& isset($arg['S3']['version'])
&& (string) $arg['S3']['version'] === '2006-03-01'
;
}));

$extension->load([$config, $configDev], $container);
}

/**
* @test
*
* @expectedException RuntimeException
*/
public function extension_should_error_merging_unknown_config_options()
{
putenv('AWS_MERGE_CONFIG=true');
$extension = new AwsExtension;
$config = [
'foo' => 'bar'
];
$configDev = [
'foo' => 'baz'
];
$container = $this->getMockBuilder(ContainerBuilder::class)
->setMethods(['getDefinition', 'replaceArgument'])
->getMock();

$extension->load([$config, $configDev], $container);
}
}