Skip to content

Commit 19a477e

Browse files
authored
Move Symfony to AsyncAws\Symfony\Bundle (#164)
* Move to AsyncAws\Symfony\Bundle * Fixed tests * cs * Fixed CS * Make sure we run Symfony tests
0 parents  commit 19a477e

21 files changed

+696
-0
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/Tests export-ignore
2+
/phpunit.xml.dist export-ignore
3+
/.gitignore export-ignore

.github/FUNDING.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# These are supported funding model platforms
2+
3+
github: [nyholm, jderusse]

.github/workflows/.editorconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[*.yml]
2+
indent_size = 2

.github/workflows/checks.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: BC Check
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
8+
jobs:
9+
roave-bc-check:
10+
name: Roave BC Check
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v2
16+
17+
- name: Roave BC Check
18+
uses: docker://nyholm/roave-bc-check-ga

.github/workflows/ci.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
8+
jobs:
9+
10+
build:
11+
name: Build
12+
runs-on: ubuntu-latest
13+
strategy:
14+
max-parallel: 10
15+
matrix:
16+
php: ['7.2', '7.3', '7.4']
17+
18+
steps:
19+
- name: Set up PHP
20+
uses: shivammathur/[email protected]
21+
with:
22+
php-version: ${{ matrix.php }}
23+
coverage: xdebug
24+
ini-values: xdebug.overload_var_dump=1
25+
tools: prestissimo
26+
27+
- name: Checkout code
28+
uses: actions/checkout@v2
29+
30+
- name: Download dependencies
31+
run: |
32+
composer config minimum-stability dev
33+
composer req symfony/phpunit-bridge --no-update
34+
composer update --no-interaction --prefer-dist --optimize-autoloader --prefer-stable
35+
36+
- name: Initialize tests
37+
run: make initialize
38+
39+
- name: Run tests
40+
run: ./vendor/bin/simple-phpunit

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/vendor/
2+
.php_cs.cache
3+
.phpunit.result.cache
4+
composer.lock

AsyncAwsBundle.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AsyncAws\Symfony\Bundle;
6+
7+
use Symfony\Component\HttpKernel\Bundle\Bundle;
8+
9+
class AsyncAwsBundle extends Bundle
10+
{
11+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AsyncAws\Symfony\Bundle\DependencyInjection;
6+
7+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
8+
use Symfony\Component\DependencyInjection\ContainerBuilder;
9+
use Symfony\Component\DependencyInjection\ContainerInterface;
10+
use Symfony\Component\DependencyInjection\Definition;
11+
use Symfony\Component\DependencyInjection\Reference;
12+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
13+
14+
class AsyncAwsExtension extends Extension
15+
{
16+
public function load(array $configs, ContainerBuilder $container)
17+
{
18+
$configuration = new Configuration();
19+
$config = $this->processConfiguration($configuration, $configs);
20+
21+
$usedServices = $this->registerConfiguredServices($container, $config);
22+
$usedServices = $this->registerInstalledServices($container, $config, $usedServices);
23+
$this->autowireServices($container, $usedServices);
24+
}
25+
26+
private function registerConfiguredServices(ContainerBuilder $container, array $config): array
27+
{
28+
$availableServices = AwsPackagesProvider::getAllServices();
29+
$usedServices = [];
30+
$defaultConfig = $config;
31+
unset($defaultConfig['services']);
32+
33+
foreach ($config['services'] as $name => $data) {
34+
$client = $availableServices[$data['type']]['client'];
35+
if (!class_exists($client)) {
36+
throw new InvalidConfigurationException(sprintf('You have configured "async_aws.%s" but the "%s" package is not installed. Try running "composer require %s"', $name, $name, $availableServices[$name]['package']));
37+
}
38+
39+
$config = array_merge($defaultConfig, $data);
40+
if ($config['register_service']) {
41+
$usedServices[$name] = $client;
42+
$this->addServiceDefinition($container, $name, $config, $client);
43+
} else {
44+
$usedServices[$name] = null;
45+
}
46+
}
47+
48+
return $usedServices;
49+
}
50+
51+
private function registerInstalledServices(ContainerBuilder $container, array $config, array $usedServices): array
52+
{
53+
if (!$config['register_service']) {
54+
return $usedServices;
55+
}
56+
57+
unset($config['services']);
58+
$availableServices = AwsPackagesProvider::getAllServices();
59+
foreach ($availableServices as $name => $data) {
60+
if (\array_key_exists($name, $usedServices)) {
61+
continue;
62+
}
63+
64+
$client = $data['client'];
65+
if (!class_exists($client)) {
66+
continue;
67+
}
68+
69+
$usedServices[$name] = $client;
70+
$this->addServiceDefinition($container, $name, $config, $client);
71+
}
72+
73+
return $usedServices;
74+
}
75+
76+
private function addServiceDefinition(ContainerBuilder $container, string $name, array $config, string $clientClass): void
77+
{
78+
if (\array_key_exists('logger', $config)) {
79+
$logger = $config['logger'] ? new Reference($config['logger']) : null;
80+
} else {
81+
// Use default Symfony logger unless explicitly set to null.
82+
$logger = new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE);
83+
}
84+
85+
$definition = new Definition($clientClass);
86+
$definition->addArgument($config['config']);
87+
$definition->addArgument(isset($config['credential_provider']) ? new Reference($config['credential_provider']) : null);
88+
$definition->addArgument(isset($config['http_client']) ? new Reference($config['http_client']) : null);
89+
$definition->addArgument($logger);
90+
$container->setDefinition(sprintf('async_aws.service.%s', $name), $definition);
91+
}
92+
93+
private function autowireServices(ContainerBuilder $container, array $usedServices): void
94+
{
95+
$awsServices = AwsPackagesProvider::getAllServices();
96+
foreach ($usedServices as $name => $client) {
97+
if (null === $client) {
98+
// This client is disabled.
99+
continue;
100+
}
101+
102+
$serviceId = sprintf('async_aws.service.%s', $name);
103+
if (isset($awsServices[$name])) {
104+
$container->setAlias($client, $serviceId);
105+
106+
continue;
107+
}
108+
109+
// Assert: Custom name
110+
$container->registerAliasForArgument($serviceId, $client, $name);
111+
}
112+
}
113+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AsyncAws\Symfony\Bundle\DependencyInjection;
6+
7+
class AwsPackagesProvider
8+
{
9+
public static function getAllServices(): array
10+
{
11+
return [
12+
's3' => [
13+
'client' => \AsyncAws\S3\S3Client::class,
14+
'package' => 'async-aws/s3',
15+
],
16+
'ses' => [
17+
'client' => \AsyncAws\Ses\SesClient::class,
18+
'package' => 'async-aws/ses',
19+
],
20+
'sqs' => [
21+
'client' => \AsyncAws\Sqs\SqsClient::class,
22+
'package' => 'async-aws/sqs',
23+
],
24+
'sts' => [
25+
'client' => \AsyncAws\Core\Sts\StsClient::class,
26+
'package' => 'async-aws/core',
27+
],
28+
'sns' => [
29+
'client' => \AsyncAws\Sns\SnsClient::class,
30+
'package' => 'async-aws/sns',
31+
],
32+
];
33+
}
34+
35+
public static function getServiceNames(): array
36+
{
37+
$services = self::getAllServices();
38+
39+
return array_keys($services);
40+
}
41+
}

DependencyInjection/Configuration.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AsyncAws\Symfony\Bundle\DependencyInjection;
6+
7+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
8+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
9+
use Symfony\Component\Config\Definition\ConfigurationInterface;
10+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
11+
12+
class Configuration implements ConfigurationInterface
13+
{
14+
public function getConfigTreeBuilder()
15+
{
16+
$treeBuilder = new TreeBuilder('async_aws');
17+
/** @var ArrayNodeDefinition $rootNode */
18+
$rootNode = $treeBuilder->getRootNode();
19+
$rootNode
20+
->fixXmlConfig('service')
21+
->children()
22+
->booleanNode('register_service')->info('If set to false, no service will be created.')->defaultTrue()->end()
23+
->scalarNode('credential_provider')->info('A service name for AsyncAws\Core\Credentials\CredentialProvider.')->defaultNull()->end()
24+
->scalarNode('http_client')->info('A service name for Symfony\Contracts\HttpClient\HttpClientInterface.')->defaultNull()->end()
25+
->scalarNode('logger')->info('A service name for Psr\Log\LoggerInterface.')->end()
26+
->arrayNode('config')->normalizeKeys(false)->prototype('variable')->end()->end()
27+
28+
->arrayNode('services')
29+
->beforeNormalization()->always()->then(\Closure::fromCallable([$this, 'validateType']))->end()
30+
->useAttributeAsKey('name')
31+
->arrayPrototype()
32+
->children()
33+
->booleanNode('register_service')->info('If set to false, no service will be created.')->defaultTrue()->end()
34+
->arrayNode('config')->normalizeKeys(false)->prototype('variable')->end()->end()
35+
->enumNode('type')->info('A valid AWS type. The service name will be used as default. ')->values(AwsPackagesProvider::getServiceNames())->end()
36+
->scalarNode('credential_provider')->info('A service name for AsyncAws\Core\Credentials\CredentialProvider.')->end()
37+
->scalarNode('http_client')->info('A service name for Symfony\Contracts\HttpClient\HttpClientInterface.')->end()
38+
->scalarNode('logger')->info('A service name for Psr\Log\LoggerInterface.')->end()
39+
->end()
40+
->end()
41+
->end()
42+
->end();
43+
44+
return $treeBuilder;
45+
}
46+
47+
private static function validateType(array $services)
48+
{
49+
$awsServices = AwsPackagesProvider::getServiceNames();
50+
foreach ($services as $name => $config) {
51+
if (\in_array($name, $awsServices)) {
52+
if (isset($config['type']) && $name !== $config['type']) {
53+
throw new InvalidConfigurationException(sprintf('You cannot define a service named "%s" with type "%s". That is super confusing.', $name, $config['type']));
54+
}
55+
$services[$name]['type'] = $name;
56+
} elseif (!isset($config['type'])) {
57+
if (!\in_array($name, $awsServices)) {
58+
throw new InvalidConfigurationException(sprintf('The "async_aws.service.%s" does not have a type. We were unable to guess what AWS service you want. Please add "aws.service.%s.type".', $name, $name));
59+
}
60+
61+
$services[$name]['type'] = $name;
62+
}
63+
}
64+
65+
return $services;
66+
}
67+
}

0 commit comments

Comments
 (0)